Class: Group

Constant Summary collapse

ACCESS_REQUEST_APPROVERS_TO_BE_NOTIFIED_LIMIT =
10

Constants included from WithUploads

WithUploads::FILE_UPLOADERS

Constants included from Avatarable

Avatarable::ALLOWED_IMAGE_SCALER_WIDTHS, Avatarable::GROUP_AVATAR_SIZES, Avatarable::PROJECT_AVATAR_SIZES, Avatarable::USER_AVATAR_SIZES

Constants inherited from Namespace

Namespace::NUMBER_OF_ANCESTORS_ALLOWED, Namespace::SHARED_RUNNERS_SETTINGS

Constants included from Gitlab::SQL::Pattern

Gitlab::SQL::Pattern::MIN_CHARS_FOR_PARTIAL_MATCHING, Gitlab::SQL::Pattern::REGEX_QUOTED_WORD

Constants included from Gitlab::VisibilityLevel

Gitlab::VisibilityLevel::INTERNAL, Gitlab::VisibilityLevel::PRIVATE, Gitlab::VisibilityLevel::PUBLIC

Constants included from CacheMarkdownField

CacheMarkdownField::INVALIDATED_BY

Class Method Summary collapse

Instance Method Summary collapse

Methods included from GroupAPICompatibility

#project_creation_level_str, #project_creation_level_str=, #subgroup_creation_level_str, #subgroup_creation_level_str=

Methods included from Gitlab::Utils::StrongMemoize

#clear_memoization, #strong_memoize, #strong_memoized?

Methods included from WithUploads

#retrieve_upload

Methods included from FastDestroyAll::Helpers

#perform_fast_destroy

Methods included from AfterCommitQueue

#run_after_commit, #run_after_commit_or_now

Methods included from GroupDescendant

build_hierarchy, #hierarchy

Methods included from LoadedInGroupList

#children_count, #member_count, #project_count, #subgroup_count

Methods included from Referable

#referable_inspect, #reference_link_text, #to_reference_base

Methods included from Avatarable

#avatar_path, #avatar_type, #uncached_avatar_path, #upload_paths

Methods included from AccessRequestable

#request_access

Methods included from Gitlab::ConfigHelper

#gitlab_config, #gitlab_config_features

Methods inherited from Namespace

#actual_limits, #actual_plan, #actual_plan_name, #aggregation_scheduled?, #all_pipelines, #all_projects, #ancestors, #ancestors_upto, #any_project_has_container_registry_tags?, #any_project_with_pages_deployed?, #any_project_with_shared_runners_enabled?, #auto_devops_enabled?, by_path, #changing_allow_descendants_override_disabled_shared_runners_is_allowed, #changing_shared_runners_enabled_is_allowed, clean_name, clean_path, #closest_setting, #default_branch_protection, #descendants, #emails_disabled?, #feature_available?, find_by_pages_host, find_by_path_or_name, #find_fork_of, #first_auto_devops_config, #first_project_with_container_registry_tags, #full_path_before_last_save, #group?, #has_parent?, #kind, #multiple_issue_boards_available?, #pages_virtual_domain, #root_ancestor, search, #self_and_ancestors, #self_and_descendants, #self_and_hierarchy, #send_update_instructions, #shared_runners_setting, #shared_runners_setting_higher_than?, #subgroup?, #to_param, #user?, #visibility_level_field

Methods included from FeatureGate

#flipper_id

Methods included from Storage::LegacyNamespace

#move_dir, #prepare_for_destroy

Methods included from Gitlab::ShellAdapter

#gitlab_shell

Methods included from Routable

#build_full_path, #full_name, #full_path, #full_path_components

Methods included from Gitlab::VisibilityLevel

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_level_attributes, #visibility_level_decreased?, #visibility_level_previous_changes, #visibility_level_value

Methods included from CacheMarkdownField

#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, #parent_user, #refresh_markdown_cache, #refresh_markdown_cache!, #rendered_field_content, #skip_project_check?, #updated_cached_html_for

Methods inherited from ApplicationRecord

at_most, id_in, id_not_in, iid_in, pluck_primary_key, primary_key_in, safe_ensure_unique, safe_find_or_create_by, safe_find_or_create_by!, underscore, where_exists, with_fast_statement_timeout, without_order

Class Method Details

.public_or_visible_to_user(user) ⇒ Object

WARNING: This method should never be used on its own please do make sure the number of rows you are filtering is small enough for this query


