Class: Group
- Inherits:
-
Namespace
show all
- Extended by:
- Gitlab::Utils::Override
- Includes:
- AccessRequestable, AfterCommitQueue, Avatarable, BulkMemberAccessLoad, BulkUsersByEmailLoad, ChronicDurationAttribute, EachBatch, Gitlab::ConfigHelper, Gitlab::Utils::StrongMemoize, GroupAPICompatibility, GroupDescendant, LoadedInGroupList, RunnerTokenExpirationInterval, SelectForProjectAuthorization, Todoable, TokenAuthenticatable, WithUploads
- Defined in:
- app/models/group.rb
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::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_DISABLED_WITH_OVERRIDE, Namespace::SR_ENABLED, Namespace::URL_MAX_LENGTH
BlocksUnsafeSerialization::UnsafeSerializationError
Namespaces::Traversal::Linear::UnboundedSearch
Gitlab::SQL::Pattern::MIN_CHARS_FOR_PARTIAL_MATCHING, Gitlab::SQL::Pattern::REGEX_QUOTED_TERM
Gitlab::VisibilityLevel::INTERNAL, Gitlab::VisibilityLevel::PRIVATE, Gitlab::VisibilityLevel::PUBLIC
CacheMarkdownField::INVALIDATED_BY
ApplicationRecord::MAX_PLUCK
ResetOnUnionError::MAX_RESET_PERIOD
Instance Attribute Summary
Attributes inherited from Namespace
#emails_disabled_memoized, #root_ancestor
#skip_markdown_cache_validation
Class Method Summary
collapse
Instance Method Summary
collapse
-
#access_level_roles ⇒ Object
-
#access_level_values ⇒ Object
-
#access_request_approvers_to_be_notified ⇒ Object
-
#activity_path ⇒ Object
-
#add_developer(user, current_user = nil) ⇒ Object
-
#add_guest(user, current_user = nil) ⇒ Object
-
#add_maintainer(user, current_user = nil) ⇒ Object
-
#add_member(user, access_level, current_user: nil, expires_at: nil, ldap: false) ⇒ Object
-
#add_members(users, access_level, current_user: nil, expires_at: nil, tasks_to_be_done: [], tasks_project_id: nil) ⇒ Object
-
#add_owner(user, current_user = nil) ⇒ Object
-
#add_reporter(user, current_user = nil) ⇒ Object
-
#adjourned_deletion? ⇒ Boolean
-
#authorizable_members_with_parents ⇒ Object
-
#blocked_owners ⇒ Object
-
#bots ⇒ Object
-
#content_editor_on_issues_feature_flag_enabled? ⇒ Boolean
-
#crm_enabled? ⇒ Boolean
-
#default_branch_name ⇒ Object
-
#dependency_proxy_feature_available? ⇒ Boolean
-
#dependency_proxy_image_prefix ⇒ Object
-
#dependency_proxy_image_ttl_policy ⇒ Object
-
#dependency_proxy_setting ⇒ Object
-
#descendant_project_members_with_inactive ⇒ Object
-
#direct_members ⇒ Object
-
#enforced_runner_token_expiration_interval ⇒ Object
-
#execute_hooks(data, hooks_scope) ⇒ Object
-
#execute_integrations(data, hooks_scope) ⇒ Object
-
#export_archive_exists? ⇒ Boolean
-
#export_file ⇒ Object
-
#export_file_exists? ⇒ Boolean
-
#feature_available?(feature, user = nil) ⇒ Boolean
-
#first_owner ⇒ Object
-
#gitlab_deploy_token ⇒ Object
-
#group_feature ⇒ Object
-
#group_readme ⇒ Object
-
#has_container_repository_including_subgroups? ⇒ Boolean
-
#has_maintainer?(user) ⇒ Boolean
-
#has_owner?(user) ⇒ Boolean
-
#has_project_with_service_desk_enabled? ⇒ Boolean
-
#hashed_storage?(_feature) ⇒ Boolean
-
#hierarchy_members ⇒ Object
Returns all members that are part of the group, it’s subgroups, and ancestor groups.
-
#hierarchy_members_with_inactive ⇒ Object
-
#highest_group_member(user) ⇒ Object
-
#human_name ⇒ Object
-
#last_owner?(user) ⇒ Boolean
Check if user is a last owner of the group.
-
#ldap_synced? ⇒ Boolean
-
#lfs_enabled? ⇒ Boolean
-
#linked_work_items_feature_flag_enabled? ⇒ Boolean
-
#mattermost_team_params ⇒ Object
-
#max_member_access_for_user(user, only_concrete_membership: false) ⇒ Object
Return the highest access level for a user.
-
#member(user) ⇒ Object
-
#member?(user, min_access_level = Gitlab::Access::GUEST) ⇒ Boolean
-
#member_owners_excluding_project_bots ⇒ Object
Excludes non-direct owners for top-level group Excludes project_bots.
-
#members_from_self_and_ancestors_with_effective_access_level ⇒ Object
-
#members_with_descendants ⇒ Object
-
#members_with_parents(only_active_users: true) ⇒ Object
-
#membership_locked? ⇒ Boolean
-
#notification_email_for(user) ⇒ Object
-
#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.
-
#notification_settings_for(user, hierarchy_order: nil) ⇒ Object
-
#open_issues_count(current_user = nil) ⇒ Object
rubocop: disable CodeReuse/ServiceClass.
-
#open_merge_requests_count(current_user = nil) ⇒ Object
rubocop: disable CodeReuse/ServiceClass.
-
#owned_by?(user) ⇒ Boolean
-
#packages_feature_enabled? ⇒ Boolean
-
#packages_policy_subject ⇒ Object
-
#parent_allows_two_factor_authentication? ⇒ Boolean
-
#post_create_hook ⇒ Object
-
#post_destroy_hook ⇒ Object
-
#preload_shared_group_links ⇒ Object
-
#project_creation_level ⇒ Object
-
#project_users_with_descendants ⇒ Object
Returns all users that are members of projects belonging to the current group or sub-groups.
-
#readme_project ⇒ Object
-
#refresh_members_authorized_projects(priority: UserProjectAccessChangedService::HIGH_PRIORITY, direct_members_only: false) ⇒ Object
rubocop: disable CodeReuse/ServiceClass.
-
#refresh_project_authorizations ⇒ Object
-
#related_group_ids ⇒ Object
-
#runners_token ⇒ Object
each existing group needs to have a ‘runners_token`.
-
#self_and_ancestors_ids ⇒ Object
-
#self_and_descendants_ids ⇒ Object
-
#self_and_hierarchy_intersecting_with_user_groups(user) ⇒ Object
-
#shared_with_group_links_visible_to_user(user) ⇒ Object
-
#subgroup_creation_level ⇒ Object
-
#supports_events? ⇒ Boolean
-
#supports_lock_on_merge? ⇒ Boolean
-
#system_hook_service ⇒ Object
rubocop: disable CodeReuse/ServiceClass.
-
#timelogs ⇒ Object
rubocop: enable CodeReuse/ServiceClass.
-
#update_two_factor_requirement_for_members ⇒ Object
-
#usage_quotas_enabled? ⇒ Boolean
-
#user_ids_for_project_authorizations ⇒ Object
-
#users_count ⇒ Object
-
#users_ids_of_direct_members ⇒ Object
rubocop: enable CodeReuse/ServiceClass.
-
#users_with_descendants ⇒ Object
-
#users_with_parents ⇒ Object
-
#visibility_level_allowed?(level = self.visibility_level) ⇒ Boolean
-
#visibility_level_allowed_by_parent?(level = self.visibility_level) ⇒ Boolean
-
#visibility_level_allowed_by_projects?(level = self.visibility_level) ⇒ Boolean
-
#visibility_level_allowed_by_sub_groups?(level = self.visibility_level) ⇒ Boolean
-
#web_url(only_path: nil) ⇒ Object
-
#work_items_feature_flag_enabled? ⇒ Boolean
-
#work_items_mvc_2_feature_flag_enabled? ⇒ Boolean
-
#work_items_mvc_feature_flag_enabled? ⇒ Boolean
extended, extensions, included, method_added, override, prepended, queue_verification, verify!
#effective_runner_token_expiration_interval, #effective_runner_token_expiration_interval_human_readable, #enforced_runner_token_expiration_interval_human_readable
#chronic_duration_attributes, #output_chronic_duration_attribute
#project_creation_level_str, #project_creation_level_str=, #subgroup_creation_level_str, #subgroup_creation_level_str=
#retrieve_upload
#perform_fast_destroy
#run_after_commit, #run_after_commit_or_now
build_hierarchy, #hierarchy
#children_count, #guest_count, #member_count, #project_count, #subgroup_count
Methods included from Avatarable
#avatar_path, #avatar_type, #uncached_avatar_path, #upload_paths
#request_access
#gitlab_config, #gitlab_config_features
Methods inherited from Namespace
#actual_limits, #actual_plan, #actual_plan_name, #aggregation_scheduled?, #all_ancestors_have_runner_registration_enabled?, #all_container_repositories, #all_project_ids, #all_project_ids_except, #all_projects, #all_projects_except_soft_deleted, #all_projects_with_pages, #allow_runner_registration_token?, #any_project_has_container_registry_tags?, #any_project_with_pages_deployed?, #any_project_with_shared_runners_enabled?, #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_name, clean_path, #closest_setting, #container_repositories_size, #container_repositories_size_cache_key, #default_branch_protection, #emails_disabled?, #emails_enabled?, #enabled_git_access_protocol, find_by_path_or_name, #find_fork_of, #first_auto_devops_config, #first_project_with_container_registry_tags, #full_path_before_last_save, #group_namespace?, #has_parent?, #issue_repositioning_disabled?, #kind, #licensed_feature_available?, #multiple_issue_boards_available?, #owner_required?, #package_settings, #paid?, #prevent_delete?, #project_namespace?, #recent?, reference_pattern, reference_prefix, #root?, search, #send_update_instructions, #shared_runners, #shared_runners_setting, #shared_runners_setting_higher_than?, sti_class_for, #subgroup?, #to_param, #to_reference, #to_reference_base, top_most, #user_namespace?, #visibility_level_field
Methods included from Referable
#referable_inspect, #reference_link_text, #to_reference, #to_reference_base
#allow_stale_runner_pruning=, #allow_stale_runner_pruning?
#serializable_hash
#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_ids, #traversal_ids=, #use_traversal_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
#flipper_id
split_query_to_search_terms
#move_dir, #prepare_for_destroy
#gitlab_shell
Methods included from Routable
#build_full_path, find_by_full_path, #full_name, #full_path, #full_path_components, optimize_routable_enabled?, #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?, #mentioned_filtered_user_ids_for, #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
Class Method Details
.get_ids_by_ids_or_paths(ids, paths) ⇒ Object
323
324
325
|
# File 'app/models/group.rb', line 323
def get_ids_by_ids_or_paths(ids, paths)
by_ids_or_paths(ids, paths).pluck(:id)
end
|
.ids_with_disabled_email(groups) ⇒ Object
Returns the ids of the passed group models where the ‘emails_disabled` column is set to true anywhere in the ancestor hierarchy.
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
|
# File 'app/models/group.rb', line 305
def ids_with_disabled_email(groups)
inner_groups = Group.where('id = namespaces_with_emails_disabled.id')
inner_query = inner_groups
.self_and_ancestors
.where(emails_disabled: true)
.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
296
297
298
299
300
301
|
# File 'app/models/group.rb', line 296
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
|
.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
265
266
267
268
269
270
271
272
273
|
# File 'app/models/group.rb', line 265
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_authorization ⇒ Object
275
276
277
278
279
280
281
282
283
|
# File 'app/models/group.rb', line 275
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
252
253
254
255
256
257
258
259
260
|
# File 'app/models/group.rb', line 252
def sort_by_attribute(method)
if method == 'storage_size_desc'
reorder('storage_size DESC, namespaces.id DESC')
else
order_by(method)
end
end
|
.sti_name ⇒ Object
28
29
30
|
# File 'app/models/group.rb', line 28
def self.sti_name
'Group'
end
|
.without_integration(integration) ⇒ Object
285
286
287
288
289
290
291
292
|
# File 'app/models/group.rb', line 285
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_roles ⇒ Object
#access_level_values ⇒ Object
815
816
817
|
# File 'app/models/group.rb', line 815
def access_level_values
access_level_roles.values
end
|
#access_request_approvers_to_be_notified ⇒ Object
#activity_path ⇒ Object
831
832
833
|
# File 'app/models/group.rb', line 831
def activity_path
Gitlab::Routing.url_helpers.activity_group_path(self)
end
|
#add_developer(user, current_user = nil) ⇒ Object
457
458
459
|
# File 'app/models/group.rb', line 457
def add_developer(user, current_user = nil)
add_member(user, :developer, current_user: current_user)
end
|
#add_guest(user, current_user = nil) ⇒ Object
449
450
451
|
# File 'app/models/group.rb', line 449
def add_guest(user, current_user = nil)
add_member(user, :guest, current_user: current_user)
end
|
#add_maintainer(user, current_user = nil) ⇒ Object
461
462
463
|
# File 'app/models/group.rb', line 461
def add_maintainer(user, current_user = nil)
add_member(user, :maintainer, current_user: current_user)
end
|
#add_member(user, access_level, current_user: nil, expires_at: nil, ldap: false) ⇒ Object
438
439
440
441
442
443
444
445
446
447
|
# File 'app/models/group.rb', line 438
def add_member(user, access_level, current_user: nil, expires_at: nil, ldap: false)
Members::Groups::CreatorService.add_member( self,
user,
access_level,
current_user: current_user,
expires_at: expires_at,
ldap: ldap
)
end
|
#add_members(users, access_level, current_user: nil, expires_at: nil, tasks_to_be_done: [], tasks_project_id: nil) ⇒ Object
426
427
428
429
430
431
432
433
434
435
436
|
# File 'app/models/group.rb', line 426
def add_members(users, access_level, current_user: nil, expires_at: nil, tasks_to_be_done: [], tasks_project_id: nil)
Members::Groups::CreatorService.add_members( self,
users,
access_level,
current_user: current_user,
expires_at: expires_at,
tasks_to_be_done: tasks_to_be_done,
tasks_project_id: tasks_project_id
)
end
|
#add_owner(user, current_user = nil) ⇒ Object
465
466
467
|
# File 'app/models/group.rb', line 465
def add_owner(user, current_user = nil)
add_member(user, :owner, current_user: current_user)
end
|
#add_reporter(user, current_user = nil) ⇒ Object
453
454
455
|
# File 'app/models/group.rb', line 453
def add_reporter(user, current_user = nil)
add_member(user, :reporter, current_user: current_user)
end
|
#adjourned_deletion? ⇒ Boolean
779
780
781
|
# File 'app/models/group.rb', line 779
def adjourned_deletion?
false
end
|
#authorizable_members_with_parents ⇒ Object
591
592
593
594
595
596
597
598
599
600
601
602
603
|
# File 'app/models/group.rb', line 591
def authorizable_members_with_parents
source_ids =
if has_parent?
self_and_ancestors.reorder(nil).select(:id)
else
id
end
group_hierarchy_members = GroupMember.where(source_id: source_ids).select(*GroupMember.cached_column_list)
GroupMember.from_union([group_hierarchy_members,
members_from_self_and_ancestor_group_shares]).authorizable
end
|
#blocked_owners ⇒ Object
481
482
483
|
# File 'app/models/group.rb', line 481
def blocked_owners
members.blocked.where(access_level: Gitlab::Access::OWNER)
end
|
#bots ⇒ Object
722
723
724
|
# File 'app/models/group.rb', line 722
def bots
users.project_bot
end
|
#content_editor_on_issues_feature_flag_enabled? ⇒ Boolean
882
883
884
|
# File 'app/models/group.rb', line 882
def content_editor_on_issues_feature_flag_enabled?
feature_flag_enabled_for_self_or_ancestor?(:content_editor_on_issues)
end
|
#crm_enabled? ⇒ Boolean
863
864
865
|
# File 'app/models/group.rb', line 863
def crm_enabled?
crm_settings&.enabled?
end
|
#default_branch_name ⇒ Object
807
808
809
|
# File 'app/models/group.rb', line 807
def default_branch_name
namespace_settings&.default_branch_name
end
|
#dependency_proxy_feature_available? ⇒ Boolean
368
369
370
|
# File 'app/models/group.rb', line 368
def dependency_proxy_feature_available?
::Gitlab.config.dependency_proxy.enabled
end
|
#dependency_proxy_image_prefix ⇒ Object
#dependency_proxy_image_ttl_policy ⇒ Object
851
852
853
|
# File 'app/models/group.rb', line 851
def dependency_proxy_image_ttl_policy
super || build_dependency_proxy_image_ttl_policy
end
|
#dependency_proxy_setting ⇒ Object
855
856
857
|
# File 'app/models/group.rb', line 855
def dependency_proxy_setting
super || build_dependency_proxy_setting
end
|
#descendant_project_members_with_inactive ⇒ Object
653
654
655
656
657
658
|
# File 'app/models/group.rb', line 653
def descendant_project_members_with_inactive
ProjectMember
.with_source_id(all_projects)
.non_request
.non_invite
end
|
#direct_members ⇒ Object
585
586
587
588
589
|
# File 'app/models/group.rb', line 585
def direct_members
GroupMember.active_without_invites_and_requests
.non_minimal_access
.where(source_id: id)
end
|
#enforced_runner_token_expiration_interval ⇒ Object
871
872
873
874
875
876
877
878
879
880
|
# File 'app/models/group.rb', line 871
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
|
#execute_hooks(data, hooks_scope) ⇒ Object
783
784
785
786
|
# File 'app/models/group.rb', line 783
def execute_hooks(data, hooks_scope)
end
|
#execute_integrations(data, hooks_scope) ⇒ Object
788
789
790
791
792
|
# File 'app/models/group.rb', line 788
def execute_integrations(data, hooks_scope)
integrations.public_send(hooks_scope).each do |integration| integration.async_execute(data)
end
end
|
#export_archive_exists? ⇒ Boolean
775
776
777
|
# File 'app/models/group.rb', line 775
def export_archive_exists?
import_export_upload&.export_archive_exists?
end
|
#export_file ⇒ Object
771
772
773
|
# File 'app/models/group.rb', line 771
def export_file
import_export_upload&.export_file
end
|
#export_file_exists? ⇒ Boolean
767
768
769
|
# File 'app/models/group.rb', line 767
def export_file_exists?
import_export_upload&.export_file_exists?
end
|
#feature_available?(feature, user = nil) ⇒ Boolean
913
914
915
916
917
918
919
|
# File 'app/models/group.rb', line 913
def feature_available?(feature, user = nil)
if ::Groups::FeatureSetting.available_features.include?(feature)
group_feature.feature_available?(feature, user) else
super
end
end
|
#first_owner ⇒ Object
801
802
803
804
805
|
# File 'app/models/group.rb', line 801
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_token ⇒ Object
921
922
923
924
925
|
# File 'app/models/group.rb', line 921
def gitlab_deploy_token
strong_memoize(:gitlab_deploy_token) do
deploy_tokens.gitlab_deploy_token
end
end
|
#group_feature ⇒ Object
859
860
861
|
# File 'app/models/group.rb', line 859
def group_feature
super || build_group_feature
end
|
#group_readme ⇒ Object
940
941
942
|
# File 'app/models/group.rb', line 940
def group_readme
readme_project&.repository&.readme
end
|
#has_container_repository_including_subgroups? ⇒ Boolean
491
492
493
|
# File 'app/models/group.rb', line 491
def has_container_repository_including_subgroups?
::ContainerRepository.for_group_and_its_subgroups(self).exists?
end
|
#has_maintainer?(user) ⇒ Boolean
485
486
487
488
489
|
# File 'app/models/group.rb', line 485
def has_maintainer?(user)
return false unless user
members_with_parents.maintainers.exists?(user_id: user)
end
|
#has_owner?(user) ⇒ Boolean
475
476
477
478
479
|
# File 'app/models/group.rb', line 475
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
826
827
828
|
# File 'app/models/group.rb', line 826
def has_project_with_service_desk_enabled?
Gitlab::ServiceDesk.supported? && all_projects.service_desk_enabled.exists?
end
|
#hashed_storage?(_feature) ⇒ Boolean
732
733
734
|
# File 'app/models/group.rb', line 732
def hashed_storage?(_feature)
false
end
|
#hierarchy_members ⇒ Object
Returns all members that are part of the group, it’s subgroups, and ancestor groups
640
641
642
643
644
|
# File 'app/models/group.rb', line 640
def hierarchy_members
GroupMember
.active_without_invites_and_requests
.where(source_id: self_and_hierarchy.reorder(nil).select(:id))
end
|
#hierarchy_members_with_inactive ⇒ Object
646
647
648
649
650
651
|
# File 'app/models/group.rb', line 646
def hierarchy_members_with_inactive
GroupMember
.non_request
.non_invite
.where(source_id: self_and_hierarchy.reorder(nil).select(:id))
end
|
#highest_group_member(user) ⇒ Object
718
719
720
|
# File 'app/models/group.rb', line 718
def highest_group_member(user)
GroupMember.where(source_id: self_and_ancestors_ids, user_id: user.id).order(:access_level).last
end
|
#human_name ⇒ Object
391
392
393
|
# File 'app/models/group.rb', line 391
def human_name
full_name
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
498
499
500
501
502
503
504
|
# File 'app/models/group.rb', line 498
def last_owner?(user)
return false unless user
all_owners = member_owners_excluding_project_bots
all_owners.size == 1 && all_owners.first.user_id == user.id
end
|
#ldap_synced? ⇒ Boolean
520
521
522
|
# File 'app/models/group.rb', line 520
def ldap_synced?
false
end
|
#lfs_enabled? ⇒ Boolean
415
416
417
418
419
420
|
# File 'app/models/group.rb', line 415
def lfs_enabled?
return false unless Gitlab.config.lfs.enabled
return Gitlab.config.lfs.enabled if self[:lfs_enabled].nil?
self[:lfs_enabled]
end
|
#linked_work_items_feature_flag_enabled? ⇒ Boolean
898
899
900
|
# File 'app/models/group.rb', line 898
def linked_work_items_feature_flag_enabled?
feature_flag_enabled_for_self_or_ancestor?(:linked_work_items)
end
|
#mattermost_team_params ⇒ Object
700
701
702
703
704
705
706
707
708
|
# File 'app/models/group.rb', line 700
def mattermost_team_params
max_length = 59
{
name: path[0..max_length],
display_name: name[0..max_length],
type: public? ? 'O' : 'I' }
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
693
694
695
696
697
698
|
# File 'app/models/group.rb', line 693
def max_member_access_for_user(user, only_concrete_membership: false)
return GroupMember::NO_ACCESS unless user
return GroupMember::OWNER if user.can_admin_all_resources? && !only_concrete_membership
max_member_access([user.id])[user.id]
end
|
#member(user) ⇒ Object
710
711
712
713
714
715
716
|
# File 'app/models/group.rb', line 710
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
469
470
471
472
473
|
# File 'app/models/group.rb', line 469
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 ⇒ Object
Excludes non-direct owners for top-level group Excludes project_bots
508
509
510
511
512
513
514
515
516
517
518
|
# File 'app/models/group.rb', line 508
def member_owners_excluding_project_bots
members_from_hiearchy = if root?
members.non_minimal_access.without_invites_and_requests
else
members_with_parents(only_active_users: false)
end
members_from_hiearchy.all_owners.left_outer_joins(:user)
.merge(User.without_project_bot)
.allow_cross_joins_across_databases(url: "https://gitlab.com/gitlab-org/gitlab/-/issues/417455")
end
|
#members_from_self_and_ancestors_with_effective_access_level ⇒ Object
628
629
630
631
|
# File 'app/models/group.rb', line 628
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_descendants ⇒ Object
633
634
635
636
637
|
# File 'app/models/group.rb', line 633
def members_with_descendants
GroupMember
.active_without_invites_and_requests
.where(source_id: self_and_descendants.reorder(nil).select(:id))
end
|
#members_with_parents(only_active_users: true) ⇒ Object
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
|
# File 'app/models/group.rb', line 605
def members_with_parents(only_active_users: true)
source_ids =
if has_parent?
self_and_ancestors.reorder(nil).select(:id)
else
id
end
group_hierarchy_members = GroupMember.non_minimal_access
.where(source_id: source_ids)
.select(*GroupMember.cached_column_list)
group_hierarchy_members = if only_active_users
group_hierarchy_members.active_without_invites_and_requests
else
group_hierarchy_members.without_invites_and_requests
end
GroupMember.from_union([group_hierarchy_members,
members_from_self_and_ancestor_group_shares])
end
|
#membership_locked? ⇒ Boolean
759
760
761
|
# File 'app/models/group.rb', line 759
def membership_locked?
false end
|
#notification_email_for(user) ⇒ Object
372
373
374
375
376
|
# File 'app/models/group.rb', line 372
def notification_email_for(user)
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.
348
349
350
351
352
353
354
355
356
357
358
|
# File 'app/models/group.rb', line 348
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
360
361
362
|
# File 'app/models/group.rb', line 360
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
#open_merge_requests_count(current_user = nil) ⇒ Object
rubocop: disable CodeReuse/ServiceClass
#owned_by?(user) ⇒ Boolean
422
423
424
|
# File 'app/models/group.rb', line 422
def owned_by?(user)
owners.include?(user)
end
|
#packages_feature_enabled? ⇒ Boolean
364
365
366
|
# File 'app/models/group.rb', line 364
def packages_feature_enabled?
::Gitlab.config.packages.enabled
end
|
#packages_policy_subject ⇒ Object
927
928
929
|
# File 'app/models/group.rb', line 927
def packages_policy_subject
::Packages::Policies::Group.new(self)
end
|
#parent_allows_two_factor_authentication? ⇒ Boolean
819
820
821
822
823
824
|
# File 'app/models/group.rb', line 819
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_hook ⇒ Object
524
525
526
527
528
|
# File 'app/models/group.rb', line 524
def post_create_hook
Gitlab::AppLogger.info("Group \"#{name}\" was created")
system_hook_service.execute_hooks_for(self, :create)
end
|
#post_destroy_hook ⇒ Object
530
531
532
533
534
|
# File 'app/models/group.rb', line 530
def post_destroy_hook
Gitlab::AppLogger.info("Group \"#{name}\" was removed")
system_hook_service.execute_hooks_for(self, :destroy)
end
|
#preload_shared_group_links ⇒ Object
794
795
796
797
798
799
|
# File 'app/models/group.rb', line 794
def preload_shared_group_links
ActiveRecord::Associations::Preloader.new(
records: [self],
associations: { shared_with_group_links: [shared_with_group: :route] }
).call
end
|
#project_creation_level ⇒ Object
747
748
749
|
# File 'app/models/group.rb', line 747
def project_creation_level
super || ::Gitlab::CurrentSettings.default_project_creation
end
|
#project_users_with_descendants ⇒ Object
Returns all users that are members of projects belonging to the current group or sub-groups
678
679
680
681
682
683
|
# File 'app/models/group.rb', line 678
def project_users_with_descendants
User
.joins(projects: :group)
.where(namespaces: { id: self_and_descendants.select(:id) })
.allow_cross_joins_across_databases(url: "https://gitlab.com/gitlab-org/gitlab/-/issues/417455")
end
|
#readme_project ⇒ Object
935
936
937
|
# File 'app/models/group.rb', line 935
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
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
|
# File 'app/models/group.rb', line 543
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_authorizations ⇒ Object
736
737
738
|
# File 'app/models/group.rb', line 736
def refresh_project_authorizations
refresh_members_authorized_projects
end
|
726
727
728
729
730
|
# File 'app/models/group.rb', line 726
def related_group_ids
[id,
*ancestors.pluck(:id),
*shared_with_group_links.pluck(:shared_with_group_id)]
end
|
#runners_token ⇒ Object
each existing group needs to have a ‘runners_token`. we do this on read since migrating all existing groups is not a feasible solution.
743
744
745
|
# File 'app/models/group.rb', line 743
def runners_token
ensure_runners_token!
end
|
#self_and_ancestors_ids ⇒ Object
573
574
575
576
577
|
# File 'app/models/group.rb', line 573
def self_and_ancestors_ids
strong_memoize(:self_and_ancestors_ids) do
self_and_ancestors.pluck(:id)
end
end
|
#self_and_descendants_ids ⇒ Object
579
580
581
582
583
|
# File 'app/models/group.rb', line 579
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
568
569
570
571
|
# File 'app/models/group.rb', line 568
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
|
#shared_with_group_links_visible_to_user(user) ⇒ Object
867
868
869
|
# File 'app/models/group.rb', line 867
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_level ⇒ Object
#supports_events? ⇒ Boolean
763
764
765
|
# File 'app/models/group.rb', line 763
def supports_events?
false
end
|
#supports_lock_on_merge? ⇒ Boolean
902
903
904
|
# File 'app/models/group.rb', line 902
def supports_lock_on_merge?
feature_flag_enabled_for_self_or_ancestor?(:enforce_locked_labels_on_merge, type: :ops)
end
|
#system_hook_service ⇒ Object
rubocop: disable CodeReuse/ServiceClass
537
538
539
|
# File 'app/models/group.rb', line 537
def system_hook_service
SystemHooksService.new
end
|
#timelogs ⇒ Object
rubocop: enable CodeReuse/ServiceClass
847
848
849
|
# File 'app/models/group.rb', line 847
def timelogs
Timelog.in_group(self)
end
|
#update_two_factor_requirement_for_members ⇒ Object
931
932
933
|
# File 'app/models/group.rb', line 931
def update_two_factor_requirement_for_members
hierarchy_members.find_each(&:update_two_factor_requirement)
end
|
#usage_quotas_enabled? ⇒ Boolean
906
907
908
|
# File 'app/models/group.rb', line 906
def usage_quotas_enabled?
::Feature.enabled?(:usage_quotas_for_all_editions, self) && root?
end
|
#user_ids_for_project_authorizations ⇒ Object
564
565
566
|
# File 'app/models/group.rb', line 564
def user_ids_for_project_authorizations
members_with_parents.pluck(Arel.sql('DISTINCT members.user_id'))
end
|
#users_count ⇒ Object
672
673
674
|
# File 'app/models/group.rb', line 672
def users_count
members.count
end
|
#users_ids_of_direct_members ⇒ Object
rubocop: enable CodeReuse/ServiceClass
560
561
562
|
# File 'app/models/group.rb', line 560
def users_ids_of_direct_members
direct_members.pluck_user_ids
end
|
#users_with_descendants ⇒ Object
666
667
668
669
670
|
# File 'app/models/group.rb', line 666
def users_with_descendants
User
.where(id: members_with_descendants.select(:user_id))
.reorder(nil)
end
|
#users_with_parents ⇒ Object
660
661
662
663
664
|
# File 'app/models/group.rb', line 660
def users_with_parents
User
.where(id: members_with_parents.select(:user_id))
.reorder(nil)
end
|
#visibility_level_allowed?(level = self.visibility_level) ⇒ Boolean
409
410
411
412
413
|
# File 'app/models/group.rb', line 409
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
395
396
397
398
399
|
# File 'app/models/group.rb', line 395
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
401
402
403
|
# File 'app/models/group.rb', line 401
def visibility_level_allowed_by_projects?(level = self.visibility_level)
!projects.without_deleted.where('visibility_level > ?', level).exists?
end
|
#visibility_level_allowed_by_sub_groups?(level = self.visibility_level) ⇒ Boolean
405
406
407
|
# File 'app/models/group.rb', line 405
def visibility_level_allowed_by_sub_groups?(level = self.visibility_level)
!children.where('visibility_level > ?', level).exists?
end
|
#web_url(only_path: nil) ⇒ Object
378
379
380
|
# File 'app/models/group.rb', line 378
def web_url(only_path: nil)
Gitlab::UrlBuilder.build(self, only_path: only_path)
end
|
#work_items_feature_flag_enabled? ⇒ Boolean
886
887
888
|
# File 'app/models/group.rb', line 886
def work_items_feature_flag_enabled?
feature_flag_enabled_for_self_or_ancestor?(:work_items)
end
|
#work_items_mvc_2_feature_flag_enabled? ⇒ Boolean
894
895
896
|
# File 'app/models/group.rb', line 894
def work_items_mvc_2_feature_flag_enabled?
feature_flag_enabled_for_self_or_ancestor?(:work_items_mvc_2)
end
|
#work_items_mvc_feature_flag_enabled? ⇒ Boolean
890
891
892
|
# File 'app/models/group.rb', line 890
def work_items_mvc_feature_flag_enabled?
feature_flag_enabled_for_self_or_ancestor?(:work_items_mvc)
end
|