debian-mirror-gitlab/app/models/namespace.rb

765 lines
25 KiB
Ruby
Raw Normal View History

2018-11-18 11:00:15 +05:30
# frozen_string_literal: true
2019-03-02 22:35:43 +05:30
class Namespace < ApplicationRecord
2016-11-03 12:29:30 +05:30
include CacheMarkdownField
2015-04-26 12:48:37 +05:30
include Sortable
2017-09-10 17:25:29 +05:30
include Gitlab::VisibilityLevel
2017-08-17 22:00:37 +05:30
include Routable
2017-09-10 17:25:29 +05:30
include AfterCommitQueue
include Storage::LegacyNamespace
2018-03-17 18:26:18 +05:30
include Gitlab::SQL::Pattern
2018-11-20 20:47:30 +05:30
include FeatureGate
2018-12-05 23:21:45 +05:30
include FromUnion
2019-07-07 11:18:12 +05:30
include Gitlab::Utils::StrongMemoize
2020-04-22 19:07:51 +05:30
include IgnorableColumns
2021-03-11 19:13:27 +05:30
include Namespaces::Traversal::Recursive
2021-04-29 21:17:54 +05:30
include Namespaces::Traversal::Linear
2021-06-08 01:23:25 +05:30
include EachBatch
2022-06-21 17:19:12 +05:30
include BlocksUnsafeSerialization
2022-07-16 23:28:13 +05:30
include Ci::NamespaceSettings
2021-04-29 21:17:54 +05:30
2021-12-11 22:18:48 +05:30
# Temporary column used for back-filling project namespaces.
# Remove it once the back-filling of all project namespaces is done.
ignore_column :tmp_project_id, remove_with: '14.7', remove_after: '2022-01-22'
2020-04-22 19:07:51 +05:30
2021-12-11 22:18:48 +05:30
# Tells ActiveRecord not to store the full class name, in order to save some space
2021-11-11 11:23:49 +05:30
# https://gitlab.com/gitlab-org/gitlab/-/merge_requests/69794
self.store_full_sti_class = false
self.store_full_class_name = false
2017-08-17 22:00:37 +05:30
# Prevent users from creating unreasonably deep level of nesting.
# The number 20 was taken based on maximum nesting level of
# Android repo (15) + some extra backup.
NUMBER_OF_ANCESTORS_ALLOWED = 20
2014-09-02 18:07:02 +05:30
2021-11-18 22:05:49 +05:30
SR_DISABLED_AND_UNOVERRIDABLE = 'disabled_and_unoverridable'
SR_DISABLED_WITH_OVERRIDE = 'disabled_with_override'
SR_ENABLED = 'enabled'
SHARED_RUNNERS_SETTINGS = [SR_DISABLED_AND_UNOVERRIDABLE, SR_DISABLED_WITH_OVERRIDE, SR_ENABLED].freeze
2021-10-27 15:23:28 +05:30
URL_MAX_LENGTH = 255
2021-01-03 14:25:43 +05:30
2021-10-29 20:43:33 +05:30
PATH_TRAILING_VIOLATIONS = %w[.git .atom .].freeze
2023-01-13 00:05:48 +05:30
# This date is just a placeholder until namespace storage enforcement timeline is confirmed at which point
# this should be replaced, see https://about.gitlab.com/pricing/faq-efficient-free-tier/#user-limits-on-gitlab-saas-free-tier
MIN_STORAGE_ENFORCEMENT_DATE = 3.months.from_now.to_date
2022-10-11 01:57:18 +05:30
# https://gitlab.com/gitlab-org/gitlab/-/issues/367531
MIN_STORAGE_ENFORCEMENT_USAGE = 5.gigabytes
2022-08-27 11:52:29 +05:30
2016-11-03 12:29:30 +05:30
cache_markdown_field :description, pipeline: :description
2017-09-10 17:25:29 +05:30
has_many :projects, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
2017-08-17 22:00:37 +05:30
has_many :project_statistics
2020-07-28 23:09:34 +05:30
has_one :namespace_settings, inverse_of: :namespace, class_name: 'NamespaceSetting', autosave: true
2022-07-16 23:28:13 +05:30
has_one :ci_cd_settings, inverse_of: :namespace, class_name: 'NamespaceCiCdSetting', autosave: true
2022-08-27 11:52:29 +05:30
has_one :namespace_details, inverse_of: :namespace, class_name: 'Namespace::Detail', autosave: true
2022-04-04 11:22:00 +05:30
has_one :namespace_statistics
2022-03-02 08:16:31 +05:30
has_one :namespace_route, foreign_key: :namespace_id, autosave: false, inverse_of: :namespace, class_name: 'Route'
has_many :namespace_members, foreign_key: :member_namespace_id, inverse_of: :member_namespace, class_name: 'Member'
2022-08-27 11:52:29 +05:30
has_many :member_roles
2018-03-17 18:26:18 +05:30
2018-11-08 19:23:39 +05:30
has_many :runner_namespaces, inverse_of: :namespace, class_name: 'Ci::RunnerNamespace'
2018-10-15 14:42:47 +05:30
has_many :runners, through: :runner_namespaces, source: :runner, class_name: 'Ci::Runner'
2021-10-27 15:23:28 +05:30
has_many :pending_builds, class_name: 'Ci::PendingBuild'
2022-10-11 01:57:18 +05:30
has_one :onboarding_progress, class_name: 'Onboarding::Progress'
2018-10-15 14:42:47 +05:30
2018-03-17 18:26:18 +05:30
# This should _not_ be `inverse_of: :namespace`, because that would also set
# `user.namespace` when this user creates a group with themselves as `owner`.
2022-01-26 12:08:38 +05:30
belongs_to :owner, class_name: 'User'
2014-09-02 18:07:02 +05:30
2017-08-17 22:00:37 +05:30
belongs_to :parent, class_name: "Namespace"
2021-12-11 22:18:48 +05:30
has_many :children, -> { where(type: Group.sti_name) }, class_name: "Namespace", foreign_key: :parent_id
2020-07-28 23:09:34 +05:30
has_many :custom_emoji, inverse_of: :namespace
2017-09-10 17:25:29 +05:30
has_one :chat_team, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
2019-09-30 21:07:59 +05:30
has_one :root_storage_statistics, class_name: 'Namespace::RootStorageStatistics'
has_one :aggregation_schedule, class_name: 'Namespace::AggregationSchedule'
2021-03-08 18:12:59 +05:30
has_one :package_setting_relation, inverse_of: :namespace, class_name: 'PackageSetting'
2017-08-17 22:00:37 +05:30
2021-04-29 21:17:54 +05:30
has_one :admin_note, inverse_of: :namespace
accepts_nested_attributes_for :admin_note, update_only: true
2022-01-26 12:08:38 +05:30
has_one :ci_namespace_mirror, class_name: 'Ci::NamespaceMirror'
has_many :sync_events, class_name: 'Namespaces::SyncEvent'
2022-07-23 23:45:48 +05:30
has_one :cluster_enabled_grant, inverse_of: :namespace, class_name: 'Clusters::ClusterEnabledGrant'
2022-08-13 15:12:31 +05:30
has_many :work_items, inverse_of: :namespace
has_many :issues, inverse_of: :namespace
2022-07-23 23:45:48 +05:30
2022-08-27 11:52:29 +05:30
has_many :timelog_categories, class_name: 'TimeTracking::TimelogCategory'
2023-03-04 22:38:38 +05:30
has_many :achievements, class_name: 'Achievements::Achievement'
2022-08-27 11:52:29 +05:30
2021-11-11 11:23:49 +05:30
validates :owner, presence: true, if: ->(n) { n.owner_required? }
2015-04-26 12:48:37 +05:30
validates :name,
2015-12-23 02:04:40 +05:30
presence: true,
2019-09-30 21:07:59 +05:30
length: { maximum: 255 }
2023-01-13 00:05:48 +05:30
validates :name, uniqueness: { scope: [:type, :parent_id] }, if: -> { parent_id.present? }
2015-04-26 12:48:37 +05:30
2017-08-17 22:00:37 +05:30
validates :description, length: { maximum: 255 }
2021-11-18 22:05:49 +05:30
2015-04-26 12:48:37 +05:30
validates :path,
2015-12-23 02:04:40 +05:30
presence: true,
2021-11-18 22:05:49 +05:30
length: { maximum: URL_MAX_LENGTH }
validates :path, namespace_path: true, if: ->(n) { !n.project_namespace? }
# Project path validator is used for project namespaces for now to assure
# compatibility with project paths
# Issue: https://gitlab.com/gitlab-org/gitlab/-/issues/341764
validates :path, project_path: true, if: ->(n) { n.project_namespace? }
2017-08-17 22:00:37 +05:30
2020-07-28 23:09:34 +05:30
# Introduce minimal path length of 2 characters.
# Allow change of other attributes without forcing users to
# rename their user or group. At the same time prevent changing
# the path without complying with new 2 chars requirement.
# Issue https://gitlab.com/gitlab-org/gitlab/-/issues/225214
2021-11-18 22:05:49 +05:30
#
# For ProjectNamespace we don't check minimal path length to keep
# compatibility with existing project restrictions.
# Issue: https://gitlab.com/gitlab-org/gitlab/-/issues/341764
validates :path, length: { minimum: 2 }, if: :enforce_minimum_path_length?
2020-07-28 23:09:34 +05:30
2020-03-13 15:44:24 +05:30
validates :max_artifacts_size, numericality: { only_integer: true, greater_than: 0, allow_nil: true }
2022-01-26 12:08:38 +05:30
validate :validate_parent_type
2021-12-11 22:18:48 +05:30
# ProjectNamespaces excluded as they are not meant to appear in the group hierarchy at the moment.
validate :nesting_level_allowed, unless: -> { project_namespace? }
validate :changing_shared_runners_enabled_is_allowed, unless: -> { project_namespace? }
validate :changing_allow_descendants_override_disabled_shared_runners_is_allowed, unless: -> { project_namespace? }
2014-09-02 18:07:02 +05:30
delegate :name, to: :owner, allow_nil: true, prefix: true
2019-07-31 22:56:46 +05:30
delegate :avatar_url, to: :owner, allow_nil: true
2022-07-16 23:28:13 +05:30
delegate :prevent_sharing_groups_outside_hierarchy, :prevent_sharing_groups_outside_hierarchy=,
to: :namespace_settings, allow_nil: true
2022-10-11 01:57:18 +05:30
delegate :show_diff_preview_in_email, :show_diff_preview_in_email?, :show_diff_preview_in_email=,
to: :namespace_settings
2023-03-04 22:38:38 +05:30
delegate :runner_registration_enabled, :runner_registration_enabled?, :runner_registration_enabled=,
to: :namespace_settings
2022-11-25 23:54:43 +05:30
delegate :maven_package_requests_forwarding,
:pypi_package_requests_forwarding,
:npm_package_requests_forwarding,
to: :package_settings
2014-09-02 18:07:02 +05:30
2018-03-17 18:26:18 +05:30
before_create :sync_share_with_group_lock_with_parent
before_update :sync_share_with_group_lock_with_parent, if: :parent_changed?
2019-07-31 22:56:46 +05:30
after_update :force_share_with_group_lock_on_descendants, if: -> { saved_change_to_share_with_group_lock? && share_with_group_lock? }
2022-05-07 20:08:51 +05:30
after_update :expire_first_auto_devops_config_cache, if: -> { saved_change_to_auto_devops_enabled? }
2023-03-04 22:38:38 +05:30
after_update :move_dir, if: :saved_change_to_path_or_parent?, unless: -> { is_a?(Namespaces::ProjectNamespace) }
after_destroy :rm_dir
after_save :reload_namespace_details
after_commit :refresh_access_of_projects_invited_groups, on: :update, if: -> { previous_changes.key?('share_with_group_lock') }
2022-10-11 01:57:18 +05:30
after_sync_traversal_ids :schedule_sync_event_worker # custom callback defined in Namespaces::Traversal::Linear
2018-03-17 18:26:18 +05:30
2017-09-10 17:25:29 +05:30
# Legacy Storage specific hooks
2017-08-17 22:00:37 +05:30
before_destroy(prepend: true) { prepare_for_destroy }
2021-06-08 01:23:25 +05:30
after_commit :expire_child_caches, on: :update, if: -> {
2022-07-16 23:28:13 +05:30
Feature.enabled?(:cached_route_lookups, self, type: :ops) &&
2021-06-08 01:23:25 +05:30
saved_change_to_name? || saved_change_to_path? || saved_change_to_parent_id?
}
2014-09-02 18:07:02 +05:30
2022-01-26 12:08:38 +05:30
scope :user_namespaces, -> { where(type: Namespaces::UserNamespace.sti_name) }
scope :without_project_namespaces, -> { where(Namespace.arel_table[:type].not_eq(Namespaces::ProjectNamespace.sti_name)) }
2022-06-21 17:19:12 +05:30
scope :sort_by_type, -> { order(arel_table[:type].asc.nulls_first) }
2021-01-03 14:25:43 +05:30
scope :include_route, -> { includes(:route) }
2021-04-29 21:17:54 +05:30
scope :by_parent, -> (parent) { where(parent_id: parent) }
scope :filter_by_path, -> (query) { where('lower(path) = :query', query: query.downcase) }
2017-08-17 22:00:37 +05:30
scope :with_statistics, -> do
joins('LEFT JOIN project_statistics ps ON ps.namespace_id = namespaces.id')
.group('namespaces.id')
.select(
'namespaces.*',
'COALESCE(SUM(ps.storage_size), 0) AS storage_size',
'COALESCE(SUM(ps.repository_size), 0) AS repository_size',
2019-09-04 21:01:54 +05:30
'COALESCE(SUM(ps.wiki_size), 0) AS wiki_size',
2020-07-28 23:09:34 +05:30
'COALESCE(SUM(ps.snippets_size), 0) AS snippets_size',
2017-08-17 22:00:37 +05:30
'COALESCE(SUM(ps.lfs_objects_size), 0) AS lfs_objects_size',
2019-07-31 22:56:46 +05:30
'COALESCE(SUM(ps.build_artifacts_size), 0) AS build_artifacts_size',
2021-12-11 22:18:48 +05:30
'COALESCE(SUM(ps.pipeline_artifacts_size), 0) AS pipeline_artifacts_size',
2021-01-29 00:20:46 +05:30
'COALESCE(SUM(ps.packages_size), 0) AS packages_size',
'COALESCE(SUM(ps.uploads_size), 0) AS uploads_size'
2017-08-17 22:00:37 +05:30
)
end
2014-09-02 18:07:02 +05:30
2021-09-30 23:02:18 +05:30
scope :sorted_by_similarity_and_parent_id_desc, -> (search) do
2022-10-11 01:57:18 +05:30
order_expression = Gitlab::Database::SimilarityScore.build_expression(
search: search,
rules: [
{ column: arel_table["path"], multiplier: 1 },
{ column: arel_table["name"], multiplier: 0.7 }
])
2021-09-30 23:02:18 +05:30
reorder(order_expression.desc, Namespace.arel_table['parent_id'].desc.nulls_last, Namespace.arel_table['id'].desc)
end
2022-10-11 01:57:18 +05:30
scope :with_shared_runners_enabled, -> { where(shared_runners_enabled: true) }
2021-03-11 19:13:27 +05:30
# Make sure that the name is same as strong_memoize name in root_ancestor
# method
2021-04-29 21:17:54 +05:30
attr_writer :root_ancestor, :emails_disabled_memoized
2021-03-11 19:13:27 +05:30
2015-04-26 12:48:37 +05:30
class << self
2021-11-11 11:23:49 +05:30
def sti_class_for(type_name)
case type_name
2021-11-18 22:05:49 +05:30
when Group.sti_name
2021-11-11 11:23:49 +05:30
Group
2021-11-18 22:05:49 +05:30
when Namespaces::ProjectNamespace.sti_name
2021-11-11 11:23:49 +05:30
Namespaces::ProjectNamespace
2021-11-18 22:05:49 +05:30
when Namespaces::UserNamespace.sti_name
Namespaces::UserNamespace
2021-11-11 11:23:49 +05:30
else
Namespace
end
end
2015-04-26 12:48:37 +05:30
def by_path(path)
2015-12-23 02:04:40 +05:30
find_by('lower(path) = :value', value: path.downcase)
2015-04-26 12:48:37 +05:30
end
2018-12-13 13:39:08 +05:30
# Case insensitive search for namespace by path or name
2015-04-26 12:48:37 +05:30
def find_by_path_or_name(path)
find_by("lower(path) = :path OR lower(name) = :path", path: path.downcase)
end
2016-06-02 11:05:42 +05:30
# Searches for namespaces matching the given query.
#
2020-06-23 00:09:42 +05:30
# This method uses ILIKE on PostgreSQL.
2016-06-02 11:05:42 +05:30
#
2020-06-23 00:09:42 +05:30
# query - The search query as a String.
2016-06-02 11:05:42 +05:30
#
2020-06-23 00:09:42 +05:30
# Returns an ActiveRecord::Relation.
2021-01-29 00:20:46 +05:30
def search(query, include_parents: false)
if include_parents
2021-12-11 22:18:48 +05:30
without_project_namespaces.where(id: Route.for_routable_type(Namespace.name).fuzzy_search(query, [Route.arel_table[:path], Route.arel_table[:name]]).select(:source_id))
2021-01-29 00:20:46 +05:30
else
2021-12-11 22:18:48 +05:30
without_project_namespaces.fuzzy_search(query, [:path, :name])
2021-01-29 00:20:46 +05:30
end
2015-04-26 12:48:37 +05:30
end
2014-09-02 18:07:02 +05:30
2022-07-23 23:45:48 +05:30
def clean_path(path, limited_to: Namespace.all)
2015-04-26 12:48:37 +05:30
path = path.dup
2015-09-11 14:41:01 +05:30
# Get the email username by removing everything after an `@` sign.
2016-11-03 12:29:30 +05:30
path.gsub!(/@.*\z/, "")
2015-09-11 14:41:01 +05:30
# Remove everything that's not in the list of allowed characters.
2016-11-03 12:29:30 +05:30
path.gsub!(/[^a-zA-Z0-9_\-\.]/, "")
# Remove trailing violations ('.atom', '.git', or '.')
2021-10-29 20:43:33 +05:30
loop do
orig = path
PATH_TRAILING_VIOLATIONS.each { |ext| path = path.chomp(ext) }
break if orig == path
end
2016-11-03 12:29:30 +05:30
# Remove leading violations ('-')
2021-10-29 20:43:33 +05:30
path.gsub!(/\A\-+/, "")
2015-04-26 12:48:37 +05:30
2015-09-11 14:41:01 +05:30
# Users with the great usernames of "." or ".." would end up with a blank username.
# Work around that by setting their username to "blank", followed by a counter.
path = "blank" if path.blank?
2017-08-17 22:00:37 +05:30
uniquify = Uniquify.new
2022-07-23 23:45:48 +05:30
uniquify.string(path) { |s| limited_to.find_by_path_or_name(s) }
2015-04-26 12:48:37 +05:30
end
2019-12-21 20:55:43 +05:30
2020-11-24 15:15:51 +05:30
def clean_name(value)
value.scan(Gitlab::Regex.group_name_regex_chars).join(' ')
end
2019-12-21 20:55:43 +05:30
def find_by_pages_host(host)
gitlab_host = "." + Settings.pages.host.downcase
2020-01-01 13:55:28 +05:30
host = host.downcase
return unless host.ends_with?(gitlab_host)
2019-12-21 20:55:43 +05:30
2020-01-01 13:55:28 +05:30
name = host.delete_suffix(gitlab_host)
2022-07-16 23:28:13 +05:30
Namespace.top_most.by_path(name)
2019-12-21 20:55:43 +05:30
end
2021-04-17 20:07:23 +05:30
def top_most
2022-07-16 23:28:13 +05:30
by_parent(nil)
2021-04-17 20:07:23 +05:30
end
2014-09-02 18:07:02 +05:30
end
2021-03-08 18:12:59 +05:30
def package_settings
package_setting_relation || build_package_setting_relation
end
2020-04-08 14:13:33 +05:30
def default_branch_protection
super || Gitlab::CurrentSettings.default_branch_protection
end
2017-09-10 17:25:29 +05:30
def visibility_level_field
:visibility_level
end
2014-09-02 18:07:02 +05:30
def to_param
2017-08-17 22:00:37 +05:30
full_path
2014-09-02 18:07:02 +05:30
end
def human_name
owner_name
end
2016-06-02 11:05:42 +05:30
def any_project_has_container_registry_tags?
2021-06-08 01:23:25 +05:30
all_projects.includes(:container_repositories).any?(&:has_container_registry_tags?)
2016-06-02 11:05:42 +05:30
end
2018-12-05 23:21:45 +05:30
def first_project_with_container_registry_tags
all_projects.find(&:has_container_registry_tags?)
end
2014-09-02 18:07:02 +05:30
def send_update_instructions
2015-10-24 18:46:33 +05:30
projects.each do |project|
2019-07-31 22:56:46 +05:30
project.send_move_instructions("#{full_path_before_last_save}/#{project.path}")
2015-10-24 18:46:33 +05:30
end
2014-09-02 18:07:02 +05:30
end
def kind
2021-11-18 22:05:49 +05:30
return 'group' if group_namespace?
return 'project' if project_namespace?
2021-11-11 11:23:49 +05:30
'user' # defaults to user
end
2021-11-18 22:05:49 +05:30
def group_namespace?
2021-11-11 11:23:49 +05:30
type == Group.sti_name
end
2021-11-18 22:05:49 +05:30
def project_namespace?
2021-11-11 11:23:49 +05:30
type == Namespaces::ProjectNamespace.sti_name
2014-09-02 18:07:02 +05:30
end
2015-04-26 12:48:37 +05:30
2021-11-18 22:05:49 +05:30
def user_namespace?
2021-11-11 11:23:49 +05:30
# That last bit ensures we're considered a user namespace as a default
2021-11-18 22:05:49 +05:30
type.nil? || type == Namespaces::UserNamespace.sti_name || !(group_namespace? || project_namespace?)
2019-07-31 22:56:46 +05:30
end
2023-03-04 22:38:38 +05:30
def bot_user_namespace?
return false unless user_namespace?
return false unless owner && owner.bot?
true
end
2021-11-11 11:23:49 +05:30
def owner_required?
2021-11-18 22:05:49 +05:30
user_namespace?
2020-05-24 23:13:21 +05:30
end
2022-03-02 08:16:31 +05:30
def first_owner
owner
end
2015-04-26 12:48:37 +05:30
def find_fork_of(project)
2019-07-07 11:18:12 +05:30
return unless project.fork_network
2018-03-17 18:26:18 +05:30
2018-12-05 23:21:45 +05:30
if Gitlab::SafeRequestStore.active?
forks_in_namespace = Gitlab::SafeRequestStore.fetch("namespaces:#{id}:forked_projects") do
2018-03-17 18:26:18 +05:30
Hash.new do |found_forks, project|
found_forks[project] = project.fork_network.find_forks_in(projects).first
end
end
forks_in_namespace[project]
else
project.fork_network.find_forks_in(projects).first
end
2015-04-26 12:48:37 +05:30
end
2016-08-24 12:49:21 +05:30
2019-10-12 21:52:04 +05:30
# any ancestor can disable emails for all descendants
def emails_disabled?
2021-04-29 21:17:54 +05:30
strong_memoize(:emails_disabled_memoized) do
2020-03-13 15:44:24 +05:30
if parent_id
self_and_ancestors.where(emails_disabled: true).exists?
else
!!emails_disabled
end
2019-10-12 21:52:04 +05:30
end
end
2022-08-13 15:12:31 +05:30
def emails_enabled?
!emails_disabled?
end
2016-09-29 09:46:39 +05:30
def lfs_enabled?
# User namespace will always default to the global setting
Gitlab.config.lfs.enabled
end
2020-07-28 23:09:34 +05:30
def any_project_with_shared_runners_enabled?
2022-10-11 01:57:18 +05:30
projects.with_shared_runners_enabled.any?
2017-08-17 22:00:37 +05:30
end
def user_ids_for_project_authorizations
[owner_id]
end
# Includes projects from this namespace and projects from all subgroups
# that belongs to this namespace
def all_projects
2022-07-16 23:28:13 +05:30
if Feature.enabled?(:recursive_approach_for_all_projects)
2021-11-18 22:05:49 +05:30
namespace = user_namespace? ? self : self_and_descendant_ids
2021-07-08 21:50:14 +05:30
Project.where(namespace: namespace)
else
Project.inside_path(full_path)
end
2017-08-17 22:00:37 +05:30
end
def has_parent?
2020-06-23 00:09:42 +05:30
parent_id.present? || parent.present?
2017-08-17 22:00:37 +05:30
end
2018-03-17 18:26:18 +05:30
def subgroup?
has_parent?
end
2018-03-27 19:54:05 +05:30
# Overridden on EE module
def multiple_issue_boards_available?
false
end
2022-07-16 23:28:13 +05:30
def all_project_ids_except(ids)
all_projects.where.not(id: ids).pluck(:id)
end
2021-04-29 21:17:54 +05:30
# Deprecated, use #licensed_feature_available? instead. Remove once Namespace#feature_available? isn't used anymore.
2022-06-21 17:19:12 +05:30
def feature_available?(feature, _user = nil)
2021-04-29 21:17:54 +05:30
licensed_feature_available?(feature)
end
2019-09-30 21:07:59 +05:30
# Overridden in EE::Namespace
2021-04-29 21:17:54 +05:30
def licensed_feature_available?(_feature)
2019-09-30 21:07:59 +05:30
false
end
2019-07-31 22:56:46 +05:30
def full_path_before_last_save
if parent_id_before_last_save.nil?
path_before_last_save
2018-03-17 18:26:18 +05:30
else
2019-07-31 22:56:46 +05:30
previous_parent = Group.find_by(id: parent_id_before_last_save)
previous_parent.full_path + '/' + path_before_last_save
2018-03-17 18:26:18 +05:30
end
end
2018-05-09 12:01:36 +05:30
def refresh_project_authorizations
owner.refresh_authorized_projects
end
2019-07-07 11:18:12 +05:30
def auto_devops_enabled?
first_auto_devops_config[:status]
end
def first_auto_devops_config
return { scope: :group, status: auto_devops_enabled } unless auto_devops_enabled.nil?
strong_memoize(:first_auto_devops_config) do
2022-07-23 23:45:48 +05:30
if has_parent?
2022-05-07 20:08:51 +05:30
Rails.cache.fetch(first_auto_devops_config_cache_key_for(id), expires_in: 1.day) do
parent.first_auto_devops_config
end
2019-07-07 11:18:12 +05:30
else
{ scope: :instance, status: Gitlab::CurrentSettings.auto_devops_enabled? }
end
end
end
2019-09-30 21:07:59 +05:30
def aggregation_scheduled?
aggregation_schedule.present?
end
2022-07-23 23:45:48 +05:30
def container_repositories_size_cache_key
"namespaces:#{id}:container_repositories_size"
end
def container_repositories_size
strong_memoize(:container_repositories_size) do
next unless Gitlab.com?
next unless root?
next unless ContainerRegistry::GitlabApiClient.supports_gitlab_api?
next 0 if all_container_repositories.empty?
next unless all_container_repositories.all_migrated?
Rails.cache.fetch(container_repositories_size_cache_key, expires_in: 7.days) do
ContainerRegistry::GitlabApiClient.deduplicated_size(full_path)
end
end
end
def all_container_repositories
ContainerRepository.for_project_id(all_projects)
end
2019-12-21 20:55:43 +05:30
def pages_virtual_domain
2022-08-13 15:12:31 +05:30
cache = if Feature.enabled?(:cache_pages_domain_api, root_ancestor)
::Gitlab::Pages::CacheControl.for_namespace(root_ancestor.id)
end
2020-04-08 14:13:33 +05:30
Pages::VirtualDomain.new(
2022-08-13 15:12:31 +05:30
projects: all_projects_with_pages.includes(:route, :project_feature, pages_metadatum: :pages_deployment),
trim_prefix: full_path,
cache: cache
2020-04-08 14:13:33 +05:30
)
2019-12-21 20:55:43 +05:30
end
2020-11-24 15:15:51 +05:30
def any_project_with_pages_deployed?
all_projects.with_pages_deployed.any?
end
2019-12-21 20:55:43 +05:30
def closest_setting(name)
self_and_ancestors(hierarchy_order: :asc)
.find { |n| !n.read_attribute(name).nil? }
.try(name)
end
2020-05-24 23:13:21 +05:30
def actual_plan
Plan.default
end
2021-04-29 21:17:54 +05:30
def paid?
root? && actual_plan.paid?
end
2023-03-04 22:38:38 +05:30
def prevent_delete?
paid?
end
2020-05-24 23:13:21 +05:30
def actual_limits
# We default to PlanLimits.new otherwise a lot of specs would fail
# On production each plan should already have associated limits record
# https://gitlab.com/gitlab-org/gitlab/issues/36037
actual_plan.actual_limits
end
def actual_plan_name
actual_plan.name
end
2021-01-03 14:25:43 +05:30
def changing_shared_runners_enabled_is_allowed
return unless new_record? || changes.has_key?(:shared_runners_enabled)
2021-11-18 22:05:49 +05:30
if shared_runners_enabled && has_parent? && parent.shared_runners_setting == SR_DISABLED_AND_UNOVERRIDABLE
2021-01-03 14:25:43 +05:30
errors.add(:shared_runners_enabled, _('cannot be enabled because parent group has shared Runners disabled'))
end
end
def changing_allow_descendants_override_disabled_shared_runners_is_allowed
return unless new_record? || changes.has_key?(:allow_descendants_override_disabled_shared_runners)
if shared_runners_enabled && !new_record?
errors.add(:allow_descendants_override_disabled_shared_runners, _('cannot be changed if shared runners are enabled'))
end
2021-11-18 22:05:49 +05:30
if allow_descendants_override_disabled_shared_runners && has_parent? && parent.shared_runners_setting == SR_DISABLED_AND_UNOVERRIDABLE
2021-01-03 14:25:43 +05:30
errors.add(:allow_descendants_override_disabled_shared_runners, _('cannot be enabled because parent group does not allow it'))
end
end
def shared_runners_setting
if shared_runners_enabled
2021-11-18 22:05:49 +05:30
SR_ENABLED
2023-03-04 22:38:38 +05:30
elsif allow_descendants_override_disabled_shared_runners
SR_DISABLED_WITH_OVERRIDE
2021-01-03 14:25:43 +05:30
else
2023-03-04 22:38:38 +05:30
SR_DISABLED_AND_UNOVERRIDABLE
2021-01-03 14:25:43 +05:30
end
end
def shared_runners_setting_higher_than?(other_setting)
2023-01-13 00:05:48 +05:30
case other_setting
when SR_ENABLED
2021-01-03 14:25:43 +05:30
false
2023-01-13 00:05:48 +05:30
when SR_DISABLED_WITH_OVERRIDE
2021-11-18 22:05:49 +05:30
shared_runners_setting == SR_ENABLED
2023-01-13 00:05:48 +05:30
when SR_DISABLED_AND_UNOVERRIDABLE
2021-11-18 22:05:49 +05:30
shared_runners_setting == SR_ENABLED || shared_runners_setting == SR_DISABLED_WITH_OVERRIDE
2021-01-03 14:25:43 +05:30
else
raise ArgumentError
end
end
2022-04-04 11:22:00 +05:30
def shared_runners
@shared_runners ||= shared_runners_enabled ? Ci::Runner.instance_type : Ci::Runner.none
end
2021-03-08 18:12:59 +05:30
def root?
!has_parent?
end
2021-04-17 20:07:23 +05:30
def recent?
created_at >= 90.days.ago
end
2021-06-08 01:23:25 +05:30
def issue_repositioning_disabled?
2022-07-16 23:28:13 +05:30
Feature.enabled?(:block_issue_repositioning, self, type: :ops)
2021-06-08 01:23:25 +05:30
end
2022-04-04 11:22:00 +05:30
def storage_enforcement_date
2022-07-23 23:45:48 +05:30
return Date.current if Feature.enabled?(:namespace_storage_limit_bypass_date_check, self)
2022-08-27 11:52:29 +05:30
MIN_STORAGE_ENFORCEMENT_DATE
2022-04-04 11:22:00 +05:30
end
2022-07-16 23:28:13 +05:30
def certificate_based_clusters_enabled?
2022-07-23 23:45:48 +05:30
cluster_enabled_granted? || certificate_based_clusters_enabled_ff?
end
def enabled_git_access_protocol
# If the instance-level setting is enabled, we defer to that
return ::Gitlab::CurrentSettings.enabled_git_access_protocol unless ::Gitlab::CurrentSettings.enabled_git_access_protocol.blank?
# Otherwise we use the stored setting on the group
namespace_settings&.enabled_git_access_protocol
2022-07-16 23:28:13 +05:30
end
2023-03-04 22:38:38 +05:30
def all_ancestors_have_runner_registration_enabled?
namespace_settings&.all_ancestors_have_runner_registration_enabled?
end
2017-09-10 17:25:29 +05:30
private
2017-08-17 22:00:37 +05:30
2022-07-23 23:45:48 +05:30
def cluster_enabled_granted?
(Gitlab.com? || Gitlab.dev_or_test_env?) && root_ancestor.cluster_enabled_grant.present?
end
def certificate_based_clusters_enabled_ff?
Feature.enabled?(:certificate_based_clusters, type: :ops)
end
2021-06-08 01:23:25 +05:30
def expire_child_caches
Namespace.where(id: descendants).each_batch do |namespaces|
namespaces.touch_all
end
all_projects.each_batch do |projects|
projects.touch_all
end
end
2019-12-21 20:55:43 +05:30
def all_projects_with_pages
all_projects.with_pages_deployed
end
2019-07-31 22:56:46 +05:30
def parent_changed?
parent_id_changed?
end
def saved_change_to_parent?
saved_change_to_parent_id?
end
def saved_change_to_path_or_parent?
saved_change_to_path? || saved_change_to_parent_id?
2018-03-17 18:26:18 +05:30
end
2017-08-17 22:00:37 +05:30
def refresh_access_of_projects_invited_groups
2021-10-27 15:23:28 +05:30
if Feature.enabled?(:specialized_worker_for_group_lock_update_auth_recalculation)
Project
.where(namespace_id: id)
.joins(:project_group_links)
.distinct
.find_each do |project|
AuthorizedProjectUpdate::ProjectRecalculateWorker.perform_async(project.id)
end
# Until we compare the inconsistency rates of the new specialized worker and
# the old approach, we still run AuthorizedProjectsWorker
# but with some delay and lower urgency as a safety net.
2021-12-11 22:18:48 +05:30
enqueue_jobs_for_groups_requiring_authorizations_refresh(priority: UserProjectAccessChangedService::LOW_PRIORITY)
2021-10-27 15:23:28 +05:30
else
2021-12-11 22:18:48 +05:30
enqueue_jobs_for_groups_requiring_authorizations_refresh(priority: UserProjectAccessChangedService::HIGH_PRIORITY)
end
end
def enqueue_jobs_for_groups_requiring_authorizations_refresh(priority:)
groups_requiring_authorizations_refresh = Group
.joins(project_group_links: :project)
.where(projects: { namespace_id: id })
.distinct
groups_requiring_authorizations_refresh.find_each do |group|
group.refresh_members_authorized_projects(
blocking: false,
priority: priority
)
2021-10-27 15:23:28 +05:30
end
2017-08-17 22:00:37 +05:30
end
def nesting_level_allowed
if ancestors.count > Group::NUMBER_OF_ANCESTORS_ALLOWED
2021-11-11 11:23:49 +05:30
errors.add(:parent_id, _('has too deep level of nesting'))
2017-08-17 22:00:37 +05:30
end
2016-08-24 12:49:21 +05:30
end
2018-03-17 18:26:18 +05:30
2021-04-17 20:07:23 +05:30
def validate_parent_type
2021-11-11 11:23:49 +05:30
unless has_parent?
2021-11-18 22:05:49 +05:30
if project_namespace?
2021-11-11 11:23:49 +05:30
errors.add(:parent_id, _('must be set for a project namespace'))
end
return
end
2022-07-23 23:45:48 +05:30
if parent&.project_namespace?
2021-11-11 11:23:49 +05:30
errors.add(:parent_id, _('project namespace cannot be the parent of another namespace'))
end
2021-04-17 20:07:23 +05:30
2021-11-18 22:05:49 +05:30
if user_namespace?
2021-12-11 22:18:48 +05:30
errors.add(:parent_id, _('cannot be used for user namespace'))
2021-11-18 22:05:49 +05:30
elsif group_namespace?
errors.add(:parent_id, _('user namespace cannot be the parent of another namespace')) if parent.user_namespace?
2021-04-17 20:07:23 +05:30
end
end
2022-08-27 11:52:29 +05:30
def reload_namespace_details
return unless !project_namespace? && (previous_changes.keys & %w(description description_html cached_markdown_version)).any? && namespace_details.present?
namespace_details.reset
end
2018-03-17 18:26:18 +05:30
def sync_share_with_group_lock_with_parent
if parent&.share_with_group_lock?
self.share_with_group_lock = true
end
end
def force_share_with_group_lock_on_descendants
# We can't use `descendants.update_all` since Rails will throw away the WITH
# RECURSIVE statement. We also can't use WHERE EXISTS since we can't use
# different table aliases, hence we're just using WHERE IN. Since we have a
# maximum of 20 nested groups this should be fine.
Namespace.where(id: descendants.select(:id))
.update_all(share_with_group_lock: true)
end
2022-05-07 20:08:51 +05:30
def expire_first_auto_devops_config_cache
descendants_to_expire = self_and_descendants.as_ids
return if descendants_to_expire.load.empty?
keys = descendants_to_expire.map { |group| first_auto_devops_config_cache_key_for(group.id) }
Rails.cache.delete_multi(keys)
end
2018-03-17 18:26:18 +05:30
def write_projects_repository_config
all_projects.find_each do |project|
2021-10-27 15:23:28 +05:30
project.set_full_path
2019-02-15 15:39:39 +05:30
project.track_project_repository
2018-03-17 18:26:18 +05:30
end
end
2021-11-18 22:05:49 +05:30
def enforce_minimum_path_length?
path_changed? && !project_namespace?
end
2022-01-26 12:08:38 +05:30
# SyncEvents are created by PG triggers (with the function `insert_namespaces_sync_event`)
def schedule_sync_event_worker
run_after_commit do
Namespaces::SyncEvent.enqueue_worker
end
end
2022-05-07 20:08:51 +05:30
def first_auto_devops_config_cache_key_for(group_id)
# Use SHA2 of `traversal_ids` to account for moving a namespace within the same root ancestor hierarchy.
"namespaces:{#{traversal_ids.first}}:first_auto_devops_config:#{group_id}:#{Digest::SHA2.hexdigest(traversal_ids.join(' '))}"
end
2014-09-02 18:07:02 +05:30
end
2019-12-04 20:38:33 +05:30
2021-06-08 01:23:25 +05:30
Namespace.prepend_mod_with('Namespace')