139
140
141
142
143
144
145
146
147
# File 'app/models/group.rb', line 139

def public_or_visible_to_user(user)
  return public_to_user unless user

  public_for_user = public_to_user_arel(user)
  visible_for_user = visible_to_user_arel(user)
  public_or_visible = public_for_user.or(visible_for_user)

  where(public_or_visible)
end

.reference_patternObject


132
133
134
# File 'app/models/group.rb', line 132

def reference_pattern
  User.reference_pattern
end

.reference_prefixObject


128
129
130
# File 'app/models/group.rb', line 128

def reference_prefix
  User.reference_prefix
end

.select_for_project_authorizationObject


149
150
151
152
153
154
155
156
157
# File 'app/models/group.rb', line 149

def select_for_project_authorization
  if current_scope.joins_values.include?(:shared_projects)
    joins('INNER JOIN namespaces project_namespace ON project_namespace.id = projects.namespace_id')
      .where('project_namespace.share_with_group_lock = ?', false)
      .select("projects.id AS project_id, LEAST(project_group_links.group_access, members.access_level) AS access_level")
  else
    super
  end
end

.sort_by_attribute(method) ⇒ Object


118
119
120
121
122
123
124
125
126
# File 'app/models/group.rb', line 118

def sort_by_attribute(method)
  if method == 'storage_size_desc'
    # storage_size is a virtual column so we need to
    # pass a string to avoid AR adding the table name
    reorder('storage_size DESC, namespaces.id DESC')
  else
    order_by(method)
  end
end

.without_integration(integration) ⇒ Object


159
160
161
162
163
164
165
166
# File 'app/models/group.rb', line 159

def without_integration(integration)
  services = Service
    .select('1')
    .where('services.group_id = namespaces.id')
    .where(type: integration.type)

  where('NOT EXISTS (?)', services)
end

Instance Method Details

#access_level_rolesObject


600
601
602
# File 'app/models/group.rb', line 600

def access_level_roles
  GroupMember.access_level_roles
end

#access_level_valuesObject


604
605
606
# File 'app/models/group.rb', line 604

def access_level_values
  access_level_roles.values
end

#access_request_approvers_to_be_notifiedObject


547
548
549
# File 'app/models/group.rb', line 547

def access_request_approvers_to_be_notified
  members.owners..limit(ACCESS_REQUEST_APPROVERS_TO_BE_NOTIFIED_LIMIT)
end

#add_developer(user, current_user = nil) ⇒ Object


291
292
293
# File 'app/models/group.rb', line 291

def add_developer(user, current_user = nil)
  add_user(user, :developer, current_user: current_user)
end

#add_guest(user, current_user = nil) ⇒ Object


283
284
285
# File 'app/models/group.rb', line 283

def add_guest(user, current_user = nil)
  add_user(user, :guest, current_user: current_user)
end

#add_maintainer(user, current_user = nil) ⇒ Object


295
296
297
# File 'app/models/group.rb', line 295

def add_maintainer(user, current_user = nil)
  add_user(user, :maintainer, current_user: current_user)
end

#add_owner(user, current_user = nil) ⇒ Object


299
300
301
# File 'app/models/group.rb', line 299

def add_owner(user, current_user = nil)
  add_user(user, :owner, current_user: current_user)
end

#add_reporter(user, current_user = nil) ⇒ Object


287
288
289
# File 'app/models/group.rb', line 287

def add_reporter(user, current_user = nil)
  add_user(user, :reporter, current_user: current_user)
end

#add_user(user, access_level, current_user: nil, expires_at: nil, ldap: false) ⇒ Object


272
273
274
275
276
277
278
279
280
281
# File 'app/models/group.rb', line 272

def add_user(user, access_level, current_user: nil, expires_at: nil, ldap: false)
  GroupMember.add_user(
    self,
    user,
    access_level,
    current_user: current_user,
    expires_at: expires_at,
    ldap: ldap
  )
end

#add_users(users, access_level, current_user: nil, expires_at: nil) ⇒ Object


262
263
264
265
266
267
268
269
270
# File 'app/models/group.rb', line 262

def add_users(users, access_level, current_user: nil, expires_at: nil)
  GroupMember.add_users(
    self,
    users,
    access_level,
    current_user: current_user,
    expires_at: expires_at
  )
end

#adjourned_deletion?Boolean

Returns:

  • (Boolean)

563
564
565
# File 'app/models/group.rb', line 563

def adjourned_deletion?
  false
end

