Class: Namespace
- Inherits:
-
ApplicationRecord
show all
- Includes:
- AfterCommitQueue, BlocksUnsafeSerialization, CacheMarkdownField, EachBatch, FeatureGate, FromUnion, Gitlab::SQL::Pattern, Gitlab::Utils::StrongMemoize, Gitlab::VisibilityLevel, IgnorableColumns, Namespaces::Traversal::Linear, Namespaces::Traversal::Recursive, Routable, Sortable, Storage::LegacyNamespace
- Defined in:
- app/models/namespace/traversal_hierarchy.rb,
app/models/namespace.rb
Overview
A Namespace::TraversalHierarchy is the collection of namespaces that descend from a root Namespace as defined by the Namespace#traversal_ids attributes.
This class provides operations to be performed on the hierarchy itself, rather than individual namespaces.
This includes methods for synchronizing traversal_ids attributes to a correct state. We use recursive methods to determine the correct state so we don't have to depend on the integrity of the traversal_ids attribute values themselves.
Defined Under Namespace
Classes: AdminNote, AggregationSchedule, PackageSetting, PackageSettingPolicy, PackageSettingsType, RootStorageStatistics, RootStorageStatisticsPolicy, SharedRunnersSettingEnum, TraversalHierarchy
Constant Summary
collapse
- NUMBER_OF_ANCESTORS_ALLOWED =
Prevent users from creating unreasonably deep level of nesting. The number 20 was taken based on maximum nesting level of Android repo (15) + some extra backup.
20
- SR_DISABLED_AND_UNOVERRIDABLE =
'disabled_and_unoverridable'
- SR_DISABLED_WITH_OVERRIDE =
'disabled_with_override'
- SR_ENABLED =
'enabled'
- SHARED_RUNNERS_SETTINGS =
[SR_DISABLED_AND_UNOVERRIDABLE, SR_DISABLED_WITH_OVERRIDE, SR_ENABLED].freeze
- URL_MAX_LENGTH =
255
- PATH_TRAILING_VIOLATIONS =
%w[.git .atom .].freeze
BlocksUnsafeSerialization::UnsafeSerializationError
Namespaces::Traversal::Linear::UnboundedSearch
Gitlab::SQL::Pattern::MIN_CHARS_FOR_PARTIAL_MATCHING, Gitlab::SQL::Pattern::REGEX_QUOTED_WORD
Gitlab::VisibilityLevel::INTERNAL, Gitlab::VisibilityLevel::PRIVATE, Gitlab::VisibilityLevel::PUBLIC
CacheMarkdownField::INVALIDATED_BY
ApplicationRecord::MAX_PLUCK
Instance Attribute Summary collapse
Class Method Summary
collapse
Instance Method Summary
collapse
#serializable_hash
#extended, extensions, #included, #method_added, #override, #prepended, #queue_verification, verify!
#ancestor_ids, #ancestors, #ancestors_upto, #descendants, #root_ancestor, #self_and_ancestor_ids, #self_and_ancestors, #self_and_descendant_ids, #self_and_descendants, #self_and_hierarchy, #sync_traversal_ids?, #use_traversal_ids?, #use_traversal_ids_for_ancestors?, #use_traversal_ids_for_ancestors_upto?, #use_traversal_ids_for_root_ancestor?, #use_traversal_ids_for_self_and_hierarchy?
#ancestor_ids, #ancestors, #ancestors_upto, #descendants, #object_hierarchy, #root_ancestor, #self_and_ancestor_ids, #self_and_ancestors, #self_and_descendant_ids, #self_and_descendants, #self_and_hierarchy
#clear_memoization, #strong_memoize, #strong_memoized?
#flipper_id
#move_dir, #prepare_for_destroy
#gitlab_shell
#run_after_commit, #run_after_commit_or_now
Methods included from Routable
#build_full_path, find_by_full_path, #full_name, #full_path, #full_path_components, #owned_by?, #parent_loaded?, #route_loaded?
allowed_for?, allowed_level?, allowed_levels, closest_allowed_level, #internal?, level_name, level_value, levels_for_user, non_restricted_level?, options, #private?, #public?, public_visibility_restricted?, restricted_level?, string_level, string_options, string_values, valid_level?, #visibility, #visibility=, #visibility_attribute_present?, #visibility_attribute_value, #visibility_level_attributes, #visibility_level_previous_changes, #visibility_level_value
#attribute_invalidated?, #banzai_render_context, #cached_html_for, #cached_html_up_to_date?, #can_cache_field?, #invalidated_markdown_cache?, #latest_cached_markdown_version, #local_version, #mentionable_attributes_changed?, #parent_user, #refresh_markdown_cache, #refresh_markdown_cache!, #rendered_field_content, #skip_project_check?, #store_mentions!, #updated_cached_html_for
cached_column_list, #create_or_load_association, declarative_enum, default_select_columns, id_in, id_not_in, iid_in, pluck_primary_key, primary_key_in, #readable_by?, safe_ensure_unique, safe_find_or_create_by, safe_find_or_create_by!, #to_ability_name, underscore, where_exists, where_not_exists, with_fast_read_statement_timeout, without_order
#serializable_hash
Instance Attribute Details
#emails_disabled_memoized=(value) ⇒ Object
Make sure that the name is same as strong_memoize name in root_ancestor method
167
168
169
|
# File 'app/models/namespace.rb', line 167
def emails_disabled_memoized=(value)
@emails_disabled_memoized = value
end
|
#root_ancestor=(value) ⇒ Object
Make sure that the name is same as strong_memoize name in root_ancestor method
167
168
169
|
# File 'app/models/namespace.rb', line 167
def root_ancestor=(value)
@root_ancestor = value
end
|
Class Method Details
.by_path(path) ⇒ Object
183
184
185
|
# File 'app/models/namespace.rb', line 183
def by_path(path)
find_by('lower(path) = :value', value: path.downcase)
end
|
.clean_name(value) ⇒ Object
.clean_path(path) ⇒ Object
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
|
# File 'app/models/namespace.rb', line 207
def clean_path(path)
path = path.dup
path.gsub!(/@.*\z/, "")
path.gsub!(/[^a-zA-Z0-9_\-\.]/, "")
loop do
orig = path
PATH_TRAILING_VIOLATIONS.each { |ext| path = path.chomp(ext) }
break if orig == path
end
path.gsub!(/\A\-+/, "")
path = "blank" if path.blank?
uniquify = Uniquify.new
uniquify.string(path) { |s| Namespace.find_by_path_or_name(s) }
end
|
.find_by_pages_host(host) ⇒ Object
235
236
237
238
239
240
241
242
|
# File 'app/models/namespace.rb', line 235
def find_by_pages_host(host)
gitlab_host = "." + Settings.pages.host.downcase
host = host.downcase
return unless host.ends_with?(gitlab_host)
name = host.delete_suffix(gitlab_host)
Namespace.where(parent_id: nil).by_path(name)
end
|
.find_by_path_or_name(path) ⇒ Object
Case insensitive search for namespace by path or name
188
189
190
|
# File 'app/models/namespace.rb', line 188
def find_by_path_or_name(path)
find_by("lower(path) = :path OR lower(name) = :path", path: path.downcase)
end
|
.search(query, include_parents: false) ⇒ Object
Searches for namespaces matching the given query.
This method uses ILIKE on PostgreSQL.
query - The search query as a String.
Returns an ActiveRecord::Relation.
199
200
201
202
203
204
205
|
# File 'app/models/namespace.rb', line 199
def search(query, include_parents: false)
if include_parents
without_project_namespaces.where(id: Route.for_routable_type(Namespace.name).fuzzy_search(query, [Route.arel_table[:path], Route.arel_table[:name]]).select(:source_id))
else
without_project_namespaces.fuzzy_search(query, [:path, :name])
end
end
|
.sti_class_for(type_name) ⇒ Object
.top_most ⇒ Object
244
245
246
|
# File 'app/models/namespace.rb', line 244
def top_most
where(parent_id: nil)
end
|
Instance Method Details
#actual_limits ⇒ Object
451
452
453
454
455
456
|
# File 'app/models/namespace.rb', line 451
def actual_limits
actual_plan.actual_limits
end
|
#actual_plan ⇒ Object
443
444
445
|
# File 'app/models/namespace.rb', line 443
def actual_plan
Plan.default
end
|
#actual_plan_name ⇒ Object
458
459
460
|
# File 'app/models/namespace.rb', line 458
def actual_plan_name
actual_plan.name
end
|
#aggregation_scheduled? ⇒ Boolean
422
423
424
|
# File 'app/models/namespace.rb', line 422
def aggregation_scheduled?
aggregation_schedule.present?
end
|
#all_project_ids_except(ids) ⇒ Object
375
376
377
|
# File 'app/models/namespace.rb', line 375
def all_project_ids_except(ids)
all_projects.where.not(id: ids).pluck(:id)
end
|
#all_projects ⇒ Object
Includes projects from this namespace and projects from all subgroups that belongs to this namespace
353
354
355
356
357
358
359
360
|
# File 'app/models/namespace.rb', line 353
def all_projects
if Feature.enabled?(:recursive_approach_for_all_projects)
namespace = user_namespace? ? self : self_and_descendant_ids
Project.where(namespace: namespace)
else
Project.inside_path(full_path)
end
end
|
269
270
271
|
# File 'app/models/namespace.rb', line 269
def any_project_has_container_registry_tags?
all_projects.includes(:container_repositories).any?(&:has_container_registry_tags?)
end
|
#any_project_with_pages_deployed? ⇒ Boolean
433
434
435
|
# File 'app/models/namespace.rb', line 433
def any_project_with_pages_deployed?
all_projects.with_pages_deployed.any?
end
|
#any_project_with_shared_runners_enabled? ⇒ Boolean
343
344
345
|
# File 'app/models/namespace.rb', line 343
def any_project_with_shared_runners_enabled?
projects.with_shared_runners.any?
end
|
#auto_devops_enabled? ⇒ Boolean
402
403
404
|
# File 'app/models/namespace.rb', line 402
def auto_devops_enabled?
first_auto_devops_config[:status]
end
|
#certificate_based_clusters_enabled? ⇒ Boolean
528
529
530
531
532
|
# File 'app/models/namespace.rb', line 528
def certificate_based_clusters_enabled?
::Gitlab::SafeRequestStore.fetch("certificate_based_clusters:ns:#{self.id}") do
Feature.enabled?(:certificate_based_clusters, self, type: :ops)
end
end
|
#changing_allow_descendants_override_disabled_shared_runners_is_allowed ⇒ Object
470
471
472
473
474
475
476
477
478
479
480
|
# File 'app/models/namespace.rb', line 470
def changing_allow_descendants_override_disabled_shared_runners_is_allowed
return unless new_record? || changes.has_key?(:allow_descendants_override_disabled_shared_runners)
if shared_runners_enabled && !new_record?
errors.add(:allow_descendants_override_disabled_shared_runners, _('cannot be changed if shared runners are enabled'))
end
if allow_descendants_override_disabled_shared_runners && has_parent? && parent.shared_runners_setting == SR_DISABLED_AND_UNOVERRIDABLE
errors.add(:allow_descendants_override_disabled_shared_runners, _('cannot be enabled because parent group does not allow it'))
end
end
|
#changing_shared_runners_enabled_is_allowed ⇒ Object
462
463
464
465
466
467
468
|
# File 'app/models/namespace.rb', line 462
def changing_shared_runners_enabled_is_allowed
return unless new_record? || changes.has_key?(:shared_runners_enabled)
if shared_runners_enabled && has_parent? && parent.shared_runners_setting == SR_DISABLED_AND_UNOVERRIDABLE
errors.add(:shared_runners_enabled, _('cannot be enabled because parent group has shared Runners disabled'))
end
end
|
#closest_setting(name) ⇒ Object
437
438
439
440
441
|
# File 'app/models/namespace.rb', line 437
def closest_setting(name)
self_and_ancestors(hierarchy_order: :asc)
.find { |n| !n.read_attribute(name).nil? }
.try(name)
end
|
#default_branch_protection ⇒ Object
253
254
255
|
# File 'app/models/namespace.rb', line 253
def default_branch_protection
super || Gitlab::CurrentSettings.default_branch_protection
end
|
#emails_disabled? ⇒ Boolean
any ancestor can disable emails for all descendants
328
329
330
331
332
333
334
335
336
|
# File 'app/models/namespace.rb', line 328
def emails_disabled?
strong_memoize(:emails_disabled_memoized) do
if parent_id
self_and_ancestors.where(emails_disabled: true).exists?
else
!!emails_disabled
end
end
end
|
#feature_available?(feature, _user = nil) ⇒ Boolean
Deprecated, use #licensed_feature_available? instead. Remove once Namespace#feature_available? isn't used anymore.
380
381
382
|
# File 'app/models/namespace.rb', line 380
def feature_available?(feature, _user = nil)
licensed_feature_available?(feature)
end
|
#find_fork_of(project) ⇒ Object
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
|
# File 'app/models/namespace.rb', line 311
def find_fork_of(project)
return unless project.fork_network
if Gitlab::SafeRequestStore.active?
forks_in_namespace = Gitlab::SafeRequestStore.fetch("namespaces:#{id}:forked_projects") do
Hash.new do |found_forks, project|
found_forks[project] = project.fork_network.find_forks_in(projects).first
end
end
forks_in_namespace[project]
else
project.fork_network.find_forks_in(projects).first
end
end
|
#first_auto_devops_config ⇒ Object
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
|
# File 'app/models/namespace.rb', line 406
def first_auto_devops_config
return { scope: :group, status: auto_devops_enabled } unless auto_devops_enabled.nil?
strong_memoize(:first_auto_devops_config) do
if has_parent? && cache_first_auto_devops_config?
Rails.cache.fetch(first_auto_devops_config_cache_key_for(id), expires_in: 1.day) do
parent.first_auto_devops_config
end
elsif has_parent?
parent.first_auto_devops_config
else
{ scope: :instance, status: Gitlab::CurrentSettings.auto_devops_enabled? }
end
end
end
|
#first_owner ⇒ Object
307
308
309
|
# File 'app/models/namespace.rb', line 307
def first_owner
owner
end
|
273
274
275
|
# File 'app/models/namespace.rb', line 273
def first_project_with_container_registry_tags
all_projects.find(&:has_container_registry_tags?)
end
|
#full_path_before_last_save ⇒ Object
389
390
391
392
393
394
395
396
|
# File 'app/models/namespace.rb', line 389
def full_path_before_last_save
if parent_id_before_last_save.nil?
path_before_last_save
else
previous_parent = Group.find_by(id: parent_id_before_last_save)
previous_parent.full_path + '/' + path_before_last_save
end
end
|
#group_namespace? ⇒ Boolean
290
291
292
|
# File 'app/models/namespace.rb', line 290
def group_namespace?
type == Group.sti_name
end
|
#has_parent? ⇒ Boolean
362
363
364
|
# File 'app/models/namespace.rb', line 362
def has_parent?
parent_id.present? || parent.present?
end
|
#human_name ⇒ Object
265
266
267
|
# File 'app/models/namespace.rb', line 265
def human_name
owner_name
end
|
#issue_repositioning_disabled? ⇒ Boolean
518
519
520
|
# File 'app/models/namespace.rb', line 518
def issue_repositioning_disabled?
Feature.enabled?(:block_issue_repositioning, self, type: :ops)
end
|
#kind ⇒ Object
283
284
285
286
287
288
|
# File 'app/models/namespace.rb', line 283
def kind
return 'group' if group_namespace?
return 'project' if project_namespace?
'user' end
|
#lfs_enabled? ⇒ Boolean
338
339
340
341
|
# File 'app/models/namespace.rb', line 338
def lfs_enabled?
Gitlab.config.lfs.enabled
end
|
#licensed_feature_available?(_feature) ⇒ Boolean
Overridden in EE::Namespace
385
386
387
|
# File 'app/models/namespace.rb', line 385
def licensed_feature_available?(_feature)
false
end
|
#multiple_issue_boards_available? ⇒ Boolean
371
372
373
|
# File 'app/models/namespace.rb', line 371
def multiple_issue_boards_available?
false
end
|
#owner_required? ⇒ Boolean
303
304
305
|
# File 'app/models/namespace.rb', line 303
def owner_required?
user_namespace?
end
|
#package_settings ⇒ Object
249
250
251
|
# File 'app/models/namespace.rb', line 249
def package_settings
package_setting_relation || build_package_setting_relation
end
|
#pages_virtual_domain ⇒ Object
426
427
428
429
430
431
|
# File 'app/models/namespace.rb', line 426
def pages_virtual_domain
Pages::VirtualDomain.new(
all_projects_with_pages.includes(:route, :project_feature, pages_metadatum: :pages_deployment),
trim_prefix: full_path
)
end
|
#paid? ⇒ Boolean
447
448
449
|
# File 'app/models/namespace.rb', line 447
def paid?
root? && actual_plan.paid?
end
|
#project_namespace? ⇒ Boolean
#recent? ⇒ Boolean
514
515
516
|
# File 'app/models/namespace.rb', line 514
def recent?
created_at >= 90.days.ago
end
|
#refresh_project_authorizations ⇒ Object
398
399
400
|
# File 'app/models/namespace.rb', line 398
def refresh_project_authorizations
owner.refresh_authorized_projects
end
|
#root? ⇒ Boolean
510
511
512
|
# File 'app/models/namespace.rb', line 510
def root?
!has_parent?
end
|
#send_update_instructions ⇒ Object
277
278
279
280
281
|
# File 'app/models/namespace.rb', line 277
def send_update_instructions
projects.each do |project|
project.send_move_instructions("#{full_path_before_last_save}/#{project.path}")
end
end
|
#shared_runners ⇒ Object
506
507
508
|
# File 'app/models/namespace.rb', line 506
def shared_runners
@shared_runners ||= shared_runners_enabled ? Ci::Runner.instance_type : Ci::Runner.none
end
|
#shared_runners_setting ⇒ Object
#shared_runners_setting_higher_than?(other_setting) ⇒ Boolean
#storage_enforcement_date ⇒ Object
522
523
524
525
526
|
# File 'app/models/namespace.rb', line 522
def storage_enforcement_date
nil
end
|
#subgroup? ⇒ Boolean
366
367
368
|
# File 'app/models/namespace.rb', line 366
def subgroup?
has_parent?
end
|
#to_param ⇒ Object
261
262
263
|
# File 'app/models/namespace.rb', line 261
def to_param
full_path
end
|
#user_ids_for_project_authorizations ⇒ Object
347
348
349
|
# File 'app/models/namespace.rb', line 347
def user_ids_for_project_authorizations
[owner_id]
end
|
#user_namespace? ⇒ Boolean
298
299
300
301
|
# File 'app/models/namespace.rb', line 298
def user_namespace?
type.nil? || type == Namespaces::UserNamespace.sti_name || !(group_namespace? || project_namespace?)
end
|
#visibility_level_field ⇒ Object
257
258
259
|
# File 'app/models/namespace.rb', line 257
def visibility_level_field
:visibility_level
end
|