Class: Group

Defined Under Namespace

Classes: CrmSettings

Constant Summary collapse

README_PROJECT_PATH =
'gitlab-profile'

Constants included from WithUploads

WithUploads::FILE_UPLOADERS

Constants included from Avatarable

Avatarable::ALLOWED_IMAGE_SCALER_WIDTHS, Avatarable::COMBINED_AVATAR_SIZES, Avatarable::COMBINED_AVATAR_SIZES_RETINA, Avatarable::GROUP_AVATAR_SIZES, Avatarable::MAXIMUM_FILE_SIZE, Avatarable::PROJECT_AVATAR_SIZES, Avatarable::USER_AVATAR_SIZES

Constants inherited from Namespace

Namespace::NUMBER_OF_ANCESTORS_ALLOWED, Namespace::SHARED_RUNNERS_SETTINGS, Namespace::SR_DISABLED_AND_OVERRIDABLE, Namespace::SR_DISABLED_AND_UNOVERRIDABLE, Namespace::SR_ENABLED, Namespace::STATISTICS_COLUMNS, Namespace::URL_MAX_LENGTH

Constants included from Cells::Claimable

Cells::Claimable::CLAIMS_BUCKET_TYPE, Cells::Claimable::CLAIMS_SOURCE_TYPE, Cells::Claimable::CLAIMS_SUBJECT_TYPE, Cells::Claimable::MissingPrimaryKeyError

Constants included from BlocksUnsafeSerialization

BlocksUnsafeSerialization::UnsafeSerializationError

Constants included from Namespaces::Stateful

Namespaces::Stateful::STATES

Constants included from Namespaces::Traversal::Linear

Namespaces::Traversal::Linear::UnboundedSearch

Constants included from Gitlab::SQL::Pattern

Gitlab::SQL::Pattern::MIN_CHARS_FOR_PARTIAL_MATCHING, Gitlab::SQL::Pattern::REGEX_QUOTED_TERM

Constants included from Gitlab::VisibilityLevel

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

Constants inherited from ApplicationRecord

ApplicationRecord::MAX_PLUCK

Constants included from HasCheckConstraints

HasCheckConstraints::NOT_NULL_CHECK_PATTERN

Constants included from ResetOnColumnErrors

ResetOnColumnErrors::MAX_RESET_PERIOD

Instance Attribute Summary

Attributes included from Importable

#importing, #user_contributions

Attributes inherited from Namespace

#emails_enabled_memoized, #root_ancestor

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Gitlab::Utils::Override

extended, extensions, included, method_added, override, prepended, queue_verification, verify!

Methods included from RunnerTokenExpirationInterval

#effective_runner_token_expiration_interval, #effective_runner_token_expiration_interval_human_readable, #enforced_runner_token_expiration_interval_human_readable

Methods included from ChronicDurationAttribute

#chronic_duration_attributes, #output_chronic_duration_attribute

Methods included from GroupAPICompatibility

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

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, #guest_count, #has_subgroups?, #member_count, #project_count, #subgroup_count

Methods included from Avatarable

#avatar_path, #avatar_type, #uncached_avatar_path, #upload_paths

Methods included from Authz::HasRoles

#can_assign_role?, #roles_user_can_assign

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_active_project_ids, #all_ancestors_have_runner_registration_enabled?, #all_catalog_resources, #all_container_repositories, #all_project_ids_except, #all_projects, #all_projects_except_soft_deleted, #all_projects_with_pages, #allow_runner_registration_token?, #allowed_work_item_type?, #allowed_work_item_types, #ancestors_archived?, #any_project_has_container_registry_tags?, #any_project_with_pages_deployed?, #any_project_with_shared_runners_enabled?, #archived?, #auto_devops_enabled?, #bot_user_namespace?, by_path, #certificate_based_clusters_enabled?, #changing_allow_descendants_override_disabled_shared_runners_is_allowed, #changing_shared_runners_enabled_is_allowed, clean_path, #closest_setting, #container_repositories_size, #container_repositories_size_cache_key, #default_branch_protected?, #default_branch_protection, #default_branch_protection_settings, #emails_disabled?, #emails_enabled?, #enabled_git_access_protocol, find_by_path_or_name, #find_fork_of, find_top_level, #first_auto_devops_config, #first_project_with_container_registry_tags, #full_path_before_last_save, gfm_autocomplete_search, #group_namespace?, #has_parent?, #issue_repositioning_disabled?, #kind, #licensed_feature_available?, #linked_to_subscription?, #multiple_issue_boards_available?, #namespace_details, #owner_entity, #owner_entity_name, #owner_required?, #package_settings, #pages_access_control_forced_by_ancestor?, #pages_access_control_forced_by_self_or_ancestor?, #pages_access_control_trie, #paid?, #pipeline_variables_default_role, #project_namespace?, #recent?, reference_pattern, reference_prefix, #root?, root_ids_for, search, #self_deletion_in_progress?, #self_or_ancestors_archived?, self_or_ancestors_archived_setting_subquery, #send_update_instructions, #shared_runners, #shared_runners_setting, #shared_runners_setting_higher_than?, sti_class_for, #subgroup?, sum_project_statistics_column, #supports_work_items?, #to_param, #to_reference, #to_reference_base, #traversal_ids_as_sql, #uploads_sharding_key, #user_namespace?, #user_role, username_reserved?, username_reserved_for_organization?, #visibility_level_field, #web_url