#ci_variables_for(ref, project) ⇒ Object


494
495
496
497
498
499
500
501
502
503
504
# File 'app/models/group.rb', line 494

def ci_variables_for(ref, project)
  cache_key = "ci_variables_for:group:#{self&.id}:project:#{project&.id}:ref:#{ref}"

  ::Gitlab::SafeRequestStore.fetch(cache_key) do
    list_of_ids = [self] + ancestors
    variables = Ci::GroupVariable.where(group: list_of_ids)
    variables = variables.unprotected unless project.protected_for?(ref)
    variables = variables.group_by(&:group_id)
    list_of_ids.reverse.flat_map { |group| variables[group.id] }.compact
  end
end

#default_branch_nameObject


596
597
598
# File 'app/models/group.rb', line 596

def default_branch_name
  namespace_settings&.default_branch_name
end

#default_ownerObject


592
593
594
# File 'app/models/group.rb', line 592

def default_owner
  owners.first || parent&.default_owner || owner
end

#dependency_proxy_feature_available?Boolean

Returns:

  • (Boolean)

209
210
211
# File 'app/models/group.rb', line 209

def dependency_proxy_feature_available?
  ::Gitlab.config.dependency_proxy.enabled
end

#direct_and_indirect_membersObject

Returns all members that are part of the group, it's subgroups, and ancestor groups


399
400
401
402
403
# File 'app/models/group.rb', line 399

def direct_and_indirect_members
  GroupMember
    .active_without_invites_and_requests
    .where(source_id: self_and_hierarchy.reorder(nil).select(:id))
end

#direct_and_indirect_members_with_inactiveObject


405
406
407
408
409
410
# File 'app/models/group.rb', line 405

def direct_and_indirect_members_with_inactive
  GroupMember
    .non_request
    .non_invite
    .where(source_id: self_and_hierarchy.reorder(nil).select(:id))
end

#direct_and_indirect_usersObject

Returns all users that are members of the group because:

  1. They belong to the group

  2. They belong to a project that belongs to the group

  3. They belong to a sub-group or project in such sub-group

  4. They belong to an ancestor group


429
430
431
432
433
434
435
436
# File 'app/models/group.rb', line 429

def direct_and_indirect_users
  User.from_union([
    User
      .where(id: direct_and_indirect_members.select(:user_id))
      .reorder(nil),
    project_users_with_descendants
  ])
end

#direct_and_indirect_users_with_inactiveObject

Returns all users (also inactive) that are members of the group because:

  1. They belong to the group

  2. They belong to a project that belongs to the group

  3. They belong to a sub-group or project in such sub-group

  4. They belong to an ancestor group


443
444
445
446
447
448
449
450
# File 'app/models/group.rb', line 443

def direct_and_indirect_users_with_inactive
  User.from_union([
    User
      .where(id: direct_and_indirect_members_with_inactive.select(:user_id))
      .reorder(nil),
    project_users_with_descendants
  ])
end

#execute_hooks(data, hooks_scope) ⇒ Object


567
568
569
570
# File 'app/models/group.rb', line 567

def execute_hooks(data, hooks_scope)
  # NOOP
  # TODO: group hooks https://gitlab.com/gitlab-org/gitlab/-/issues/216904
end

#execute_services(data, hooks_scope) ⇒ Object


572
573
574
575
# File 'app/models/group.rb', line 572

def execute_services(data, hooks_scope)
  # NOOP
  # TODO: group hooks https://gitlab.com/gitlab-org/gitlab/-/issues/216904
end

#export_fileObject


559
560
561
# File 'app/models/group.rb', line 559

def export_file
  import_export_upload&.export_file
end

#export_file_exists?Boolean

Returns:

  • (Boolean)

555
556
557
# File 'app/models/group.rb', line 555

def export_file_exists?
  export_file&.file
end

#group_member(user) ⇒ Object


506
507
508
509
510
511
512
# File 'app/models/group.rb', line 506

def group_member(user)
  if group_members.loaded?
    group_members.find { |gm| gm.user_id == user.id }
  else
    group_members.find_by(user_id: user)
  end
end

#has_container_repository_including_subgroups?Boolean

Returns:

  • (Boolean)

321
322
323
# File 'app/models/group.rb', line 321

def has_container_repository_including_subgroups?
  ::ContainerRepository.for_group_and_its_subgroups(self).exists?
end

#has_maintainer?(user) ⇒ Boolean

Returns:

  • (Boolean)

