Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2023-05-17 19:05:49 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-05-17 19:05:49 +0300
commit43a25d93ebdabea52f99b05e15b06250cd8f07d7 (patch)
treedceebdc68925362117480a5d672bcff122fb625b /app/finders
parent20c84b99005abd1c82101dfeff264ac50d2df211 (diff)
Add latest changes from gitlab-org/gitlab@16-0-stable-eev16.0.0-rc42
Diffstat (limited to 'app/finders')
-rw-r--r--app/finders/abuse_reports_finder.rb87
-rw-r--r--app/finders/access_requests_finder.rb6
-rw-r--r--app/finders/achievements/achievements_finder.rb29
-rw-r--r--app/finders/autocomplete/users_finder.rb6
-rw-r--r--app/finders/ci/pipelines_finder.rb9
-rw-r--r--app/finders/ci/runners_finder.rb2
-rw-r--r--app/finders/clusters/agent_authorizations_finder.rb69
-rw-r--r--app/finders/clusters/agent_tokens_finder.rb22
-rw-r--r--app/finders/clusters/agents/authorizations/ci_access/finder.rb75
-rw-r--r--app/finders/clusters/agents/authorizations/user_access/finder.rb69
-rw-r--r--app/finders/clusters/agents_finder.rb2
-rw-r--r--app/finders/concerns/finder_with_group_hierarchy.rb12
-rw-r--r--app/finders/concerns/updated_at_filter.rb14
-rw-r--r--app/finders/context_commits_finder.rb8
-rw-r--r--app/finders/data_transfer/group_data_transfer_finder.rb34
-rw-r--r--app/finders/data_transfer/mocked_transfer_finder.rb27
-rw-r--r--app/finders/data_transfer/project_data_transfer_finder.rb25
-rw-r--r--app/finders/deployments_finder.rb27
-rw-r--r--app/finders/fork_targets_finder.rb2
-rw-r--r--app/finders/group_descendants_finder.rb21
-rw-r--r--app/finders/group_members_finder.rb61
-rw-r--r--app/finders/groups/accepting_project_creations_finder.rb101
-rw-r--r--app/finders/groups/accepting_project_imports_finder.rb31
-rw-r--r--app/finders/groups/accepting_project_shares_finder.rb24
-rw-r--r--app/finders/groups/user_groups_finder.rb8
-rw-r--r--app/finders/issuable_finder.rb8
-rw-r--r--app/finders/labels_finder.rb9
-rw-r--r--app/finders/members_finder.rb21
-rw-r--r--app/finders/merge_requests_finder.rb15
-rw-r--r--app/finders/merge_requests_finder/params.rb2
-rw-r--r--app/finders/milestones_finder.rb16
-rw-r--r--app/finders/notes_finder.rb8
-rw-r--r--app/finders/packages/conan/package_finder.rb28
-rw-r--r--app/finders/packages/npm/package_finder.rb6
-rw-r--r--app/finders/pending_todos_finder.rb28
-rw-r--r--app/finders/projects_finder.rb2
-rw-r--r--app/finders/security/security_jobs_finder.rb2
-rw-r--r--app/finders/serverless_domain_finder.rb35
-rw-r--r--app/finders/snippets_finder.rb2
-rw-r--r--app/finders/template_finder.rb15
40 files changed, 756 insertions, 212 deletions
diff --git a/app/finders/abuse_reports_finder.rb b/app/finders/abuse_reports_finder.rb
index 04043f36426..6a6d0413194 100644
--- a/app/finders/abuse_reports_finder.rb
+++ b/app/finders/abuse_reports_finder.rb
@@ -1,18 +1,93 @@
# frozen_string_literal: true
class AbuseReportsFinder
- attr_reader :params
+ attr_reader :params, :reports
+
+ DEFAULT_STATUS_FILTER = 'open'
+ DEFAULT_SORT = 'created_at_desc'
+ ALLOWED_SORT = [DEFAULT_SORT, *%w[created_at_asc updated_at_desc updated_at_asc]].freeze
def initialize(params = {})
@params = params
+ @reports = AbuseReport.all
end
def execute
- reports = AbuseReport.all
- reports = reports.by_user(params[:user_id]) if params[:user_id].present?
+ filter_reports
+ sort_reports
+
+ reports.with_users.page(params[:page])
+ end
+
+ private
+
+ def filter_reports
+ filter_by_user_id
+
+ filter_by_user
+ filter_by_reporter
+ filter_by_status
+ filter_by_category
+ end
+
+ def filter_by_status
+ return unless Feature.enabled?(:abuse_reports_list)
+ return unless params[:status].present?
+
+ status = params[:status]
+ status = DEFAULT_STATUS_FILTER unless status.in?(AbuseReport.statuses.keys)
+
+ case status
+ when 'open'
+ @reports = @reports.open
+ when 'closed'
+ @reports = @reports.closed
+ end
+ end
+
+ def filter_by_category
+ return unless params[:category].present?
+
+ @reports = @reports.by_category(params[:category])
+ end
+
+ def filter_by_user
+ return unless params[:user].present?
+
+ user_id = find_user_id(params[:user])
+ return unless user_id
+
+ @reports = @reports.by_user_id(user_id)
+ end
+
+ def filter_by_reporter
+ return unless params[:reporter].present?
+
+ user_id = find_user_id(params[:reporter])
+ return unless user_id
+
+ @reports = @reports.by_reporter_id(user_id)
+ end
+
+ def filter_by_user_id
+ return unless params[:user_id].present?
+
+ @reports = @reports.by_user_id(params[:user_id])
+ end
+
+ def sort_reports
+ if Feature.disabled?(:abuse_reports_list)
+ @reports = @reports.with_order_id_desc
+ return
+ end
+
+ sort_by = params[:sort]
+ sort_by = DEFAULT_SORT unless sort_by.in?(ALLOWED_SORT)
+
+ @reports = @reports.order_by(sort_by)
+ end
- reports.with_order_id_desc
- .with_users
- .page(params[:page])
+ def find_user_id(username)
+ User.by_username(username).pick(:id)
end
end
diff --git a/app/finders/access_requests_finder.rb b/app/finders/access_requests_finder.rb
index 7b98df68f29..140d68cfe91 100644
--- a/app/finders/access_requests_finder.rb
+++ b/app/finders/access_requests_finder.rb
@@ -18,11 +18,7 @@ class AccessRequestsFinder
def execute!(current_user)
raise Gitlab::Access::AccessDeniedError unless can_see_access_requests?(current_user)
- if Feature.enabled?(:project_members_index_by_project_namespace, source)
- source.namespace_requesters
- else
- source.requesters
- end
+ source.namespace_requesters
end
private
diff --git a/app/finders/achievements/achievements_finder.rb b/app/finders/achievements/achievements_finder.rb
new file mode 100644
index 00000000000..98bd12afcd4
--- /dev/null
+++ b/app/finders/achievements/achievements_finder.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+module Achievements
+ class AchievementsFinder
+ attr_reader :namespace, :params
+
+ def initialize(namespace, params = {})
+ @namespace = namespace
+ @params = params
+ end
+
+ def execute
+ achievements = namespace.achievements
+ by_ids(achievements)
+ end
+
+ private
+
+ def by_ids(achievements)
+ return achievements unless ids?
+
+ achievements.id_in(params[:ids])
+ end
+
+ def ids?
+ params[:ids].present?
+ end
+ end
+end
diff --git a/app/finders/autocomplete/users_finder.rb b/app/finders/autocomplete/users_finder.rb
index bb91f84de99..7ecf5c98ac0 100644
--- a/app/finders/autocomplete/users_finder.rb
+++ b/app/finders/autocomplete/users_finder.rb
@@ -11,8 +11,8 @@ module Autocomplete
LIMIT = 20
attr_reader :current_user, :project, :group, :search, :skip_users,
- :author_id, :todo_filter, :todo_state_filter,
- :filter_by_current_user, :states
+ :author_id, :todo_filter, :todo_state_filter,
+ :filter_by_current_user, :states
def initialize(params:, current_user:, project:, group:)
@current_user = current_user
@@ -98,7 +98,7 @@ module Autocomplete
# rubocop: disable CodeReuse/ActiveRecord
def preload_associations(items)
- ActiveRecord::Associations::Preloader.new.preload(items, :status)
+ ActiveRecord::Associations::Preloader.new(records: items, associations: :status).call
end
# rubocop: enable CodeReuse/ActiveRecord
diff --git a/app/finders/ci/pipelines_finder.rb b/app/finders/ci/pipelines_finder.rb
index a2d1805286d..e52fc510628 100644
--- a/app/finders/ci/pipelines_finder.rb
+++ b/app/finders/ci/pipelines_finder.rb
@@ -2,6 +2,8 @@
module Ci
class PipelinesFinder
+ include UpdatedAtFilter
+
attr_reader :project, :pipelines, :params, :current_user
ALLOWED_INDEXED_COLUMNS = %w[id status ref updated_at user_id].freeze
@@ -146,13 +148,6 @@ module Ci
end
# rubocop: enable CodeReuse/ActiveRecord
- def by_updated_at(items)
- items = items.updated_before(params[:updated_before]) if params[:updated_before].present?
- items = items.updated_after(params[:updated_after]) if params[:updated_after].present?
-
- items
- end
-
def by_name(items)
return items unless
Feature.enabled?(:pipeline_name_search, project) &&
diff --git a/app/finders/ci/runners_finder.rb b/app/finders/ci/runners_finder.rb
index bc1dcb3ad5f..5f03ae77338 100644
--- a/app/finders/ci/runners_finder.rb
+++ b/app/finders/ci/runners_finder.rb
@@ -74,7 +74,7 @@ module Ci
end
def project_runners
- raise Gitlab::Access::AccessDeniedError unless can?(@current_user, :admin_project, @project)
+ raise Gitlab::Access::AccessDeniedError unless can?(@current_user, :read_project_runners, @project)
@runners = ::Ci::Runner.owned_or_instance_wide(@project.id)
end
diff --git a/app/finders/clusters/agent_authorizations_finder.rb b/app/finders/clusters/agent_authorizations_finder.rb
deleted file mode 100644
index 70c0868cc7f..00000000000
--- a/app/finders/clusters/agent_authorizations_finder.rb
+++ /dev/null
@@ -1,69 +0,0 @@
-# frozen_string_literal: true
-
-module Clusters
- class AgentAuthorizationsFinder
- def initialize(project)
- @project = project
- end
-
- def execute
- # closest, most-specific authorization for a given agent wins
- (project_authorizations + implicit_authorizations + group_authorizations)
- .uniq(&:agent_id)
- end
-
- private
-
- attr_reader :project
-
- def implicit_authorizations
- project.cluster_agents.map do |agent|
- Clusters::Agents::ImplicitAuthorization.new(agent: agent)
- end
- end
-
- # rubocop: disable CodeReuse/ActiveRecord
- def project_authorizations
- namespace_ids = project.group ? all_namespace_ids : project.namespace_id
-
- Clusters::Agents::ProjectAuthorization
- .where(project_id: project.id)
- .joins(agent: :project)
- .preload(agent: :project)
- .where(cluster_agents: { projects: { namespace_id: namespace_ids } })
- .with_available_ci_access_fields(project)
- .to_a
- end
-
- def group_authorizations
- return [] unless project.group
-
- authorizations = Clusters::Agents::GroupAuthorization.arel_table
-
- ordered_ancestors_cte = Gitlab::SQL::CTE.new(
- :ordered_ancestors,
- project.group.self_and_ancestors(hierarchy_order: :asc).reselect(:id)
- )
-
- cte_join_sources = authorizations.join(ordered_ancestors_cte.table).on(
- authorizations[:group_id].eq(ordered_ancestors_cte.table[:id])
- ).join_sources
-
- Clusters::Agents::GroupAuthorization
- .with(ordered_ancestors_cte.to_arel)
- .joins(cte_join_sources)
- .joins(agent: :project)
- .with_available_ci_access_fields(project)
- .where(projects: { namespace_id: all_namespace_ids })
- .order(Arel.sql('agent_id, array_position(ARRAY(SELECT id FROM ordered_ancestors)::bigint[], agent_group_authorizations.group_id)'))
- .select('DISTINCT ON (agent_id) agent_group_authorizations.*')
- .preload(agent: :project)
- .to_a
- end
- # rubocop: enable CodeReuse/ActiveRecord
-
- def all_namespace_ids
- project.root_ancestor.self_and_descendants.select(:id)
- end
- end
-end
diff --git a/app/finders/clusters/agent_tokens_finder.rb b/app/finders/clusters/agent_tokens_finder.rb
index 72692777bc6..9ec00245250 100644
--- a/app/finders/clusters/agent_tokens_finder.rb
+++ b/app/finders/clusters/agent_tokens_finder.rb
@@ -11,21 +11,31 @@ module Clusters
end
def execute
- return ::Clusters::AgentToken.none unless can_read_cluster_agents?
+ return ::Clusters::AgentToken.none unless can_read_cluster_agent?
- agent.agent_tokens.then { |agent_tokens| by_status(agent_tokens) }
+ agent_tokens_by_status
end
private
attr_reader :agent, :current_user, :params
- def by_status(agent_tokens)
- params[:status].present? ? agent_tokens.with_status(params[:status]) : agent_tokens
+ def agent_tokens_by_status
+ # If the `status` parameter is set to `active`, we use the `active_agent_tokens` scope
+ # in case this called from GraphQL's AgentTokensResolver. This prevents a repeat query
+ # to the database, because `active_agent_tokens` is already preloaded in the AgentsResolver
+ return agent.active_agent_tokens if active_tokens_only?
+
+ # Else, we use the `agent_tokens` scope combined with `with_status` if necessary
+ params[:status].present? ? agent.agent_tokens.with_status(params[:status]) : agent.agent_tokens
+ end
+
+ def active_tokens_only?
+ params[:status].present? && params[:status].to_sym == :active
end
- def can_read_cluster_agents?
- current_user&.can?(:read_cluster, agent&.project)
+ def can_read_cluster_agent?
+ current_user&.can?(:read_cluster_agent, agent)
end
end
end
diff --git a/app/finders/clusters/agents/authorizations/ci_access/finder.rb b/app/finders/clusters/agents/authorizations/ci_access/finder.rb
new file mode 100644
index 00000000000..97d378669a4
--- /dev/null
+++ b/app/finders/clusters/agents/authorizations/ci_access/finder.rb
@@ -0,0 +1,75 @@
+# frozen_string_literal: true
+
+module Clusters
+ module Agents
+ module Authorizations
+ module CiAccess
+ class Finder
+ def initialize(project)
+ @project = project
+ end
+
+ def execute
+ # closest, most-specific authorization for a given agent wins
+ (project_authorizations + implicit_authorizations + group_authorizations)
+ .uniq(&:agent_id)
+ end
+
+ private
+
+ attr_reader :project
+
+ def implicit_authorizations
+ project.cluster_agents.map do |agent|
+ Clusters::Agents::Authorizations::CiAccess::ImplicitAuthorization.new(agent: agent)
+ end
+ end
+
+ # rubocop: disable CodeReuse/ActiveRecord
+ def project_authorizations
+ namespace_ids = project.group ? all_namespace_ids : project.namespace_id
+
+ Clusters::Agents::Authorizations::CiAccess::ProjectAuthorization
+ .where(project_id: project.id)
+ .joins(agent: :project)
+ .preload(agent: :project)
+ .where(cluster_agents: { projects: { namespace_id: namespace_ids } })
+ .with_available_ci_access_fields(project)
+ .to_a
+ end
+
+ def group_authorizations
+ return [] unless project.group
+
+ authorizations = Clusters::Agents::Authorizations::CiAccess::GroupAuthorization.arel_table
+
+ ordered_ancestors_cte = Gitlab::SQL::CTE.new(
+ :ordered_ancestors,
+ project.group.self_and_ancestors(hierarchy_order: :asc).reselect(:id)
+ )
+
+ cte_join_sources = authorizations.join(ordered_ancestors_cte.table).on(
+ authorizations[:group_id].eq(ordered_ancestors_cte.table[:id])
+ ).join_sources
+
+ Clusters::Agents::Authorizations::CiAccess::GroupAuthorization
+ .with(ordered_ancestors_cte.to_arel)
+ .joins(cte_join_sources)
+ .joins(agent: :project)
+ .with_available_ci_access_fields(project)
+ .where(projects: { namespace_id: all_namespace_ids })
+ .order(Arel.sql('agent_id, array_position(ARRAY(SELECT id FROM ordered_ancestors)::bigint[], agent_group_authorizations.group_id)'))
+ .select('DISTINCT ON (agent_id) agent_group_authorizations.*')
+ .preload(agent: :project)
+ .to_a
+ end
+ # rubocop: enable CodeReuse/ActiveRecord
+
+ def all_namespace_ids
+ project.root_ancestor.self_and_descendants.select(:id)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/app/finders/clusters/agents/authorizations/user_access/finder.rb b/app/finders/clusters/agents/authorizations/user_access/finder.rb
new file mode 100644
index 00000000000..bde75fa46cb
--- /dev/null
+++ b/app/finders/clusters/agents/authorizations/user_access/finder.rb
@@ -0,0 +1,69 @@
+# frozen_string_literal: true
+
+module Clusters
+ module Agents
+ module Authorizations
+ module UserAccess
+ class Finder
+ def initialize(user, agent: nil, project: nil, preload: true, limit: nil)
+ @user = user
+ @agent = agent
+ @project = project
+ @limit = limit
+ @preload = preload
+ end
+
+ def execute
+ project_authorizations + group_authorizations
+ end
+
+ private
+
+ attr_reader :user, :agent, :project, :preload, :limit
+
+ def project_authorizations
+ authorizations = Clusters::Agents::Authorizations::UserAccess::ProjectAuthorization.for_user(user)
+ authorizations = filter_by_agent(authorizations)
+ authorizations = filter_by_project(authorizations)
+ authorizations = apply_limit(authorizations)
+ authorizations = apply_preload(authorizations)
+ authorizations.to_a
+ end
+
+ def group_authorizations
+ authorizations = Clusters::Agents::Authorizations::UserAccess::GroupAuthorization.for_user(user)
+ authorizations = filter_by_agent(authorizations)
+ authorizations = filter_by_project(authorizations)
+ authorizations = apply_limit(authorizations)
+ authorizations = apply_preload(authorizations)
+ authorizations.to_a
+ end
+
+ def filter_by_agent(authorizations)
+ return authorizations unless agent.present?
+
+ authorizations.for_agent(agent)
+ end
+
+ def filter_by_project(authorizations)
+ return authorizations unless project.present?
+
+ authorizations.for_project(project)
+ end
+
+ def apply_limit(authorizations)
+ return authorizations unless limit.present?
+
+ authorizations.limit(limit)
+ end
+
+ def apply_preload(authorizations)
+ return authorizations unless preload
+
+ authorizations.preloaded
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/app/finders/clusters/agents_finder.rb b/app/finders/clusters/agents_finder.rb
index 14277db3f85..0cdebe93f32 100644
--- a/app/finders/clusters/agents_finder.rb
+++ b/app/finders/clusters/agents_finder.rb
@@ -29,7 +29,7 @@ module Clusters
end
def can_read_cluster_agents?
- current_user&.can?(:read_cluster, object)
+ current_user&.can?(:read_cluster_agent, object)
end
end
end
diff --git a/app/finders/concerns/finder_with_group_hierarchy.rb b/app/finders/concerns/finder_with_group_hierarchy.rb
index 4ced544ba2c..99b58fa6954 100644
--- a/app/finders/concerns/finder_with_group_hierarchy.rb
+++ b/app/finders/concerns/finder_with_group_hierarchy.rb
@@ -27,11 +27,7 @@ module FinderWithGroupHierarchy
# we can preset root group for all of them to optimize permission checks
Group.preset_root_ancestor_for(groups)
- # Preloading the max access level for the given groups to avoid N+1 queries
- # during the access check.
- if !skip_authorization && current_user && Feature.enabled?(:preload_max_access_levels_for_labels_finder, group)
- Preloaders::UserMaxAccessLevelInGroupsPreloader.new(groups, current_user).execute
- end
+ preload_associations(groups) if !skip_authorization && current_user
groups_user_can_read_items(groups).map(&:id)
end
@@ -77,4 +73,10 @@ module FinderWithGroupHierarchy
groups.select { |group| authorized_to_read_item?(group) }
end
end
+
+ def preload_associations(groups)
+ Preloaders::UserMaxAccessLevelInGroupsPreloader.new(groups, current_user).execute
+ end
end
+
+FinderWithGroupHierarchy.prepend_mod_with('FinderWithGroupHierarchy')
diff --git a/app/finders/concerns/updated_at_filter.rb b/app/finders/concerns/updated_at_filter.rb
new file mode 100644
index 00000000000..0e9a3fb5e8c
--- /dev/null
+++ b/app/finders/concerns/updated_at_filter.rb
@@ -0,0 +1,14 @@
+# frozen_string_literal: true
+
+module UpdatedAtFilter
+ def by_updated_at(items)
+ updated_before = params[:updated_before]&.in_time_zone
+ updated_after = params[:updated_after]&.in_time_zone
+ return items.none if [updated_before, updated_after].all?(&:present?) && updated_before < updated_after
+
+ items = items.updated_before(updated_before) if updated_before.present?
+ items = items.updated_after(updated_after) if updated_after.present?
+
+ items
+ end
+end
diff --git a/app/finders/context_commits_finder.rb b/app/finders/context_commits_finder.rb
index 4a45817cc61..a186ca92c7b 100644
--- a/app/finders/context_commits_finder.rb
+++ b/app/finders/context_commits_finder.rb
@@ -21,20 +21,24 @@ class ContextCommitsFinder
attr_reader :project, :merge_request, :search, :author, :committed_before, :committed_after, :limit
def init_collection
- if search.present?
+ if search_params_present?
search_commits
else
project.repository.commits(merge_request.target_branch, { limit: limit })
end
end
+ def search_params_present?
+ [search, author, committed_before, committed_after].map(&:present?).any?
+ end
+
def filter_existing_commits(commits)
commits.select! { |commit| already_included_ids.exclude?(commit.id) }
commits
end
def search_commits
- key = search.strip
+ key = search&.strip
commits = []
if Commit.valid_hash?(key)
mr_existing_commits_ids = merge_request.commits.map(&:id)
diff --git a/app/finders/data_transfer/group_data_transfer_finder.rb b/app/finders/data_transfer/group_data_transfer_finder.rb
new file mode 100644
index 00000000000..19ab99d4477
--- /dev/null
+++ b/app/finders/data_transfer/group_data_transfer_finder.rb
@@ -0,0 +1,34 @@
+# frozen_string_literal: true
+
+module DataTransfer
+ class GroupDataTransferFinder
+ def initialize(group:, from:, to:, user:)
+ @group = group
+ @from = from
+ @to = to
+ @user = user
+ end
+
+ def execute
+ return ::Projects::DataTransfer.none unless Ability.allowed?(user, :read_usage_quotas, group)
+
+ ::Projects::DataTransfer
+ .with_namespace_between_dates(group, from, to)
+ .select('SUM(repository_egress
+ + artifacts_egress
+ + packages_egress
+ + registry_egress
+ ) as total_egress,
+ SUM(repository_egress) as repository_egress,
+ SUM(artifacts_egress) as artifacts_egress,
+ SUM(packages_egress) as packages_egress,
+ SUM(registry_egress) as registry_egress,
+ date,
+ namespace_id')
+ end
+
+ private
+
+ attr_reader :group, :from, :to, :user
+ end
+end
diff --git a/app/finders/data_transfer/mocked_transfer_finder.rb b/app/finders/data_transfer/mocked_transfer_finder.rb
new file mode 100644
index 00000000000..9c5551005ea
--- /dev/null
+++ b/app/finders/data_transfer/mocked_transfer_finder.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+# Mocked data for data transfer
+# Follow this epic for recent progress: https://gitlab.com/groups/gitlab-org/-/epics/9330
+module DataTransfer
+ class MockedTransferFinder
+ def execute
+ start_date = Date.new(2023, 0o1, 0o1)
+ date_for_index = ->(i) { (start_date + i.months).strftime('%Y-%m-%d') }
+
+ 0.upto(11).map do |i|
+ {
+ date: date_for_index.call(i),
+ repository_egress: rand(70000..550000),
+ artifacts_egress: rand(70000..550000),
+ packages_egress: rand(70000..550000),
+ registry_egress: rand(70000..550000)
+ }.tap do |hash|
+ hash[:total_egress] = hash
+ .slice(:repository_egress, :artifacts_egress, :packages_egress, :registry_egress)
+ .values
+ .sum
+ end
+ end
+ end
+ end
+end
diff --git a/app/finders/data_transfer/project_data_transfer_finder.rb b/app/finders/data_transfer/project_data_transfer_finder.rb
new file mode 100644
index 00000000000..bcabbdb00a5
--- /dev/null
+++ b/app/finders/data_transfer/project_data_transfer_finder.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+module DataTransfer
+ class ProjectDataTransferFinder
+ def initialize(project:, from:, to:, user:)
+ @project = project
+ @from = from
+ @to = to
+ @user = user
+ end
+
+ def execute
+ return ::Projects::DataTransfer.none unless Ability.allowed?(user, :read_usage_quotas, project)
+
+ ::Projects::DataTransfer
+ .with_project_between_dates(project, from, to)
+ .select(:project_id, :date, :repository_egress, :artifacts_egress, :packages_egress, :registry_egress,
+ "repository_egress + artifacts_egress + packages_egress + registry_egress as total_egress")
+ end
+
+ private
+
+ attr_reader :project, :from, :to, :user
+ end
+end
diff --git a/app/finders/deployments_finder.rb b/app/finders/deployments_finder.rb
index 21869f6f31d..316dffcb3b2 100644
--- a/app/finders/deployments_finder.rb
+++ b/app/finders/deployments_finder.rb
@@ -14,6 +14,8 @@
# order_by: String (see ALLOWED_SORT_VALUES constant)
# sort: String (asc | desc)
class DeploymentsFinder
+ include UpdatedAtFilter
+
attr_reader :params
# Warning:
@@ -50,10 +52,6 @@ class DeploymentsFinder
private
- def raise_for_inefficient_updated_at_query?
- params.fetch(:raise_for_inefficient_updated_at_query, Rails.env.development? || Rails.env.test?)
- end
-
def validate!
if filter_by_updated_at? && filter_by_finished_at?
raise InefficientQueryError, 'Both `updated_at` filter and `finished_at` filter can not be specified'
@@ -61,12 +59,20 @@ class DeploymentsFinder
# Currently, the inefficient parameters are allowed in order to avoid breaking changes in Deployment API.
# We'll switch to a hard error in https://gitlab.com/gitlab-org/gitlab/-/issues/328500.
- if (filter_by_updated_at? && !order_by_updated_at?) || (!filter_by_updated_at? && order_by_updated_at?)
- error = InefficientQueryError.new('`updated_at` filter and `updated_at` sorting must be paired')
+ if filter_by_updated_at? && !order_by_updated_at?
+ error = InefficientQueryError.new('`updated_at` filter requires `updated_at` sort')
Gitlab::ErrorTracking.log_exception(error)
- raise error if raise_for_inefficient_updated_at_query?
+ # We are adding a Feature Flag to introduce the breaking change indicated in
+ # https://gitlab.com/gitlab-org/gitlab/-/issues/328500
+ # We are also adding a way to override this flag for special case users that
+ # are running into large volume of errors when the flag is enabled.
+ # These Feature Flags must be removed by 16.1
+ if Feature.enabled?(:deployments_raise_updated_at_inefficient_error) &&
+ Feature.disabled?(:deployments_raise_updated_at_inefficient_error_override, params[:project])
+ raise error
+ end
end
if filter_by_finished_at? && !order_by_finished_at?
@@ -109,13 +115,6 @@ class DeploymentsFinder
items.order(sort_params) # rubocop: disable CodeReuse/ActiveRecord
end
- def by_updated_at(items)
- items = items.updated_before(params[:updated_before]) if params[:updated_before].present?
- items = items.updated_after(params[:updated_after]) if params[:updated_after].present?
-
- items
- end
-
def by_finished_at(items)
items = items.finished_before(params[:finished_before]) if params[:finished_before].present?
items = items.finished_after(params[:finished_after]) if params[:finished_after].present?
diff --git a/app/finders/fork_targets_finder.rb b/app/finders/fork_targets_finder.rb
index c1769ea28f9..a96acd5838e 100644
--- a/app/finders/fork_targets_finder.rb
+++ b/app/finders/fork_targets_finder.rb
@@ -24,7 +24,7 @@ class ForkTargetsFinder
def fork_targets(options)
if options[:only_groups]
- user.manageable_groups(include_groups_with_developer_maintainer_access: true)
+ Groups::AcceptingProjectCreationsFinder.new(user).execute # rubocop: disable CodeReuse/Finder
else
user.forkable_namespaces.sort_by_type
end
diff --git a/app/finders/group_descendants_finder.rb b/app/finders/group_descendants_finder.rb
index 033af0f42a6..07f39f98b12 100644
--- a/app/finders/group_descendants_finder.rb
+++ b/app/finders/group_descendants_finder.rb
@@ -64,9 +64,7 @@ class GroupDescendantsFinder
def direct_child_groups
# rubocop: disable CodeReuse/Finder
- GroupsFinder.new(current_user,
- parent: parent_group,
- all_available: true).execute
+ GroupsFinder.new(current_user, parent: parent_group, all_available: true).execute
# rubocop: enable CodeReuse/Finder
end
@@ -78,12 +76,11 @@ class GroupDescendantsFinder
.in(Gitlab::VisibilityLevel.levels_for_user(current_user))
if current_user
- authorized_groups = GroupsFinder.new(current_user,
- all_available: false)
- .execute.arel.as('authorized')
+ authorized_groups = GroupsFinder.new(current_user, all_available: false)
+ .execute.arel.as('authorized')
authorized_to_user = groups_table.project(1).from(authorized_groups)
- .where(authorized_groups[:id].eq(groups_table[:id]))
- .exists
+ .where(authorized_groups[:id].eq(groups_table[:id]))
+ .exists
visible_to_user = visible_to_user.or(authorized_to_user)
end
@@ -161,9 +158,11 @@ class GroupDescendantsFinder
projects_nested_in_group = Project.where(namespace_id: parent_group.self_and_descendants.as_ids)
params_with_search = params.merge(search: params[:filter])
- ProjectsFinder.new(params: params_with_search,
- current_user: current_user,
- project_ids_relation: projects_nested_in_group).execute
+ ProjectsFinder.new(
+ params: params_with_search,
+ current_user: current_user,
+ project_ids_relation: projects_nested_in_group
+ ).execute
# rubocop: enable CodeReuse/Finder
end
# rubocop: enable CodeReuse/ActiveRecord
diff --git a/app/finders/group_members_finder.rb b/app/finders/group_members_finder.rb
index 47ed623b252..1025e0ebc9b 100644
--- a/app/finders/group_members_finder.rb
+++ b/app/finders/group_members_finder.rb
@@ -30,7 +30,11 @@ class GroupMembersFinder < UnionFinder
def execute(include_relations: DEFAULT_RELATIONS)
groups = groups_by_relations(include_relations)
- members = all_group_members(groups).distinct_on_user_with_max_access_level
+ shared_from_groups = if include_relations&.include?(:shared_from_groups)
+ Group.shared_into_ancestors(group).public_or_visible_to_user(user)
+ end
+
+ members = all_group_members(groups, shared_from_groups).distinct_on_user_with_max_access_level
filter_members(members)
end
@@ -47,9 +51,8 @@ class GroupMembersFinder < UnionFinder
related_groups << Group.by_id(group.id) if include_relations&.include?(:direct)
related_groups << group.ancestors if include_relations&.include?(:inherited)
related_groups << group.descendants if include_relations&.include?(:descendants)
- related_groups << Group.shared_into_ancestors(group).public_or_visible_to_user(user) if include_relations&.include?(:shared_from_groups)
- find_union(related_groups, Group)
+ related_groups
end
def filter_members(members)
@@ -64,6 +67,7 @@ class GroupMembersFinder < UnionFinder
members = members.by_access_level(params[:access_levels])
end
+ members = filter_by_user_type(members)
members = apply_additional_filters(members)
by_created_at(members)
@@ -77,12 +81,49 @@ class GroupMembersFinder < UnionFinder
group.members
end
- def all_group_members(groups)
- members_of_groups(groups).non_minimal_access
+ def all_group_members(groups, shared_from_groups)
+ members_of_groups(groups, shared_from_groups).non_minimal_access
+ end
+
+ def members_of_groups(groups, shared_from_groups)
+ if Feature.disabled?(:members_with_shared_group_access, @group.root_ancestor)
+ groups << shared_from_groups unless shared_from_groups.nil?
+ return GroupMember.non_request.of_groups(find_union(groups, Group))
+ end
+
+ members = GroupMember.non_request.of_groups(find_union(groups, Group))
+ return members if shared_from_groups.nil?
+
+ shared_members = GroupMember.non_request.of_groups(shared_from_groups)
+ select_attributes = GroupMember.attribute_names
+ members_shared_with_group_access = members_shared_with_group_access(shared_members, select_attributes)
+
+ # `members` and `members_shared_with_group_access` should have even select values
+ find_union([members.select(select_attributes), members_shared_with_group_access], GroupMember)
+ end
+
+ def members_shared_with_group_access(shared_members, select_attributes)
+ group_group_link_table = GroupGroupLink.arel_table
+ group_member_table = GroupMember.arel_table
+
+ member_columns = select_attributes.map do |column_name|
+ if column_name == 'access_level'
+ args = [group_group_link_table[:group_access], group_member_table[:access_level]]
+ smallest_value_arel(args, 'access_level')
+ else
+ group_member_table[column_name]
+ end
+ end
+
+ # rubocop:disable CodeReuse/ActiveRecord
+ shared_members
+ .joins("LEFT OUTER JOIN group_group_links ON members.source_id = group_group_links.shared_with_group_id")
+ .select(member_columns)
+ # rubocop:enable CodeReuse/ActiveRecord
end
- def members_of_groups(groups)
- GroupMember.non_request.of_groups(groups)
+ def smallest_value_arel(args, column_alias)
+ Arel::Nodes::As.new(Arel::Nodes::NamedFunction.new('LEAST', args), Arel::Nodes::SqlLiteral.new(column_alias))
end
def check_relation_arguments!(include_relations)
@@ -91,6 +132,12 @@ class GroupMembersFinder < UnionFinder
end
end
+ def filter_by_user_type(members)
+ return members unless params[:user_type] && can_manage_members
+
+ members.filter_by_user_type(params[:user_type])
+ end
+
def apply_additional_filters(members)
# overridden in EE to include additional filtering conditions.
members
diff --git a/app/finders/groups/accepting_project_creations_finder.rb b/app/finders/groups/accepting_project_creations_finder.rb
new file mode 100644
index 00000000000..76463086943
--- /dev/null
+++ b/app/finders/groups/accepting_project_creations_finder.rb
@@ -0,0 +1,101 @@
+# frozen_string_literal: true
+
+module Groups
+ class AcceptingProjectCreationsFinder
+ def initialize(current_user)
+ @current_user = current_user
+ end
+
+ def execute
+ groups_accepting_project_creations =
+ [
+ current_user
+ .manageable_groups(include_groups_with_developer_maintainer_access: true)
+ .project_creation_allowed,
+ owner_maintainer_groups_originating_from_group_shares
+ .project_creation_allowed,
+ *developer_groups_originating_from_group_shares
+ ]
+
+ # We move the UNION query into a materialized CTE to improve query performance during text search.
+ union_query = ::Group.from_union(groups_accepting_project_creations)
+ cte = Gitlab::SQL::CTE.new(:my_union_cte, union_query)
+
+ Group.with(cte.to_arel).from(cte.alias_to(Group.arel_table)) # rubocop: disable CodeReuse/ActiveRecord
+ end
+
+ private
+
+ attr_reader :current_user
+
+ def owner_maintainer_groups_originating_from_group_shares
+ GroupGroupLink
+ .with_owner_or_maintainer_access
+ .groups_accessible_via(
+ groups_that_user_has_owner_or_maintainer_access_via_direct_membership
+ .select(:id)
+ )
+ end
+
+ def groups_that_user_has_owner_or_maintainer_access_via_direct_membership
+ current_user.owned_or_maintainers_groups
+ end
+
+ def developer_groups_originating_from_group_shares
+ # Example:
+ #
+ # Group A -----shared to---> Group B
+ #
+
+ # Now, there are 2 ways a user in Group A can get "Developer" access to Group B (and it's subgroups)
+ [
+ # 1. User has Developer or above access in Group A,
+ # but the group_group_link has MAX access level set to Developer
+ GroupGroupLink
+ .with_developer_access
+ .groups_accessible_via(
+ groups_that_user_has_developer_access_and_above_via_direct_membership
+ .select(:id)
+ ).with_project_creation_levels(project_creations_levels_allowing_developers_to_create_projects),
+
+ # 2. User has exactly Developer access in Group A,
+ # but the group_group_link has MAX access level set to Developer or above.
+ GroupGroupLink
+ .with_developer_maintainer_owner_access
+ .groups_accessible_via(
+ groups_that_user_has_developer_access_via_direct_membership
+ .select(:id)
+ ).with_project_creation_levels(project_creations_levels_allowing_developers_to_create_projects)
+ ]
+
+ # Lastly, we should make sure that such groups indeed allow Developers to create projects in them,
+ # based on the value of `groups.project_creation_level`,
+ # which is why we use the scope .with_project_creation_levels on each set.
+ end
+
+ def groups_that_user_has_developer_access_and_above_via_direct_membership
+ current_user.developer_maintainer_owned_groups
+ end
+
+ def groups_that_user_has_developer_access_via_direct_membership
+ current_user.developer_groups
+ end
+
+ def project_creations_levels_allowing_developers_to_create_projects
+ project_creation_levels = [::Gitlab::Access::DEVELOPER_MAINTAINER_PROJECT_ACCESS]
+
+ # When the value of application_settings.default_project_creation is set to `DEVELOPER_MAINTAINER_PROJECT_ACCESS`,
+ # it means that a `nil` value for `groups.project_creation_level` is telling us:
+ # such groups also have `project_creation_level` implicitly set to `DEVELOPER_MAINTAINER_PROJECT_ACCESS`.
+ # ie, `nil` is a placeholder value for inheriting the value from the ApplicationSetting.
+ # So we will include `nil` in the list,
+ # when the application_setting's value is `DEVELOPER_MAINTAINER_PROJECT_ACCESS`
+
+ if ::Gitlab::CurrentSettings.default_project_creation == ::Gitlab::Access::DEVELOPER_MAINTAINER_PROJECT_ACCESS
+ project_creation_levels << nil
+ end
+
+ project_creation_levels
+ end
+ end
+end
diff --git a/app/finders/groups/accepting_project_imports_finder.rb b/app/finders/groups/accepting_project_imports_finder.rb
new file mode 100644
index 00000000000..55d72edf7bb
--- /dev/null
+++ b/app/finders/groups/accepting_project_imports_finder.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+
+module Groups
+ class AcceptingProjectImportsFinder
+ def initialize(current_user)
+ @current_user = current_user
+ end
+
+ def execute
+ ::Group.from_union(
+ [
+ current_user.manageable_groups,
+ managable_groups_originating_from_group_shares
+ ]
+ )
+ end
+
+ private
+
+ attr_reader :current_user
+
+ def managable_groups_originating_from_group_shares
+ GroupGroupLink
+ .with_owner_or_maintainer_access
+ .groups_accessible_via(
+ current_user.owned_or_maintainers_groups
+ .select(:id)
+ )
+ end
+ end
+end
diff --git a/app/finders/groups/accepting_project_shares_finder.rb b/app/finders/groups/accepting_project_shares_finder.rb
index c4963fcc352..c85e5a0f538 100644
--- a/app/finders/groups/accepting_project_shares_finder.rb
+++ b/app/finders/groups/accepting_project_shares_finder.rb
@@ -25,7 +25,9 @@ module Groups
groups_with_guest_access_plus
end
- groups = groups.search(params[:search]) if params[:search].present?
+ groups = by_hierarchy(groups)
+ groups = by_ignorable(groups)
+ groups = by_search(groups)
sort(groups).with_route
end
@@ -48,5 +50,25 @@ module Groups
Ability.allowed?(current_user, :admin_project, project_to_be_shared) &&
project_to_be_shared.allowed_to_share_with_group?
end
+
+ def by_ignorable(groups)
+ # groups already linked to this project or groups above the project's
+ # current hierarchy needs to be ignored.
+ groups.id_not_in(project_to_be_shared.related_group_ids)
+ end
+
+ def by_hierarchy(groups)
+ return groups if project_to_be_shared.personal? || sharing_outside_hierarchy_allowed?
+
+ groups.id_in(root_ancestor.self_and_descendants_ids)
+ end
+
+ def sharing_outside_hierarchy_allowed?
+ !root_ancestor.prevent_sharing_groups_outside_hierarchy
+ end
+
+ def root_ancestor
+ project_to_be_shared.root_ancestor
+ end
end
end
diff --git a/app/finders/groups/user_groups_finder.rb b/app/finders/groups/user_groups_finder.rb
index b58c1323b1f..536b81b2300 100644
--- a/app/finders/groups/user_groups_finder.rb
+++ b/app/finders/groups/user_groups_finder.rb
@@ -36,9 +36,11 @@ module Groups
def by_permission_scope
if permission_scope_create_projects?
- target_user.manageable_groups(include_groups_with_developer_maintainer_access: true)
+ Groups::AcceptingProjectCreationsFinder.new(target_user).execute # rubocop: disable CodeReuse/Finder
elsif permission_scope_transfer_projects?
Groups::AcceptingProjectTransfersFinder.new(target_user).execute # rubocop: disable CodeReuse/Finder
+ elsif permission_scope_import_projects?
+ Groups::AcceptingProjectImportsFinder.new(target_user).execute # rubocop: disable CodeReuse/Finder
else
target_user.groups
end
@@ -51,5 +53,9 @@ module Groups
def permission_scope_transfer_projects?
params[:permission_scope] == :transfer_projects
end
+
+ def permission_scope_import_projects?
+ params[:permission_scope] == :import_projects
+ end
end
end
diff --git a/app/finders/issuable_finder.rb b/app/finders/issuable_finder.rb
index 159836062cb..478a2ba622c 100644
--- a/app/finders/issuable_finder.rb
+++ b/app/finders/issuable_finder.rb
@@ -43,6 +43,7 @@ class IssuableFinder
include FinderMethods
include CreatedAtFilter
include Gitlab::Utils::StrongMemoize
+ include UpdatedAtFilter
requires_cross_project_access unless: -> { params.project? }
@@ -289,13 +290,6 @@ class IssuableFinder
end
# rubocop: enable CodeReuse/ActiveRecord
- def by_updated_at(items)
- items = items.updated_after(params[:updated_after]) if params[:updated_after].present?
- items = items.updated_before(params[:updated_before]) if params[:updated_before].present?
-
- items
- end
-
def by_closed_at(items)
items = items.closed_after(params[:closed_after]) if params[:closed_after].present?
items = items.closed_before(params[:closed_before]) if params[:closed_before].present?
diff --git a/app/finders/labels_finder.rb b/app/finders/labels_finder.rb
index 9f9d0da6efd..b1387f2a104 100644
--- a/app/finders/labels_finder.rb
+++ b/app/finders/labels_finder.rb
@@ -11,6 +11,11 @@ class LabelsFinder < UnionFinder
def initialize(current_user, params = {})
@current_user = current_user
@params = params
+ # Preload container records (project, group) by default, in some cases we invoke
+ # the LabelsPreloader on the loaded records to prevent all N+1 queries.
+ # In that case we disable the default with_preloaded_container scope because it
+ # interferes with the LabelsPreloader.
+ @preload_parent_association = params.fetch(:preload_parent_association, true)
end
def execute(skip_authorization: false)
@@ -19,7 +24,9 @@ class LabelsFinder < UnionFinder
items = with_title(items)
items = by_subscription(items)
items = by_search(items)
- sort(items.with_preloaded_container)
+
+ items = items.with_preloaded_container if @preload_parent_association
+ sort(items)
end
private
diff --git a/app/finders/members_finder.rb b/app/finders/members_finder.rb
index 1641219a14c..3c0714441b2 100644
--- a/app/finders/members_finder.rb
+++ b/app/finders/members_finder.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
class MembersFinder
- RELATIONS = %i[direct inherited descendants invited_groups].freeze
+ RELATIONS = %i[direct inherited descendants invited_groups shared_into_ancestors].freeze
DEFAULT_RELATIONS = %i[direct inherited].freeze
# Params can be any of the following:
@@ -31,11 +31,7 @@ class MembersFinder
attr_reader :project, :current_user, :group
def find_members(include_relations)
- project_members = if Feature.enabled?(:project_members_index_by_project_namespace, project)
- project.namespace_members
- else
- project.project_members
- end
+ project_members = project.namespace_members
if params[:active_without_invites_and_requests].present?
project_members = project_members.active_without_invites_and_requests
@@ -62,15 +58,20 @@ class MembersFinder
def group_union_members(include_relations)
[].tap do |members|
- members << direct_group_members(include_relations.include?(:descendants)) if group
+ members << direct_group_members(include_relations) if group
members << project_invited_groups if include_relations.include?(:invited_groups)
end
end
- def direct_group_members(include_descendants)
+ def direct_group_members(include_relations)
requested_relations = [:inherited, :direct]
- requested_relations << :descendants if include_descendants
- GroupMembersFinder.new(group).execute(include_relations: requested_relations).non_invite.non_minimal_access # rubocop: disable CodeReuse/Finder
+ requested_relations << :descendants if include_relations.include?(:descendants)
+ requested_relations << :shared_from_groups if include_relations.include?(:shared_into_ancestors)
+
+ GroupMembersFinder.new(group, current_user) # rubocop: disable CodeReuse/Finder
+ .execute(include_relations: requested_relations)
+ .non_invite
+ .non_minimal_access
end
def project_invited_groups
diff --git a/app/finders/merge_requests_finder.rb b/app/finders/merge_requests_finder.rb
index ffa912afd1e..f1c5d5e08ad 100644
--- a/app/finders/merge_requests_finder.rb
+++ b/app/finders/merge_requests_finder.rb
@@ -36,6 +36,7 @@ class MergeRequestsFinder < IssuableFinder
def self.scalar_params
@scalar_params ||= super + [
+ :approved,
:approved_by_ids,
:deployed_after,
:deployed_before,
@@ -71,8 +72,9 @@ class MergeRequestsFinder < IssuableFinder
items = by_approvals(items)
items = by_deployments(items)
items = by_reviewer(items)
+ items = by_source_project_id(items)
- by_source_project_id(items)
+ by_approved(items)
end
def filter_negated_items(items)
@@ -183,6 +185,17 @@ class MergeRequestsFinder < IssuableFinder
end
# rubocop: enable CodeReuse/Finder
+ def by_approved(items)
+ approved_param = Gitlab::Utils.to_boolean(params.fetch(:approved, nil))
+ return items if approved_param.nil? || Feature.disabled?(:mr_approved_filter, type: :ops)
+
+ if approved_param
+ items.with_approvals
+ else
+ items.without_approvals
+ end
+ end
+
def by_deployments(items)
env = params[:environment]
before = parse_datetime(params[:deployed_before])
diff --git a/app/finders/merge_requests_finder/params.rb b/app/finders/merge_requests_finder/params.rb
index e44e96054d3..2c218898dcf 100644
--- a/app/finders/merge_requests_finder/params.rb
+++ b/app/finders/merge_requests_finder/params.rb
@@ -16,8 +16,6 @@ class MergeRequestsFinder
User.find_by_id(params[:reviewer_id])
elsif reviewer_username?
User.find_by_username(params[:reviewer_username])
- else
- nil
end
end
end
diff --git a/app/finders/milestones_finder.rb b/app/finders/milestones_finder.rb
index 5fe55e88086..9ffd623338f 100644
--- a/app/finders/milestones_finder.rb
+++ b/app/finders/milestones_finder.rb
@@ -15,6 +15,7 @@
class MilestonesFinder
include FinderMethods
include TimeFrameFilter
+ include UpdatedAtFilter
attr_reader :params
@@ -30,9 +31,12 @@ class MilestonesFinder
items = by_groups_and_projects(items)
items = by_title(items)
items = by_search_title(items)
+ items = by_search(items)
items = by_state(items)
items = by_timeframe(items)
items = containing_date(items)
+ items = by_updated_at(items)
+ items = by_iids(items)
order(items)
end
@@ -67,6 +71,12 @@ class MilestonesFinder
end
end
+ def by_search(items)
+ return items if params[:search].blank?
+
+ items.search(params[:search])
+ end
+
def by_state(items)
Milestone.filter_by_state(items, params[:state])
end
@@ -84,4 +94,10 @@ class MilestonesFinder
def sort_by_expired_last?(sort_by)
EXPIRED_LAST_SORTS.include?(sort_by)
end
+
+ def by_iids(items)
+ return items unless params[:iids].present? && !params[:include_parent_milestones]
+
+ items.by_iid(params[:iids])
+ end
end
diff --git a/app/finders/notes_finder.rb b/app/finders/notes_finder.rb
index 81017290f12..3d764f67990 100644
--- a/app/finders/notes_finder.rb
+++ b/app/finders/notes_finder.rb
@@ -31,6 +31,7 @@ class NotesFinder
notes = since_fetch_at(notes)
notes = notes.with_notes_filter(@params[:notes_filter]) if notes_filter?
notes = redact_internal(notes)
+ notes = notes.without_hidden if without_hidden_notes?
sort(notes)
end
@@ -189,6 +190,13 @@ class NotesFinder
notes.not_internal
end
+
+ def without_hidden_notes?
+ return false unless Feature.enabled?(:hidden_notes)
+ return false if @current_user&.can_admin_all_resources?
+
+ true
+ end
end
NotesFinder.prepend_mod_with('NotesFinder')
diff --git a/app/finders/packages/conan/package_finder.rb b/app/finders/packages/conan/package_finder.rb
index 210b37635b3..161a3d0d409 100644
--- a/app/finders/packages/conan/package_finder.rb
+++ b/app/finders/packages/conan/package_finder.rb
@@ -3,25 +3,43 @@
module Packages
module Conan
class PackageFinder
- attr_reader :current_user, :query
+ MAX_PACKAGES_COUNT = 500
- def initialize(current_user, params)
+ def initialize(current_user, params, project: nil)
@current_user = current_user
@query = params[:query]
+ @project = project
end
def execute
- packages_for_current_user.installable.with_name_like(query).order_name_asc if query
+ return ::Packages::Package.none unless query
+
+ packages
end
private
+ attr_reader :current_user, :query, :project
+
def packages
- Packages::Package.conan
+ base
+ .conan
+ .installable
+ .preload_conan_metadatum
+ .with_name_like(query)
+ .limit_recent(MAX_PACKAGES_COUNT)
+ end
+
+ def base
+ project ? packages_of_project : packages_for_current_user
+ end
+
+ def packages_of_project
+ project.packages
end
def packages_for_current_user
- packages.for_projects(projects_visible_to_current_user)
+ Packages::Package.for_projects(projects_visible_to_current_user)
end
def projects_visible_to_current_user
diff --git a/app/finders/packages/npm/package_finder.rb b/app/finders/packages/npm/package_finder.rb
index a367fda37de..953e8299138 100644
--- a/app/finders/packages/npm/package_finder.rb
+++ b/app/finders/packages/npm/package_finder.rb
@@ -21,7 +21,11 @@ module Packages
return result unless @last_of_each_version
- result.last_of_each_version
+ if Feature.enabled?(:npm_allow_packages_in_multiple_projects)
+ Packages::Package.id_in(result.last_of_each_version_ids)
+ else
+ result.last_of_each_version
+ end
end
private
diff --git a/app/finders/pending_todos_finder.rb b/app/finders/pending_todos_finder.rb
index babff65cc37..a1a72840236 100644
--- a/app/finders/pending_todos_finder.rb
+++ b/app/finders/pending_todos_finder.rb
@@ -13,24 +13,36 @@
class PendingTodosFinder
attr_reader :users, :params
- # users - The list of users to retrieve the todos for.
+ # users - The list of users to retrieve the todos for. If nil is passed, it won't filter todos based on users
# params - A Hash containing columns and values to use for filtering todos.
- def initialize(users, params = {})
- @users = users
+ def initialize(params = {})
@params = params
+
+ # To prevent N+1 queries when fetching the users of the PendingTodos.
+ @preload_user_association = params.fetch(:preload_user_association, false)
end
def execute
- todos = Todo.for_user(users)
- todos = todos.pending
+ todos = Todo.pending
+ todos = by_users(todos)
todos = by_project(todos)
todos = by_target_id(todos)
todos = by_target_type(todos)
+ todos = by_author_id(todos)
todos = by_discussion(todos)
todos = by_commit_id(todos)
+
+ todos = todos.with_preloaded_user if @preload_user_association
+
by_action(todos)
end
+ def by_users(todos)
+ return todos unless params[:users].present?
+
+ todos.for_user(params[:users])
+ end
+
def by_project(todos)
if (id = params[:project_id])
todos.for_project(id)
@@ -55,6 +67,12 @@ class PendingTodosFinder
end
end
+ def by_author_id(todos)
+ return todos unless params[:author_id]
+
+ todos.for_author(params[:author_id])
+ end
+
def by_commit_id(todos)
if (id = params[:commit_id])
todos.for_commit(id)
diff --git a/app/finders/projects_finder.rb b/app/finders/projects_finder.rb
index 401bc473216..57a9538db15 100644
--- a/app/finders/projects_finder.rb
+++ b/app/finders/projects_finder.rb
@@ -31,6 +31,7 @@
#
class ProjectsFinder < UnionFinder
include CustomAttributesFilter
+ include UpdatedAtFilter
attr_accessor :params
attr_reader :current_user, :project_ids_relation
@@ -87,6 +88,7 @@ class ProjectsFinder < UnionFinder
collection = by_last_activity_before(collection)
collection = by_language(collection)
collection = by_feature_availability(collection)
+ collection = by_updated_at(collection)
by_repository_storage(collection)
end
diff --git a/app/finders/security/security_jobs_finder.rb b/app/finders/security/security_jobs_finder.rb
index 5754492cfa7..8cfb699a62a 100644
--- a/app/finders/security/security_jobs_finder.rb
+++ b/app/finders/security/security_jobs_finder.rb
@@ -13,7 +13,7 @@
module Security
class SecurityJobsFinder < JobsFinder
def self.allowed_job_types
- [:sast, :sast_iac, :dast, :dependency_scanning, :container_scanning, :secret_detection, :coverage_fuzzing, :api_fuzzing, :cluster_image_scanning]
+ [:sast, :sast_iac, :breach_and_attack_simulation, :dast, :dependency_scanning, :container_scanning, :secret_detection, :coverage_fuzzing, :api_fuzzing, :cluster_image_scanning]
end
end
end
diff --git a/app/finders/serverless_domain_finder.rb b/app/finders/serverless_domain_finder.rb
deleted file mode 100644
index 661cd0ca363..00000000000
--- a/app/finders/serverless_domain_finder.rb
+++ /dev/null
@@ -1,35 +0,0 @@
-# frozen_string_literal: true
-
-class ServerlessDomainFinder
- attr_reader :match, :serverless_domain_cluster, :environment
-
- def initialize(uri)
- @match = ::Serverless::Domain::REGEXP.match(uri)
- end
-
- def execute
- return unless serverless?
-
- @serverless_domain_cluster = ::Serverless::DomainCluster.for_uuid(serverless_domain_cluster_uuid)
- return unless serverless_domain_cluster&.knative&.external_ip
-
- @environment = ::Environment.for_id_and_slug(match[:environment_id].to_i(16), match[:environment_slug])
- return unless environment
-
- ::Serverless::Domain.new(
- function_name: match[:function_name],
- serverless_domain_cluster: serverless_domain_cluster,
- environment: environment
- )
- end
-
- def serverless_domain_cluster_uuid
- return unless serverless?
-
- match[:cluster_left] + match[:cluster_middle] + match[:cluster_right]
- end
-
- def serverless?
- !!match
- end
-end
diff --git a/app/finders/snippets_finder.rb b/app/finders/snippets_finder.rb
index bf20a2c2c3d..9dd7e508c22 100644
--- a/app/finders/snippets_finder.rb
+++ b/app/finders/snippets_finder.rb
@@ -179,8 +179,6 @@ class SnippetsFinder < UnionFinder
Snippet::INTERNAL
when 'are_public'
Snippet::PUBLIC
- else
- nil
end
end
diff --git a/app/finders/template_finder.rb b/app/finders/template_finder.rb
index b82b601541c..c6c5c30cbf7 100644
--- a/app/finders/template_finder.rb
+++ b/app/finders/template_finder.rb
@@ -16,16 +16,27 @@ class TemplateFinder
def build(type, project, params = {})
if type.to_s == 'licenses'
LicenseTemplateFinder.new(project, params) # rubocop: disable CodeReuse/Finder
- else
+ elsif type_allowed?(type)
new(type, project, params)
end
end
def all_template_names(project, type)
- return {} if !VENDORED_TEMPLATES.key?(type.to_s) && type.to_s != 'licenses'
+ return {} unless type_allowed?(type)
build(type, project).template_names
end
+
+ def type_allowed?(type)
+ case type.to_s
+ when 'licenses'
+ true
+ when 'metrics_dashboard_ymls'
+ !Feature.enabled?(:remove_monitor_metrics)
+ else
+ VENDORED_TEMPLATES.key?(type)
+ end
+ end
end
attr_reader :type, :project, :params