Methods included from Cells::Claimable

#handle_grpc_error

Methods included from Referable

#referable_inspect, #reference_link_text, #to_reference, #to_reference_base

Methods included from Ci::NamespaceSettings

#allow_stale_runner_pruning=, #allow_stale_runner_pruning?

Methods included from BlocksUnsafeSerialization

#serializable_hash

Methods included from Organizations::Isolatable

#isolated?, #mark_as_isolated!, #mark_as_not_isolated!, #not_isolated?

Methods included from Namespaces::AdjournedDeletable

#ancestor_scheduled_for_deletion?, #deletion_adjourned_period, #deletion_in_progress_or_scheduled_in_hierarchy_chain?, #first_scheduled_for_deletion_in_hierarchy_chain, #scheduled_for_deletion_in_hierarchy_chain?, #self_deletion_in_progress?, #self_deletion_scheduled?, #self_deletion_scheduled_deletion_created_on

Methods included from Namespaces::Traversal::Cached

#all_project_ids, #all_unarchived_project_ids, #descendant_ids, #self_and_descendant_ids

Methods included from Namespaces::Traversal::Linear

#all_project_ids, #ancestor_ids, #ancestors, #ancestors_upto, #descendants, #parent=, #parent_id=, #root_ancestor, #self_and_ancestor_ids, #self_and_ancestors, #self_and_descendant_ids, #self_and_descendants, #self_and_hierarchy, #traversal_path, #use_traversal_ids?

Methods included from Namespaces::Traversal::Recursive

#all_project_ids, #all_unarchived_project_ids, #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

Methods included from FeatureGate

#flipper_id

Methods included from Gitlab::SQL::Pattern

split_query_to_search_terms

Methods included from Routable

#build_full_path, find_by_full_path, #full_name, #full_path, #full_path_components

Methods included from Gitlab::VisibilityLevel

allowed_for?, allowed_level?, allowed_levels, allowed_levels_for_user, 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

Methods inherited from ApplicationRecord

===, cached_column_list, #create_or_load_association, current_transaction, declarative_enum, default_select_columns, delete_all_returning, #deleted_from_database?, id_in, id_not_in, iid_in, nullable_column?, 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

Methods included from Organizations::Sharding

#sharding_organization

Methods included from ResetOnColumnErrors

#reset_on_union_error, #reset_on_unknown_attribute_error

Methods included from Gitlab::SensitiveSerializableHash

#serializable_hash

Class Method Details

.descendant_groups_countsObject



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

def descendant_groups_counts
  left_joins(:children).group(:id).count(:children_namespaces)
end

.get_ids_by_ids_or_paths(ids, paths) ⇒ Object



510
511
512
# File 'app/models/group.rb', line 510

def get_ids_by_ids_or_paths(ids, paths)
  by_ids_or_paths(ids, paths).pluck(:id)
end

.group_members_countsObject



522
523
524
# File 'app/models/group.rb', line 522

def group_members_counts
  left_joins(:group_members).group(:id).count(:members)
end

.groups_user_can(groups, user, action, same_root: false) ⇒ Object



475
476
477
478
479
# File 'app/models/group.rb', line 475

def groups_user_can(groups, user, action, same_root: false)
  DeclarativePolicy.user_scope do
    groups.select { |group| Ability.allowed?(user, action, group) }
  end
end

.ids_with_disabled_email(groups) ⇒ Object

Returns the ids of the passed group models where the emails_enabled column is set to false anywhere in the ancestor hierarchy.



492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
# File 'app/models/group.rb', line 492

def ids_with_disabled_email(groups)
  inner_groups = Group.where('id = namespaces_with_emails_disabled.id')
  inner_query = inner_groups
    .self_and_ancestors
    .joins(:namespace_settings)
    .where(namespace_settings: { emails_enabled: false })
    .select('1')
    .limit(1)

  group_ids = Namespace
    .from('(SELECT * FROM namespaces) as namespaces_with_emails_disabled')
    .where(namespaces_with_emails_disabled: { id: groups })
    .where('EXISTS (?)', inner_query)
    .pluck(:id)

  Set.new(group_ids)
end

.preset_root_ancestor_for(groups) ⇒ Object

This method can be used only if all groups have the same top-level group



483
484
485
486
487
488
# File 'app/models/group.rb', line 483

def preset_root_ancestor_for(groups)
  return groups if groups.size < 2

  root = groups.first.root_ancestor
  groups.drop(1).each { |group| group.root_ancestor = root }
end

.prevent_project_creation?(user, project_creation_setting) ⇒ Boolean

Returns:

  • (Boolean)


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

def prevent_project_creation?(user, project_creation_setting)
  return true if project_creation_setting == ::Gitlab::Access::NO_ONE_PROJECT_ACCESS
  return false if Ability.allowed?(user, :admin_all_resources)

  project_creation_setting == ::Gitlab::Access::ADMINISTRATOR_PROJECT_ACCESS
end

.project_creation_levels_for_user(user) ⇒ Object