315
316
317
318
319
# File 'app/models/group.rb', line 315

def has_maintainer?(user)
  return false unless user

  members_with_parents.maintainers.exists?(user_id: user)
end

#has_owner?(user) ⇒ Boolean

Returns:

  • (Boolean)

309
310
311
312
313
# File 'app/models/group.rb', line 309

def has_owner?(user)
  return false unless user

  members_with_parents.owners.exists?(user_id: user)
end

#has_project_with_service_desk_enabled?Boolean

Returns:

  • (Boolean)

615
616
617
# File 'app/models/group.rb', line 615

def has_project_with_service_desk_enabled?
  Gitlab::ServiceDesk.supported? && all_projects.service_desk_enabled.exists?
end

#hashed_storage?(_feature) ⇒ Boolean

Returns:

  • (Boolean)

524
525
526
# File 'app/models/group.rb', line 524

def hashed_storage?(_feature)
  false
end

#highest_group_member(user) ⇒ Object


514
515
516
# File 'app/models/group.rb', line 514

def highest_group_member(user)
  GroupMember.where(source_id: self_and_ancestors_ids, user_id: user.id).order(:access_level).last
end

#human_nameObject


227
228
229
# File 'app/models/group.rb', line 227

def human_name
  full_name
end

#last_owner?(user) ⇒ Boolean

Check if user is a last owner of the group.

Returns:

  • (Boolean)

326
327
328
# File 'app/models/group.rb', line 326

def last_owner?(user)
  has_owner?(user) && members_with_parents.owners.size == 1
end

#ldap_synced?Boolean

Returns:

  • (Boolean)

330
331
332
# File 'app/models/group.rb', line 330

def ldap_synced?
  false
end

#lfs_enabled?Boolean

Returns:

  • (Boolean)

251
252
253
254
255
256
# File 'app/models/group.rb', line 251

def lfs_enabled?
  return false unless Gitlab.config.lfs.enabled
  return Gitlab.config.lfs.enabled if self[:lfs_enabled].nil?

  self[:lfs_enabled]
end

#mattermost_team_paramsObject


484
485
486
487
488
489
490
491
492
# File 'app/models/group.rb', line 484

def mattermost_team_params
  max_length = 59

  {
    name: path[0..max_length],
    display_name: name[0..max_length],
    type: public? ? 'O' : 'I' # Open vs Invite-only
  }
end

#max_member_access_for_user(user, only_concrete_membership: false) ⇒ Object

Return the highest access level for a user

A special case is handled here when the user is a GitLab admin which implies it has “OWNER” access everywhere, but should not officially appear as a member of a group unless specifically added to it

Parameters:

  • user (User)
  • only_concrete_membership (Bool) (defaults to: false)

    whether require admin concrete membership status


472
473
474
475
476
477
478
479
480
481
482
# File 'app/models/group.rb', line 472

def max_member_access_for_user(user, only_concrete_membership: false)
  return GroupMember::NO_ACCESS unless user
  return GroupMember::OWNER if user.admin? && !only_concrete_membership

  max_member_access = members_with_parents.where(user_id: user)
                                          .reorder(access_level: :desc)
                                          .first
                                          &.access_level

  max_member_access || GroupMember::NO_ACCESS
end

#member?(user, min_access_level = Gitlab::Access::GUEST) ⇒ Boolean

Returns:

  • (Boolean)

303
304
305
306
307
# File 'app/models/group.rb', line 303

def member?(user, min_access_level = Gitlab::Access::GUEST)
  return false unless user

  max_member_access_for_user(user) >= min_access_level
end

#members_from_self_and_ancestors_with_effective_access_levelObject


387
388
389
390
# File 'app/models/group.rb', line 387

def members_from_self_and_ancestors_with_effective_access_level
  members_with_parents.select([:user_id, 'MAX(access_level) AS access_level'])
                      .group(:user_id)
end

#members_with_descendantsObject


392
393
394
395
396
# File 'app/models/group.rb', line 392

def members_with_descendants
  GroupMember
    .active_without_invites_and_requests
    .where(source_id: self_and_descendants.reorder(nil).select(:id))
end

#members_with_parentsObject


370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
# File 'app/models/group.rb', line 370

def members_with_parents
  # Avoids an unnecessary SELECT when the group has no parents
  source_ids =
    if has_parent?
      self_and_ancestors.reorder(nil).select(:id)
    else
      id
    end

  group_hierarchy_members = GroupMember.active_without_invites_and_requests
                                       .non_minimal_access
                                       .where(source_id: source_ids)

  GroupMember.from_union([group_hierarchy_members,
                          members_from_self_and_ancestor_group_shares])
end

#notification_email_for(user) ⇒ Object


213
214
215
216
217
# File 'app/models/group.rb', line 213

def notification_email_for(user)
  # Finds the closest notification_setting with a `notification_email`
  notification_settings = notification_settings_for(user, hierarchy_order: :asc)
  notification_settings.find { |n| n.notification_email.present? }&.notification_email
end

#notification_settings(hierarchy_order: nil) ⇒ Object

Overrides notification_settings has_many association This allows to apply notification settings from parent groups to child groups and projects.


189
190
191
192
193
194
195
196
197
198
199
# File 'app/models/group.rb', line 189

def notification_settings(hierarchy_order: nil)
  source_type = self.class.base_class.name
  settings = NotificationSetting.where(source_type: source_type, source_id: self_and_ancestors_ids)

  return settings unless hierarchy_order && self_and_ancestors_ids.length > 1

  settings
    .joins("LEFT JOIN (#{self_and_ancestors(hierarchy_order: hierarchy_order).to_sql}) AS ordered_groups ON notification_settings.source_id = ordered_groups.id")
    .select('notification_settings.*, ordered_groups.depth AS depth')
    .order("ordered_groups.depth #{hierarchy_order}")
end

#notification_settings_for(user, hierarchy_order: nil) ⇒ Object


201
202
203
# File 'app/models/group.rb', line 201

def notification_settings_for(user, hierarchy_order: nil)
  notification_settings(hierarchy_order: hierarchy_order).where(user: user)
end

#owned_by?(user) ⇒ Boolean

Returns:

  • (Boolean)

258
259
260
# File 'app/models/group.rb', line 258

def owned_by?(user)
  owners.include?(user)
end

#packages_feature_enabled?Boolean

Returns:

  • (Boolean)

205
206
207
# File 'app/models/group.rb', line 205

def packages_feature_enabled?
  ::Gitlab.config.packages.enabled
end

#parent_allows_two_factor_authentication?Boolean

Returns:

  • (Boolean)

608
609
610
611
612
613
# File 'app/models/group.rb', line 608

def parent_allows_two_factor_authentication?
  return true unless has_parent?

  ancestor_settings = ancestors.find_by(parent_id: nil).namespace_settings
  ancestor_settings.allow_mfa_for_subgroups
end

#post_create_hookObject


334
335
336
337
338
# File 'app/models/group.rb', line 334

def post_create_hook
  Gitlab::AppLogger.info("Group \"#{name}\" was created")

  system_hook_service.execute_hooks_for(self, :create)
end

#post_destroy_hookObject


340
341
342
343
344
# File 'app/models/group.rb', line 340

def post_destroy_hook
  Gitlab::AppLogger.info("Group \"#{name}\" was removed")

  system_hook_service.execute_hooks_for(self, :destroy)
end

577
578
579
580
# File 'app/models/group.rb', line 577

def preload_shared_group_links
  preloader = ActiveRecord::Associations::Preloader.new
  preloader.preload(self, shared_with_group_links: [shared_with_group: :route])
end

#project_creation_levelObject


539
540
541
# File 'app/models/group.rb', line 539

def project_creation_level
  super || ::Gitlab::CurrentSettings.default_project_creation
end

#project_users_with_descendantsObject

Returns all users that are members of projects belonging to the current group or sub-groups


458
459
460
461
462
# File 'app/models/group.rb', line 458

def project_users_with_descendants
  User
    .joins(projects: :group)
    .where(namespaces: { id: self_and_descendants.select(:id) })
end

#refresh_members_authorized_projects(blocking: true, priority: UserProjectAccessChangedService::HIGH_PRIORITY) ⇒ Object

rubocop: disable CodeReuse/ServiceClass


353
354
355
356
357
# File 'app/models/group.rb', line 353

def refresh_members_authorized_projects(blocking: true, priority: UserProjectAccessChangedService::HIGH_PRIORITY)
  UserProjectAccessChangedService
    .new(user_ids_for_project_authorizations)
    .execute(blocking: blocking, priority: priority)
end

#refresh_project_authorizationsObject


528
529
530
# File 'app/models/group.rb', line 528

def refresh_project_authorizations
  refresh_members_authorized_projects(blocking: false)
end