Handle project creation permissions based on application setting and group setting. The default_project_creation application setting is the default value and can be overridden by the project_creation_level group setting. nil value of namespaces.project_creation_level` means that allowed creation level has not been explicitly set by the group owner and is a placeholder value for inheriting the value from the ApplicationSetting.



541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
# File 'app/models/group.rb', line 541

def project_creation_levels_for_user(user)
  project_creation_allowed_on_levels = [
    ::Gitlab::Access::DEVELOPER_PROJECT_ACCESS,
    ::Gitlab::Access::MAINTAINER_PROJECT_ACCESS,
    ::Gitlab::Access::OWNER_PROJECT_ACCESS,
    nil
  ]

  if user.can_admin_all_resources?
    project_creation_allowed_on_levels << ::Gitlab::Access::ADMINISTRATOR_PROJECT_ACCESS
  end

  default_project_creation = ::Gitlab::CurrentSettings.default_project_creation
  prevent_project_creation_by_default = prevent_project_creation?(user, default_project_creation)

  # Remove nil (i.e. inherited `default_project_creation`) when the application setting is:
  # 1. NO_ONE_PROJECT_ACCESS
  # 2. ADMINISTRATOR_PROJECT_ACCESS and the user is not an admin
  #
  # To prevent showing groups in the namespaces dropdown on the project creation page that have no explicit group
  # setting for `project_creation_level`.
  project_creation_allowed_on_levels.delete(nil) if prevent_project_creation_by_default

  project_creation_allowed_on_levels
end

.projects_countsObject



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

def projects_counts
  left_joins(:non_archived_projects).group(:id).count(:projects)
end

.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



446
447
448
449
450
451
452
453
454
# File 'app/models/group.rb', line 446

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

.select_for_project_authorizationObject



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

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

.self_or_ancestors_deletion_schedule_subqueryObject



574
575
576
577
578
579
580
581
582
583
584
585
# File 'app/models/group.rb', line 574

def self_or_ancestors_deletion_schedule_subquery
  deletion_schedule_reflection = reflect_on_association(:deletion_schedule)
  deletion_schedule_table = Arel::Table.new(deletion_schedule_reflection.table_name)
  traversal_ids_ref = "#{arel_table.name}.#{arel_table[:traversal_ids].name}"

  deletion_schedule_table
    .project(1)
    .where(
      deletion_schedule_table[deletion_schedule_reflection.foreign_key]
        .eq(Arel.sql("ANY (#{traversal_ids_ref})"))
    )
end

.sort_by_attribute(method) ⇒ Object



424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
# File 'app/models/group.rb', line 424

def sort_by_attribute(method)
  case method.to_s
  when 'storage_size_keyset_asc'
    order_storage_size_keyset(:asc)
  when 'storage_size_keyset_desc'
    order_storage_size_keyset(:desc)
  when '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')
  when 'path_asc'
    order_path_asc
  when 'path_desc'
    order_path_desc
  else
    order_by(method)
  end
end

.sti_nameObject



33
34
35
# File 'app/models/group.rb', line 33

def self.sti_name
  'Group'
end

.supported_keyset_orderingsObject



37
38
39
# File 'app/models/group.rb', line 37

def self.supported_keyset_orderings
  { name: [:asc] }
end

.with_api_scopesObject



526
527
528
529
530
531
532
533
534
535
# File 'app/models/group.rb', line 526

def with_api_scopes
  preload(
    :namespace_settings,
    :namespace_settings_with_ancestors_inherited_settings,
    :namespace_details,
    :group_feature,
    :parent,
    :deletion_schedule
  )
end

.without_integration(integration) ⇒ Object



466
467
468
469
470
471
472
473
# File 'app/models/group.rb', line 466

def without_integration(integration)
  integrations = Integration
    .select('1')
    .where("#{Integration.table_name}.group_id = namespaces.id")
    .where(type: integration.type)

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

Instance Method Details

#access_level_rolesObject



1082
1083
1084
# File 'app/models/group.rb', line 1082

def access_level_roles
  GroupMember.access_level_roles
end

#access_level_valuesObject



1086
1087
1088
# File 'app/models/group.rb', line 1086

def access_level_values
  access_level_roles.values
end

#access_request_approvers_to_be_notifiedObject



1022
1023
1024
# File 'app/models/group.rb', line 1022

def access_request_approvers_to_be_notified
  members.owners.connected_to_user..limit(Member::ACCESS_REQUEST_APPROVERS_TO_BE_NOTIFIED_LIMIT)
end

#active?Boolean

Returns:

  • (Boolean)


1292
1293
1294
# File 'app/models/group.rb', line 1292

def active?
  self_and_ancestors.inactive.none?
end

#add_developer(user, current_user = nil) ⇒ Object



729
730
731
# File 'app/models/group.rb', line 729

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

#add_guest(user, current_user = nil) ⇒ Object



711
712
713
# File 'app/models/group.rb', line 711

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

#add_maintainer(user, current_user = nil) ⇒ Object



733
734
735
# File 'app/models/group.rb', line 733

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

#add_member(user, access_level) ⇒ Object



707
708
709
# File 'app/models/group.rb', line 707

def add_member(user, access_level, ...)
  Members::Groups::CreatorService.add_member(self, user, access_level, ...) # rubocop:disable CodeReuse/ServiceClass
end

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



697
698
699
700
701
702
703
704
705
# File 'app/models/group.rb', line 697

def add_members(users, access_level, current_user: nil, expires_at: nil)
  Members::Groups::CreatorService.add_members( # rubocop:disable CodeReuse/ServiceClass
    self,
    users,
    access_level,
    current_user: current_user,
    expires_at: expires_at
  )
end

#add_owner(user, current_user = nil) ⇒ Object



737
738
739
# File 'app/models/group.rb', line 737

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

#add_planner(user, current_user = nil) ⇒ Object



715
716
717
# File 'app/models/group.rb', line 715

def add_planner(user, current_user = nil)
  add_member(user, :planner, current_user: current_user)
end

#add_reporter(user, current_user = nil) ⇒ Object



719
720
721
# File 'app/models/group.rb', line 719

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

#add_security_manager(user, current_user = nil) ⇒ Object



723
724
725
726
727
# File 'app/models/group.rb', line 723

def add_security_manager(user, current_user = nil)
  return unless Gitlab::Security::SecurityManagerConfig.enabled?

  add_member(user, :security_manager, current_user: current_user)
end

#allow_iframes_in_markdown_feature_flag_enabled?Boolean

Returns:

  • (Boolean)


1161
1162
1163
# File 'app/models/group.rb', line 1161

def allow_iframes_in_markdown_feature_flag_enabled?
  feature_flag_enabled_for_self_or_ancestor?(:allow_iframes_in_markdown, type: :wip)
end

#authorizable_members_with_parentsObject



890
891
892
# File 'app/models/group.rb', line 890

def authorizable_members_with_parents
  Members::MembersWithParents.new(self).all_members.authorizable
end

#blocked_ownersObject



753
754
755
# File 'app/models/group.rb', line 753

def blocked_owners
  members.blocked.where(access_level: Gitlab::Access::OWNER)
end

#botsObject



987
988
989
# File 'app/models/group.rb', line 987

def bots
  users.project_bot
end

#cluster_agentsObject



1288
1289
1290
# File 'app/models/group.rb', line 1288

def cluster_agents
  ::Clusters::Agent.for_projects(all_projects)
end

#crm_enabled?Boolean

Returns:

  • (Boolean)


1130
1131
1132
# File 'app/models/group.rb', line 1130

def crm_enabled?
  crm_settings.nil? || crm_settings.enabled?
end

#crm_groupObject



1261
1262
1263
1264
1265
1266
# File 'app/models/group.rb', line 1261

def crm_group
  Group.id_in_ordered(traversal_ids.reverse)
    .joins(:crm_settings)
    .where.not(crm_settings: { source_group_id: nil })
    .first&.crm_settings&.source_group || root_ancestor
end

#crm_group?Boolean

Returns:

  • (Boolean)


1269
1270
1271
1272
1273
# File 'app/models/group.rb', line 1269

def crm_group?
  return true if root? && crm_settings&.source_group_id.nil?

  crm_targets.present?
end

#default_branch_nameObject



1078
1079
1080
# File 'app/models/group.rb', line 1078

def default_branch_name
  namespace_settings&.default_branch_name
end

#delete_contactsObject



1280
1281
1282
# File 'app/models/group.rb', line 1280

def delete_contacts
  CustomerRelations::Contact.where(group_id: id).delete_all
end

#delete_organizationsObject



1284
1285
1286
# File 'app/models/group.rb', line 1284

def delete_organizations
  CustomerRelations::Organization.where(group_id: id).delete_all
end

#dependency_proxy_feature_available?Boolean

Returns:

  • (Boolean)


628
629
630
# File 'app/models/group.rb', line 628

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

#dependency_proxy_for_containers_policy_subjectObject



1230
1231
1232
# File 'app/models/group.rb', line 1230

def dependency_proxy_for_containers_policy_subject
  ::Packages::Policies::DependencyProxy::Group.new(self)
end

#dependency_proxy_image_prefixObject



638
639
640
641
642
643
644
645
# File 'app/models/group.rb', line 638

def dependency_proxy_image_prefix
  # The namespace path can include uppercase letters, which
  # Docker doesn't allow. The proxy expects it to be downcased.
  url = "#{Gitlab::Routing.url_helpers.group_url(self).downcase}#{DependencyProxy::URL_SUFFIX}"

  # Docker images do not include the protocol
  url.partition('//').last
end

#dependency_proxy_image_ttl_policyObject



1118
1119
1120
# File 'app/models/group.rb', line 1118

def dependency_proxy_image_ttl_policy
  super || build_dependency_proxy_image_ttl_policy
end

#dependency_proxy_settingObject



1122
1123
1124
# File 'app/models/group.rb', line 1122

def dependency_proxy_setting
  super || build_dependency_proxy_setting
end

#descendant_project_members_with_inactiveObject



925
926
927
928
929
930
# File 'app/models/group.rb', line 925

def descendant_project_members_with_inactive
  ProjectMember
    .with_source_id(all_projects)
    .non_request
    .non_invite
end

#direct_membersObject



884
885
886
887
888
# File 'app/models/group.rb', line 884

def direct_members
  GroupMember.active_without_invites_and_requests
             .non_minimal_access
             .where(source_id: id)
end

#enforced_runner_token_expiration_intervalObject



1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
# File 'app/models/group.rb', line 1138

def enforced_runner_token_expiration_interval
  all_parent_groups = Gitlab::ObjectHierarchy.new(Group.where(id: id)).ancestors
  all_group_settings = NamespaceSetting.where(namespace_id: all_parent_groups)
  group_interval = all_group_settings.where.not(subgroup_runner_token_expiration_interval: nil).minimum(:subgroup_runner_token_expiration_interval)&.seconds

  [
    Gitlab::CurrentSettings.group_runner_token_expiration_interval&.seconds,
    group_interval
  ].compact.min
end

#enterprise_user_settings_available?(user = nil) ⇒ Boolean

overriden in EE

Returns:

  • (Boolean)


1190
1191
1192
# File 'app/models/group.rb', line 1190

def (user = nil)
  false
end

#execute_hooks(data, hooks_scope) ⇒ Object



1050
1051
1052
1053
# File 'app/models/group.rb', line 1050

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

#execute_integrations(data, hooks_scope) ⇒ Object



1059
1060
1061
1062
1063
# File 'app/models/group.rb', line 1059

def execute_integrations(data, hooks_scope)
  integrations.public_send(hooks_scope).each do |integration| # rubocop:disable GitlabSecurity/PublicSend
    integration.async_execute(data)
  end
end

#export_archive_exists?(user) ⇒ Boolean

Returns:

  • (Boolean)


1046
1047
1048
# File 'app/models/group.rb', line 1046

def export_archive_exists?(user)
  import_export_upload_by_user(user)&.export_archive_exists?
end

#export_file(user) ⇒ Object



1042
1043
1044
# File 'app/models/group.rb', line 1042

def export_file(user)
  import_export_upload_by_user(user)&.export_file
end

#export_file_exists?(user) ⇒ Boolean

Returns:

  • (Boolean)


1038
1039
1040
# File 'app/models/group.rb', line 1038

def export_file_exists?(user)
  import_export_upload_by_user(user)&.export_file_exists?
end

#feature_available?(feature, user = nil) ⇒ Boolean

Returns:

  • (Boolean)


1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
# File 'app/models/group.rb', line 1209

def feature_available?(feature, user = nil)
  # when we check the :issues feature at group level we need to check the `epics` license feature instead
  feature = :epics if feature == :issues

  if ::Groups::FeatureSetting.available_features.include?(feature)
    group_feature.feature_available?(feature, user) # rubocop:disable Gitlab/FeatureAvailableUsage
  else
    super
  end
end

#find_or_initialize_integration(integration) ⇒ Object



1055
1056
1057
# File 'app/models/group.rb', line 1055

def find_or_initialize_integration(integration)
  Integration.find_or_initialize_non_project_specific_integration(integration, group_id: id)
end

#first_ownerObject



1072
1073
1074
1075
1076
# File 'app/models/group.rb', line 1072

def first_owner
  first_owner_member = all_group_members.all_owners.order(:user_id).first

  first_owner_member&.user || parent&.first_owner || owner
end

#gitlab_deploy_tokenObject



1220
1221
1222
1223
1224
# File 'app/models/group.rb', line 1220

def gitlab_deploy_token
  strong_memoize(:gitlab_deploy_token) do
    deploy_tokens.gitlab_deploy_token
  end
end

#glql_load_on_click_feature_flag_enabled?Boolean

Returns:

  • (Boolean)


1157
1158
1159
# File 'app/models/group.rb', line 1157

def glql_load_on_click_feature_flag_enabled?
  feature_flag_enabled_for_self_or_ancestor?(:glql_load_on_click, type: :ops)
end

#group_featureObject



1126
1127
1128
# File 'app/models/group.rb', line 1126

def group_feature
  super || build_group_feature
end

#group_readmeObject



1247
1248
1249
# File 'app/models/group.rb', line 1247

def group_readme
  readme_project&.repository&.readme
end

#has_active_hooks?(hooks_scope = :push_hooks) ⇒ Boolean

overriden in EE

Returns:

  • (Boolean)


1185
1186
1187
# File 'app/models/group.rb', line 1185

def has_active_hooks?(hooks_scope = :push_hooks)
  false
end

#has_container_repository_including_subgroups?Boolean

Returns:

  • (Boolean)


763
764
765
# File 'app/models/group.rb', line 763

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

#has_issues_with_contacts?Boolean

Returns:

  • (Boolean)


1276
1277
1278
# File 'app/models/group.rb', line 1276

def has_issues_with_contacts?
  CustomerRelations::IssueContact.joins(:issue).where(issue: { project_id: Project.where(namespace_id: self_and_descendant_ids) }).exists?
end

#has_maintainer?(user) ⇒ Boolean

Returns:

  • (Boolean)


757
758
759
760
761
# File 'app/models/group.rb', line 757

def has_maintainer?(user)
  return false unless user

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

#has_owner?(user) ⇒ Boolean

Returns:

  • (Boolean)


747
748
749
750
751
# File 'app/models/group.rb', line 747

def has_owner?(user)
  return false unless user

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

#has_project_with_service_desk_enabled?Boolean

Returns:

  • (Boolean)


1097
1098
1099
# File 'app/models/group.rb', line 1097

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

#has_user?(user) ⇒ Boolean

Only for direct and not requested members with higher access level than MIMIMAL_ACCESS It returns true for non-active users

Returns:

  • (Boolean)


878
879
880
881
882
# File 'app/models/group.rb', line 878

def has_user?(user)
  return false unless user

  group_members.non_invite.exists?(user: user)
end

#hashed_storage?(_feature) ⇒ Boolean

Returns:

  • (Boolean)


997
998
999
# File 'app/models/group.rb', line 997

def hashed_storage?(_feature)
  false
end

#hierarchy_membersObject

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



912
913
914
915
916
# File 'app/models/group.rb', line 912

def hierarchy_members
  GroupMember
    .active_without_invites_and_requests
    .where(source_id: self_and_hierarchy.without_order.select(:id))
end

#hierarchy_members_with_inactiveObject



918
919
920
921
922
923
# File 'app/models/group.rb', line 918

def hierarchy_members_with_inactive
  GroupMember
    .non_request
    .non_invite
    .where(source_id: self_and_hierarchy.without_order.select(:id))
end

#highest_group_member(user) ⇒ Object



979
980
981
982
983
984
985
# File 'app/models/group.rb', line 979

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

#hook_attrsObject



1252
1253
1254
1255
1256
1257
1258
1259
# File 'app/models/group.rb', line 1252

def hook_attrs
  {
    group_name: name,
    group_path: path,
    group_id: id,
    full_path: full_path
  }
end

#human_nameObject



647
648
649
# File 'app/models/group.rb', line 647

def human_name
  full_name
end

#import_export_upload_by_user(user) ⇒ Object



1034
1035
1036
# File 'app/models/group.rb', line 1034

def import_export_upload_by_user(user)
  import_export_uploads.find_by(user_id: user.id)
end

#last_owner?(user) ⇒ Boolean

Check if user is a last owner of the group. Excludes non-direct owners for top-level group Excludes project_bots

Returns:

  • (Boolean)


770
771
772
773
774
775
# File 'app/models/group.rb', line 770

def last_owner?(user)
  return false unless user

  all_owners = member_owners_excluding_project_bots_and_service_accounts
  last_owner_in_list?(user, all_owners)
end

#last_owner_in_list?(user, all_owners) ⇒ Boolean

This is used in BillableMember Entity to avoid multiple “member_owners_excluding_project_bots_and_service_accounts” calls for each billable members

Returns:

  • (Boolean)


780
781
782
783
784
# File 'app/models/group.rb', line 780

def last_owner_in_list?(user, all_owners)
  return false unless user

  all_owners.size == 1 && all_owners.first.user_id == user.id
end

#ldap_synced?Boolean

Returns:

  • (Boolean)


806
807
808
# File 'app/models/group.rb', line 806

def ldap_synced?
  false
end

#lfs_enabled?Boolean

Returns:

  • (Boolean)


684
685
686
687
688
689
# File 'app/models/group.rb', line 684

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

  self[:lfs_enabled]
end

#markdown_placeholders_feature_flag_enabled?Boolean

Returns:

  • (Boolean)


1153
1154
1155
# File 'app/models/group.rb', line 1153

def markdown_placeholders_feature_flag_enabled?
  feature_flag_enabled_for_self_or_ancestor?(:markdown_placeholders, type: :gitlab_com_derisk)
end

#mattermost_team_paramsObject



961
962
963
964
965
966
967
968
969
# File 'app/models/group.rb', line 961

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



950
951
952
953
954
955
956
957
958
959
# File 'app/models/group.rb', line 950

def max_member_access_for_user(user, only_concrete_membership: false)
  return GroupMember::NO_ACCESS unless user

  unless only_concrete_membership
    return GroupMember::OWNER if user.can_admin_all_resources?
    return GroupMember::OWNER if user.can_admin_organization?(organization)
  end

  max_member_access(user)
end

#member(user) ⇒ Object



971
972
973
974
975
976
977
# File 'app/models/group.rb', line 971

def 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

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

Returns:

  • (Boolean)


741
742
743
744
745
# File 'app/models/group.rb', line 741

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

  max_member_access_for_user(user) >= min_access_level
end

#member_owners_excluding_project_bots_and_service_accountsObject

Excludes non-direct owners for top-level group Excludes project_bots Excludes service accounts



789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
# File 'app/models/group.rb', line 789

def member_owners_excluding_project_bots_and_service_accounts
  members_from_hierarchy = if root?
                             members.non_minimal_access.without_invites_and_requests
                           else
                             members_with_parents(only_active_users: false)
                           end

  owners = []
  members_from_hierarchy.all_owners.non_invite.each_batch do |relation|
    owners += relation.preload(:user, :source).load.reject do |member|
      member.user.nil? || member.user.project_bot? || member.user.service_account?
    end
  end

  owners
end

#members_from_self_and_ancestors_with_effective_access_levelObject



900
901
902
903
# File 'app/models/group.rb', line 900

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



905
906
907
908
909
# File 'app/models/group.rb', line 905

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

#members_with_parents(only_active_users: true) ⇒ Object



894
895
896
897
898
# File 'app/models/group.rb', line 894

def members_with_parents(only_active_users: true)
  Members::MembersWithParents
    .new(self)
    .members(active_users: only_active_users)
end

#membership_locked?Boolean

Returns:

  • (Boolean)


1026
1027
1028
# File 'app/models/group.rb', line 1026

def membership_locked?
  false # to support project and group calling this as 'source'
end

#notification_email_for(user) ⇒ Object



632
633
634
635
636
# File 'app/models/group.rb', line 632

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_groupObject



1243
1244
1245
# File 'app/models/group.rb', line 1243

def notification_group
  self
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.



608
609
610
611
612
613
614
615
616
617
618
# File 'app/models/group.rb', line 608

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



620
621
622
# File 'app/models/group.rb', line 620

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

#open_issues_count(current_user = nil) ⇒ Object

rubocop: disable CodeReuse/ServiceClass



1103
1104
1105
# File 'app/models/group.rb', line 1103

def open_issues_count(current_user = nil)
  Groups::OpenIssuesCountService.new(self, current_user).count
end

#open_merge_requests_count(current_user = nil) ⇒ Object

rubocop: disable CodeReuse/ServiceClass



1109
1110
1111
# File 'app/models/group.rb', line 1109

def open_merge_requests_count(current_user = nil)
  Groups::MergeRequestsCountService.new(self, current_user).count
end

#owned_by?(user) ⇒ Boolean

Returns:

  • (Boolean)


691
692
693
694
695
# File 'app/models/group.rb', line 691

def owned_by?(user)
  return false unless user

  non_invite_owner_members.exists?(user: user)
end

#packages_feature_enabled?Boolean

Returns:

  • (Boolean)


624
625
626
# File 'app/models/group.rb', line 624

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

#packages_policy_subjectObject



1226
1227
1228
# File 'app/models/group.rb', line 1226

def packages_policy_subject
  ::Packages::Policies::Group.new(self)
end

#parent_allows_two_factor_authentication?Boolean

Returns:

  • (Boolean)


1090
1091
1092
1093
1094
1095
# File 'app/models/group.rb', line 1090

def parent_allows_two_factor_authentication?
  return true unless has_parent?

  ancestor_settings = ancestors.find_top_level.namespace_settings
  ancestor_settings.allow_mfa_for_subgroups
end

#pending_delete?Boolean

Returns:

  • (Boolean)


1296
1297
1298
1299
1300
# File 'app/models/group.rb', line 1296

def pending_delete?
  return false unless deletion_schedule

  deletion_schedule.marked_for_deletion_on.future?
end

#post_create_hookObject



810
811
812
813
814
# File 'app/models/group.rb', line 810

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

  system_hook_service.execute_hooks_for(self, :create)
end

#post_destroy_hookObject



816
817
818
819
820
# File 'app/models/group.rb', line 816

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

  system_hook_service.execute_hooks_for(self, :destroy)
end


1065
1066
1067
1068
1069
1070
# File 'app/models/group.rb', line 1065

def preload_shared_group_links
  ActiveRecord::Associations::Preloader.new(
    records: [self],
    associations: { shared_with_group_links: [shared_with_group: :route] }
  ).call
end

#project_creation_levelObject



1014
1015
1016
# File 'app/models/group.rb', line 1014

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

#readme_projectObject



1238
1239
1240
# File 'app/models/group.rb', line 1238

def readme_project
  projects.find_by(path: README_PROJECT_PATH)
end

#refresh_members_authorized_projects(priority: UserProjectAccessChangedService::HIGH_PRIORITY, direct_members_only: false) ⇒ Object

rubocop: disable CodeReuse/ServiceClass



829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
# File 'app/models/group.rb', line 829

def refresh_members_authorized_projects(
  priority: UserProjectAccessChangedService::HIGH_PRIORITY,
  direct_members_only: false
)

  user_ids = if direct_members_only
               users_ids_of_direct_members
             else
               user_ids_for_project_authorizations
             end

  UserProjectAccessChangedService
    .new(user_ids)
    .execute(priority: priority)
end

#refresh_project_authorizationsObject



1001
1002
1003
# File 'app/models/group.rb', line 1001

def refresh_project_authorizations
  refresh_members_authorized_projects
end


991
992
993
994
995
# File 'app/models/group.rb', line 991

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.



1008
1009
1010
1011
1012
# File 'app/models/group.rb', line 1008

def runners_token
  return unless allow_runner_registration_token?

  ensure_runners_token!
end

#self_and_ancestors_ascObject



871
872
873
# File 'app/models/group.rb', line 871

def self_and_ancestors_asc
  self_and_ancestors(hierarchy_order: :asc)
end

#self_and_ancestors_idsObject



859
860
861
862
863
# File 'app/models/group.rb', line 859

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

#self_and_descendants_idsObject



865
866
867
868
869
# File 'app/models/group.rb', line 865

def self_and_descendants_ids
  strong_memoize(:self_and_descendants_ids) do
    self_and_descendants.pluck(:id)
  end
end

#self_and_hierarchy_intersecting_with_user_groups(user) ⇒ Object



854
855
856
857
# File 'app/models/group.rb', line 854

def self_and_hierarchy_intersecting_with_user_groups(user)
  user_groups = GroupsFinder.new(user).execute.unscope(:order)
  self_and_hierarchy.unscope(:order).where(id: user_groups)
end


1134
1135
1136
# File 'app/models/group.rb', line 1134

def shared_with_group_links_visible_to_user(user)
  shared_with_group_links.preload_shared_with_groups.filter { |link| Ability.allowed?(user, :read_group, link.shared_with_group) }
end

#subgroup_creation_levelObject



1018
1019
1020
# File 'app/models/group.rb', line 1018

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

#supports_events?Boolean

Returns:

  • (Boolean)


1030
1031
1032
# File 'app/models/group.rb', line 1030

def supports_events?
  false
end

#supports_lock_on_merge?Boolean

Returns:

  • (Boolean)


1194
1195
1196
# File 'app/models/group.rb', line 1194

def supports_lock_on_merge?
  feature_flag_enabled_for_self_or_ancestor?(:enforce_locked_labels_on_merge, type: :ops)
end

#supports_saved_replies?Boolean

Returns:

  • (Boolean)


1202
1203
1204
# File 'app/models/group.rb', line 1202

def supports_saved_replies?
  false
end

#system_hook_serviceObject

rubocop: disable CodeReuse/ServiceClass



823
824
825
# File 'app/models/group.rb', line 823

def system_hook_service
  SystemHooksService.new
end

#timelogsObject

rubocop: enable CodeReuse/ServiceClass



1114
1115
1116
# File 'app/models/group.rb', line 1114

def timelogs
  Timelog.in_group(self)
end

#to_human_reference(from = nil) ⇒ Object



651
652
653
654
655
# File 'app/models/group.rb', line 651

def to_human_reference(from = nil)
  return unless cross_namespace_reference?(from)

  human_name
end

#unarchive_all_projects!Object



1308
1309
1310
1311
1312
1313
1314
# File 'app/models/group.rb', line 1308

def unarchive_all_projects!
  Project
    .joins(:namespace)
    .where("namespaces.traversal_ids @> '{?}'", id)
    .where(archived: true)
    .update_all(archived: false)
end

#unarchive_descendants!Object



1302
1303
1304
1305
1306
# File 'app/models/group.rb', line 1302

def unarchive_descendants!
  NamespaceSetting
    .where(namespace_id: descendant_ids, archived: true)
    .update_all(archived: false)
end

#update_two_factor_requirement_for_membersObject



1234
1235
1236
# File 'app/models/group.rb', line 1234

def update_two_factor_requirement_for_members
  hierarchy_members.find_each(&:update_two_factor_requirement)
end

#usage_quotas_enabled?Boolean

Returns:

  • (Boolean)


1198
1199
1200
# File 'app/models/group.rb', line 1198

def usage_quotas_enabled?
  root?
end

#use_work_item_url?Boolean

Returns:

  • (Boolean)


1178
1179
1180
1181
1182
# File 'app/models/group.rb', line 1178

def use_work_item_url?
  return false if feature_flag_enabled_for_self_or_ancestor?(:work_item_legacy_url, type: :gitlab_com_derisk)

  work_items_consolidated_list_enabled?
end

#user_ids_for_project_authorizationsObject



850
851
852
# File 'app/models/group.rb', line 850

def user_ids_for_project_authorizations
  members_with_parents.pluck(Arel.sql('DISTINCT members.user_id'))
end

#users_countObject



938
939
940
# File 'app/models/group.rb', line 938

def users_count
  members.count
end

#users_ids_of_direct_membersObject

rubocop: enable CodeReuse/ServiceClass



846
847
848
# File 'app/models/group.rb', line 846

def users_ids_of_direct_members
  direct_members.pluck_user_ids
end

#users_with_descendantsObject



932
933
934
935
936
# File 'app/models/group.rb', line 932

def users_with_descendants
  User
    .id_in(members_with_descendants.select(:user_id))
    .without_order
end

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

Returns:

  • (Boolean)


677
678
679
680
681
682
# File 'app/models/group.rb', line 677

def visibility_level_allowed?(level = self.visibility_level)
  visibility_level_allowed_by_organization?(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_organization?(level = self.visibility_level) ⇒ Boolean

Returns:

  • (Boolean)


657
658
659
660
661
# File 'app/models/group.rb', line 657

def visibility_level_allowed_by_organization?(level = self.visibility_level)
  return true unless organization

  level <= organization.visibility_level
end

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

Returns:

  • (Boolean)


663
664
665
666
667
# File 'app/models/group.rb', line 663

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)


669
670
671
# File 'app/models/group.rb', line 669

def visibility_level_allowed_by_projects?(level = self.visibility_level)
  !projects.not_aimed_for_deletion.with_visibility_level_greater_than(level).exists?
end

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

Returns:

  • (Boolean)


673
674
675
# File 'app/models/group.rb', line 673

def visibility_level_allowed_by_sub_groups?(level = self.visibility_level)
  !children.with_visibility_level_greater_than(level).exists?
end

#work_item_tasks_on_boards_feature_flag_enabled?Boolean

Returns:

  • (Boolean)


1149
1150
1151
# File 'app/models/group.rb', line 1149

def work_item_tasks_on_boards_feature_flag_enabled?
  feature_flag_enabled_for_self_or_ancestor?(:work_item_tasks_on_boards, type: :wip)
end

#work_items_consolidated_list_enabled?(user = nil) ⇒ Boolean

Returns:

  • (Boolean)


1171
1172
1173
1174
1175
1176
# File 'app/models/group.rb', line 1171

def work_items_consolidated_list_enabled?(user = nil)
  # work_item_planning_view is the feature flag used to determine whether the consolidated list is enabled or not
  return true if feature_flag_enabled_for_self_or_ancestor?(:work_item_planning_view, type: :wip)

  user.present? && Feature.enabled?(:work_items_consolidated_list_user, user)
end

#work_items_saved_views_enabled?(user = nil) ⇒ Boolean

Returns:

  • (Boolean)


1165
1166
1167
1168
1169
# File 'app/models/group.rb', line 1165

def work_items_saved_views_enabled?(user = nil)
  return true if feature_flag_enabled_for_self_or_ancestor?(:work_items_saved_views, type: :wip)

  user.present? && Feature.enabled?(:work_items_saved_views_user, user)
end