518
519
520
521
522
# File 'app/models/group.rb', line 518

def related_group_ids
  [id,
   *ancestors.pluck(:id),
   *shared_with_group_links.pluck(:shared_with_group_id)]
end

#runners_tokenObject

each existing group needs to have a `runners_token`. we do this on read since migrating all existing groups is not a feasible solution.


535
536
537
# File 'app/models/group.rb', line 535

def runners_token
  ensure_runners_token!
end

#self_and_ancestors_idsObject


364
365
366
367
368
# File 'app/models/group.rb', line 364

def self_and_ancestors_ids
  strong_memoize(:self_and_ancestors_ids) do
    self_and_ancestors.pluck(:id)
  end
end

#subgroup_creation_levelObject


543
544
545
# File 'app/models/group.rb', line 543

def subgroup_creation_level
  super || ::Gitlab::Access::OWNER_SUBGROUP_ACCESS
end

#supports_events?Boolean

Returns:

  • (Boolean)

551
552
553
# File 'app/models/group.rb', line 551

def supports_events?
  false
end

#system_hook_serviceObject

rubocop: disable CodeReuse/ServiceClass


347
348
349
# File 'app/models/group.rb', line 347

def system_hook_service
  SystemHooksService.new
end

#to_reference(_from = nil, target_project: nil, full: nil) ⇒ Object


219
220
221
# File 'app/models/group.rb', line 219

def to_reference(_from = nil, target_project: nil, full: nil)
  "#{self.class.reference_prefix}#{full_path}"
end

#update_shared_runners_setting!(state) ⇒ Object

Raises:

  • (ArgumentError)

582
583
584
585
586
587
588
589
590
# File 'app/models/group.rb', line 582

def update_shared_runners_setting!(state)
  raise ArgumentError unless SHARED_RUNNERS_SETTINGS.include?(state)

  case state
  when 'disabled_and_unoverridable' then disable_shared_runners! # also disallows override
  when 'disabled_with_override' then disable_shared_runners_and_allow_override!
  when 'enabled' then enable_shared_runners! # set both to true
  end
end

#user_ids_for_project_authorizationsObject

rubocop: enable CodeReuse/ServiceClass


360
361
362
# File 'app/models/group.rb', line 360

def user_ids_for_project_authorizations
  members_with_parents.pluck(:user_id)
end

#users_countObject


452
453
454
# File 'app/models/group.rb', line 452

def users_count
  members.count
end

#users_with_descendantsObject


418
419
420
421
422
# File 'app/models/group.rb', line 418

def users_with_descendants
  User
    .where(id: members_with_descendants.select(:user_id))
    .reorder(nil)
end

#users_with_parentsObject


412
413
414
415
416
# File 'app/models/group.rb', line 412

def users_with_parents
  User
    .where(id: members_with_parents.select(:user_id))
    .reorder(nil)
end

#visibility_level_allowed?(level = self.visibility_level) ⇒ Boolean

Returns:

  • (Boolean)

245
246
247
248
249
# File 'app/models/group.rb', line 245

def visibility_level_allowed?(level = self.visibility_level)
  visibility_level_allowed_by_parent?(level) &&
    visibility_level_allowed_by_projects?(level) &&
    visibility_level_allowed_by_sub_groups?(level)
end

#visibility_level_allowed_by_parent?(level = self.visibility_level) ⇒ Boolean

Returns:

  • (Boolean)

231
232
233
234
235
# File 'app/models/group.rb', line 231

def visibility_level_allowed_by_parent?(level = self.visibility_level)
  return true unless parent_id && parent_id.nonzero?

  level <= parent.visibility_level
end

#visibility_level_allowed_by_projects?(level = self.visibility_level) ⇒ Boolean

Returns:

  • (Boolean)

237
238
239
# File 'app/models/group.rb', line 237

def visibility_level_allowed_by_projects?(level = self.visibility_level)
  !projects.where('visibility_level > ?', level).exists?
end

#visibility_level_allowed_by_sub_groups?(level = self.visibility_level) ⇒ Boolean

Returns:

  • (Boolean)

241
242
243
# File 'app/models/group.rb', line 241

def visibility_level_allowed_by_sub_groups?(level = self.visibility_level)
  !children.where('visibility_level > ?', level).exists?
end

#web_url(only_path: nil) ⇒ Object


223
224
225
# File 'app/models/group.rb', line 223

def web_url(only_path: nil)
  Gitlab::UrlBuilder.build(self, only_path: only_path)
end