diff options
Diffstat (limited to 'app/finders')
-rw-r--r-- | app/finders/context_commits_finder.rb | 11 | ||||
-rw-r--r-- | app/finders/crm/organizations_finder.rb | 16 | ||||
-rw-r--r-- | app/finders/database/batched_background_migrations_finder.rb | 27 | ||||
-rw-r--r-- | app/finders/deployments_finder.rb | 47 | ||||
-rw-r--r-- | app/finders/environments/environments_finder.rb | 7 | ||||
-rw-r--r-- | app/finders/group_members_finder.rb | 2 | ||||
-rw-r--r-- | app/finders/groups/accepting_group_transfers_finder.rb | 69 | ||||
-rw-r--r-- | app/finders/groups/accepting_project_transfers_finder.rb | 4 | ||||
-rw-r--r-- | app/finders/groups/base.rb | 17 | ||||
-rw-r--r-- | app/finders/groups/user_groups_finder.rb | 12 | ||||
-rw-r--r-- | app/finders/groups_finder.rb | 36 | ||||
-rw-r--r-- | app/finders/incident_management/timeline_events_finder.rb | 2 | ||||
-rw-r--r-- | app/finders/issuable_finder.rb | 29 | ||||
-rw-r--r-- | app/finders/issues_finder.rb | 4 | ||||
-rw-r--r-- | app/finders/merge_requests/by_approvals_finder.rb | 4 | ||||
-rw-r--r-- | app/finders/merge_requests_finder.rb | 28 | ||||
-rw-r--r-- | app/finders/merge_requests_finder/params.rb | 6 | ||||
-rw-r--r-- | app/finders/projects_finder.rb | 4 | ||||
-rw-r--r-- | app/finders/user_groups_counter.rb | 6 |
19 files changed, 251 insertions, 80 deletions
diff --git a/app/finders/context_commits_finder.rb b/app/finders/context_commits_finder.rb index d623854ada4..4a45817cc61 100644 --- a/app/finders/context_commits_finder.rb +++ b/app/finders/context_commits_finder.rb @@ -5,8 +5,10 @@ class ContextCommitsFinder @project = project @merge_request = merge_request @search = params[:search] + @author = params[:author] + @committed_before = params[:committed_before] + @committed_after = params[:committed_after] @limit = (params[:limit] || 40).to_i - @offset = (params[:offset] || 0).to_i end def execute @@ -16,13 +18,13 @@ class ContextCommitsFinder private - attr_reader :project, :merge_request, :search, :limit, :offset + attr_reader :project, :merge_request, :search, :author, :committed_before, :committed_after, :limit def init_collection if search.present? search_commits else - project.repository.commits(merge_request.target_branch, { limit: limit, offset: offset }) + project.repository.commits(merge_request.target_branch, { limit: limit }) end end @@ -41,7 +43,8 @@ class ContextCommitsFinder commits = [commit_by_sha] if commit_by_sha end else - commits = project.repository.find_commits_by_message(search, merge_request.target_branch, nil, 20) + commits = project.repository.list_commits_by(search, merge_request.target_branch, + author: author, before: committed_before, after: committed_after, limit: limit) end commits diff --git a/app/finders/crm/organizations_finder.rb b/app/finders/crm/organizations_finder.rb index 5a8ab148ef3..69f72235c71 100644 --- a/app/finders/crm/organizations_finder.rb +++ b/app/finders/crm/organizations_finder.rb @@ -16,6 +16,11 @@ module Crm attr_reader :params, :current_user + def self.counts_by_state(current_user, params = {}) + params = params.merge(sort: nil) + new(current_user, params).execute.counts_by_state + end + def initialize(current_user, params = {}) @current_user = current_user @params = params @@ -28,11 +33,20 @@ module Crm organizations = by_ids(organizations) organizations = by_search(organizations) organizations = by_state(organizations) - organizations.sort_by_name + sort_organizations(organizations) end private + def sort_organizations(organizations) + return organizations.sort_by_name unless @params.key?(:sort) + return organizations if @params[:sort].nil? + + field = @params[:sort][:field] + direction = @params[:sort][:direction] + organizations.sort_by_field(field, direction) + end + def root_group strong_memoize(:root_group) do group = params[:group]&.root_ancestor diff --git a/app/finders/database/batched_background_migrations_finder.rb b/app/finders/database/batched_background_migrations_finder.rb new file mode 100644 index 00000000000..866acd47238 --- /dev/null +++ b/app/finders/database/batched_background_migrations_finder.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +module Database + class BatchedBackgroundMigrationsFinder + RETURNED_MIGRATIONS = 20 + + def initialize(connection:) + @connection = connection + end + + def execute + batched_migration_class.ordered_by_created_at_desc.for_gitlab_schema(schema).limit(RETURNED_MIGRATIONS) + end + + private + + attr_accessor :connection + + def batched_migration_class + Gitlab::Database::BackgroundMigration::BatchedMigration + end + + def schema + Gitlab::Database.gitlab_schemas_for_connection(connection) + end + end +end diff --git a/app/finders/deployments_finder.rb b/app/finders/deployments_finder.rb index 04b82ee04ec..5b2139cb941 100644 --- a/app/finders/deployments_finder.rb +++ b/app/finders/deployments_finder.rb @@ -9,8 +9,8 @@ # updated_before: DateTime # finished_after: DateTime # finished_before: DateTime -# environment: String -# status: String (see Deployment.statuses) +# environment: String (name) or Integer (ID) +# status: String or Array<String> (see Deployment.statuses) # order_by: String (see ALLOWED_SORT_VALUES constant) # sort: String (asc | desc) class DeploymentsFinder @@ -33,6 +33,7 @@ class DeploymentsFinder def initialize(params = {}) @params = params + @params[:status] = Array(@params[:status]).map(&:to_s) if @params[:status] validate! end @@ -68,16 +69,25 @@ class DeploymentsFinder raise error if raise_for_inefficient_updated_at_query? end - if (filter_by_finished_at? && !order_by_finished_at?) || (!filter_by_finished_at? && order_by_finished_at?) - raise InefficientQueryError, '`finished_at` filter and `finished_at` sorting must be paired' + if filter_by_finished_at? && !order_by_finished_at? + raise InefficientQueryError, '`finished_at` filter requires `finished_at` sort.' + end + + if order_by_finished_at? && !(filter_by_finished_at? || filter_by_finished_statuses?) + raise InefficientQueryError, + '`finished_at` sort requires `finished_at` filter or a filter with at least one of the finished statuses.' end if filter_by_finished_at? && !filter_by_successful_deployment? raise InefficientQueryError, '`finished_at` filter must be combined with `success` status filter.' end - if params[:environment].present? && !params[:project].present? - raise InefficientQueryError, '`environment` filter must be combined with `project` scope.' + if filter_by_environment_name? && !params[:project].present? + raise InefficientQueryError, '`environment` name filter must be combined with `project` scope.' + end + + if filter_by_finished_statuses? && filter_by_upcoming_statuses? + raise InefficientQueryError, 'finished statuses and upcoming statuses must be separately queried.' end end @@ -86,6 +96,8 @@ class DeploymentsFinder params[:project].deployments elsif params[:group].present? ::Deployment.for_projects(params[:group].all_projects) + elsif filter_by_environment_id? + ::Deployment.for_environment(params[:environment]) else ::Deployment.none end @@ -112,7 +124,7 @@ class DeploymentsFinder end def by_environment(items) - if params[:project].present? && params[:environment].present? + if params[:project].present? && filter_by_environment_name? items.for_environment_name(params[:project], params[:environment]) else items @@ -122,7 +134,7 @@ class DeploymentsFinder def by_status(items) return items unless params[:status].present? - unless Deployment.statuses.key?(params[:status]) + unless Deployment.statuses.keys.intersection(params[:status]) == params[:status] raise ArgumentError, "The deployment status #{params[:status]} is invalid" end @@ -165,7 +177,23 @@ class DeploymentsFinder end def filter_by_successful_deployment? - params[:status].to_s == 'success' + params[:status].present? && params[:status].count == 1 && params[:status].first.to_s == 'success' + end + + def filter_by_finished_statuses? + params[:status].present? && Deployment::FINISHED_STATUSES.map(&:to_s).intersection(params[:status]).any? + end + + def filter_by_upcoming_statuses? + params[:status].present? && Deployment::UPCOMING_STATUSES.map(&:to_s).intersection(params[:status]).any? + end + + def filter_by_environment_name? + params[:environment].present? && params[:environment].is_a?(String) + end + + def filter_by_environment_id? + params[:environment].present? && params[:environment].is_a?(Integer) end def order_by_updated_at? @@ -183,6 +211,7 @@ class DeploymentsFinder environment: [], deployable: { job_artifacts: [], + user: [], pipeline: { project: { route: [], diff --git a/app/finders/environments/environments_finder.rb b/app/finders/environments/environments_finder.rb index 46c49f096c6..f2dcba04349 100644 --- a/app/finders/environments/environments_finder.rb +++ b/app/finders/environments/environments_finder.rb @@ -14,6 +14,7 @@ module Environments def execute environments = project.environments + environments = by_type(environments) environments = by_name(environments) environments = by_search(environments) environments = by_ids(environments) @@ -24,6 +25,12 @@ module Environments private + def by_type(environments) + return environments unless params[:type].present? + + environments.for_type(params[:type]) + end + def by_name(environments) if params[:name].present? environments.for_name(params[:name]) diff --git a/app/finders/group_members_finder.rb b/app/finders/group_members_finder.rb index 048e25046da..4688d561897 100644 --- a/app/finders/group_members_finder.rb +++ b/app/finders/group_members_finder.rb @@ -47,7 +47,7 @@ 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_with_groups.public_or_visible_to_user(user) if include_relations&.include?(:shared_from_groups) + 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) end diff --git a/app/finders/groups/accepting_group_transfers_finder.rb b/app/finders/groups/accepting_group_transfers_finder.rb new file mode 100644 index 00000000000..df67f940d20 --- /dev/null +++ b/app/finders/groups/accepting_group_transfers_finder.rb @@ -0,0 +1,69 @@ +# frozen_string_literal: true + +module Groups + class AcceptingGroupTransfersFinder < Base + include Gitlab::Utils::StrongMemoize + + def initialize(current_user, group_to_be_transferred, params = {}) + @current_user = current_user + @group_to_be_transferred = group_to_be_transferred + @params = params + end + + def execute + return Group.none unless can_transfer_group? + + items = if Feature.enabled?(:include_groups_from_group_shares_in_group_transfer_locations) + find_all_groups + else + find_groups + end + + items = by_search(items) + + sort(items) + end + + private + + attr_reader :current_user, :group_to_be_transferred, :params + + def find_groups + GroupsFinder.new( # rubocop: disable CodeReuse/Finder + current_user, + min_access_level: Gitlab::Access::OWNER, + exclude_group_ids: exclude_groups + ).execute.without_order + end + + def find_all_groups + ::Namespace.from_union( + [ + find_groups, + groups_originating_from_group_shares_with_owner_access + ] + ) + end + + def groups_originating_from_group_shares_with_owner_access + GroupGroupLink + .with_owner_access + .groups_accessible_via( + current_user.owned_groups.select(:id) + ).id_not_in(exclude_groups) + end + + def exclude_groups + strong_memoize(:exclude_groups) do + exclude_groups = group_to_be_transferred.self_and_descendants.pluck_primary_key + exclude_groups << group_to_be_transferred.parent_id if group_to_be_transferred.parent_id + + exclude_groups + end + end + + def can_transfer_group? + Ability.allowed?(current_user, :admin_group, group_to_be_transferred) + end + end +end diff --git a/app/finders/groups/accepting_project_transfers_finder.rb b/app/finders/groups/accepting_project_transfers_finder.rb index 09d3c430641..a3f58a78eca 100644 --- a/app/finders/groups/accepting_project_transfers_finder.rb +++ b/app/finders/groups/accepting_project_transfers_finder.rb @@ -7,10 +7,6 @@ module Groups end def execute - if Feature.disabled?(:include_groups_from_group_shares_in_project_transfer_locations) - return current_user.manageable_groups - end - groups_accepting_project_transfers = [ current_user.manageable_groups, diff --git a/app/finders/groups/base.rb b/app/finders/groups/base.rb new file mode 100644 index 00000000000..d7f56b1a7a6 --- /dev/null +++ b/app/finders/groups/base.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +module Groups + class Base + private + + def sort(items) + items.order(Group.arel_table[:path].asc, Group.arel_table[:id].asc) # rubocop: disable CodeReuse/ActiveRecord + end + + def by_search(items) + return items if params[:search].blank? + + items.search(params[:search], include_parents: true) + end + end +end diff --git a/app/finders/groups/user_groups_finder.rb b/app/finders/groups/user_groups_finder.rb index bda8b7cc1e0..b58c1323b1f 100644 --- a/app/finders/groups/user_groups_finder.rb +++ b/app/finders/groups/user_groups_finder.rb @@ -13,7 +13,7 @@ # # Initially created to filter user groups and descendants where the user can create projects module Groups - class UserGroupsFinder + class UserGroupsFinder < Base def initialize(current_user, target_user, params = {}) @current_user = current_user @target_user = target_user @@ -34,16 +34,6 @@ module Groups attr_reader :current_user, :target_user, :params - def sort(items) - items.order(Group.arel_table[:path].asc, Group.arel_table[:id].asc) # rubocop: disable CodeReuse/ActiveRecord - end - - def by_search(items) - return items if params[:search].blank? - - items.search(params[:search], include_parents: true) - end - def by_permission_scope if permission_scope_create_projects? target_user.manageable_groups(include_groups_with_developer_maintainer_access: true) diff --git a/app/finders/groups_finder.rb b/app/finders/groups_finder.rb index 9a8bc74f435..61d79885001 100644 --- a/app/finders/groups_finder.rb +++ b/app/finders/groups_finder.rb @@ -15,6 +15,7 @@ # exclude_group_ids: array of integers # include_parent_descendants: boolean (defaults to false) - includes descendant groups when # filtering by parent. The parent param must be present. +# include_ancestors: boolean (defaults to true) # # Users with full private access can see all groups. The `owned` and `parent` # params can be used to restrict the groups that are returned. @@ -52,15 +53,7 @@ class GroupsFinder < UnionFinder return [Group.all] if current_user&.can_read_all_resources? && all_available? groups = [] - - if current_user - if Feature.enabled?(:use_traversal_ids_groups_finder, current_user) - groups << current_user.authorized_groups.self_and_ancestors - groups << current_user.groups.self_and_descendants - else - groups << Gitlab::ObjectHierarchy.new(groups_for_ancestors, groups_for_descendants).all_objects - end - end + groups = get_groups_for_user if current_user groups << Group.unscoped.public_to_user(current_user) if include_public_groups? groups << Group.none if groups.empty? @@ -136,4 +129,29 @@ class GroupsFinder < UnionFinder def min_access_level? current_user && params[:min_access_level].present? end + + def include_ancestors? + params.fetch(:include_ancestors, true) + end + + def get_groups_for_user + groups = [] + + if Feature.enabled?(:use_traversal_ids_groups_finder, current_user) + groups << if include_ancestors? + current_user.authorized_groups.self_and_ancestors + else + current_user.authorized_groups + end + + groups << current_user.groups.self_and_descendants + elsif include_ancestors? + groups << Gitlab::ObjectHierarchy.new(groups_for_ancestors, groups_for_descendants).all_objects + else + groups << current_user.authorized_groups + groups << Gitlab::ObjectHierarchy.new(groups_for_descendants).base_and_descendants + end + + groups + end end diff --git a/app/finders/incident_management/timeline_events_finder.rb b/app/finders/incident_management/timeline_events_finder.rb index 09de46bb79f..aaf3133236a 100644 --- a/app/finders/incident_management/timeline_events_finder.rb +++ b/app/finders/incident_management/timeline_events_finder.rb @@ -31,7 +31,7 @@ module IncidentManagement end def sort(collection) - collection.order_occurred_at_asc + collection.order_occurred_at_asc_id_asc end end end diff --git a/app/finders/issuable_finder.rb b/app/finders/issuable_finder.rb index 1088d53c9a0..9f331d381aa 100644 --- a/app/finders/issuable_finder.rb +++ b/app/finders/issuable_finder.rb @@ -46,8 +46,7 @@ class IssuableFinder requires_cross_project_access unless: -> { params.project? } - FULL_TEXT_SEARCH_TERM_PATTERN = '[\u0000-\u218F]*' - FULL_TEXT_SEARCH_TERM_REGEX = /\A#{FULL_TEXT_SEARCH_TERM_PATTERN}\z/.freeze + FULL_TEXT_SEARCH_TERM_REGEX = /\A[\p{ASCII}|\p{Latin}]+\z/.freeze NEGATABLE_PARAMS_HELPER_KEYS = %i[project_id scope status include_subgroups].freeze attr_accessor :current_user, :params @@ -59,19 +58,19 @@ class IssuableFinder class << self def scalar_params @scalar_params ||= %i[ - assignee_id - assignee_username - author_id - author_username - crm_contact_id - crm_organization_id - label_name - milestone_title - release_tag - my_reaction_emoji - search - in - ] + assignee_id + assignee_username + author_id + author_username + crm_contact_id + crm_organization_id + label_name + milestone_title + release_tag + my_reaction_emoji + search + in + ] end def array_params diff --git a/app/finders/issues_finder.rb b/app/finders/issues_finder.rb index 663dda73a6a..9f96abcd4e5 100644 --- a/app/finders/issues_finder.rb +++ b/app/finders/issues_finder.rb @@ -60,10 +60,10 @@ class IssuesFinder < IssuableFinder # count of issues assigned to the user for the header bar. return issues.all if current_user && assignee_filter.includes_user?(current_user) - return issues.where('issues.confidential IS NOT TRUE') if params.user_cannot_see_confidential_issues? + return issues.public_only if params.user_cannot_see_confidential_issues? issues.where(' - issues.confidential IS NOT TRUE + issues.confidential = FALSE OR (issues.confidential = TRUE AND (issues.author_id = :user_id OR EXISTS (SELECT TRUE FROM issue_assignees WHERE user_id = :user_id AND issue_id = issues.id) diff --git a/app/finders/merge_requests/by_approvals_finder.rb b/app/finders/merge_requests/by_approvals_finder.rb index 94f13468327..8b2e9aa8df1 100644 --- a/app/finders/merge_requests/by_approvals_finder.rb +++ b/app/finders/merge_requests/by_approvals_finder.rb @@ -71,9 +71,7 @@ module MergeRequests # # @param [ActiveRecord::Relation] items the activerecord relation def with_any_approvals(items) - items.select_from_union([ - items.with_approvals - ]) + items.select_from_union([items.with_approvals]) end # Merge requests approved by given usernames diff --git a/app/finders/merge_requests_finder.rb b/app/finders/merge_requests_finder.rb index 06feefb9059..ffa912afd1e 100644 --- a/app/finders/merge_requests_finder.rb +++ b/app/finders/merge_requests_finder.rb @@ -30,6 +30,8 @@ # updated_before: datetime # class MergeRequestsFinder < IssuableFinder + extend ::Gitlab::Utils::Override + include MergedAtFilter def self.scalar_params @@ -44,8 +46,7 @@ class MergeRequestsFinder < IssuableFinder :reviewer_id, :reviewer_username, :target_branch, - :wip, - :attention + :wip ] end @@ -70,7 +71,6 @@ class MergeRequestsFinder < IssuableFinder items = by_approvals(items) items = by_deployments(items) items = by_reviewer(items) - items = by_attention(items) by_source_project_id(items) end @@ -84,6 +84,16 @@ class MergeRequestsFinder < IssuableFinder private + override :sort + def sort(items) + items = super(items) + + return items unless use_grouping_columns? + + grouping_columns = klass.grouping_columns(params[:sort]) + items.group(grouping_columns) # rubocop:disable CodeReuse/ActiveRecord + end + def by_commit(items) return items unless params[:commit_sha].presence @@ -220,18 +230,18 @@ class MergeRequestsFinder < IssuableFinder end end - def by_attention(items) - return items unless params.attention? - - items.attention(params.attention) - end - def parse_datetime(input) # To work around http://www.ruby-lang.org/en/news/2021/11/15/date-parsing-method-regexp-dos-cve-2021-41817/ DateTime.parse(input.byteslice(0, 128)) if input rescue Date::Error nil end + + def use_grouping_columns? + return false unless params[:sort].present? + + params[:approved_by_usernames].present? || params[:approved_by_ids].present? + end end MergeRequestsFinder.prepend_mod_with('MergeRequestsFinder') diff --git a/app/finders/merge_requests_finder/params.rb b/app/finders/merge_requests_finder/params.rb index 1c6a425c8af..e44e96054d3 100644 --- a/app/finders/merge_requests_finder/params.rb +++ b/app/finders/merge_requests_finder/params.rb @@ -21,11 +21,5 @@ class MergeRequestsFinder end end end - - def attention - strong_memoize(:attention) do - User.find_by_username(params[:attention]) - end - end end end diff --git a/app/finders/projects_finder.rb b/app/finders/projects_finder.rb index 6b8dcd61d29..6bfe730ebc9 100644 --- a/app/finders/projects_finder.rb +++ b/app/finders/projects_finder.rb @@ -119,9 +119,9 @@ class ProjectsFinder < UnionFinder # This is an optimization - surprisingly PostgreSQL does not optimize # for this. # - # If the default visiblity level and desired visiblity level filter cancels + # If the default visibility level and desired visibility level filter cancels # each other out, don't use the SQL clause for visibility level in - # `Project.public_or_visible_to_user`. In fact, this then becames equivalent + # `Project.public_or_visible_to_user`. In fact, this then becomes equivalent # to just authorized projects for the user. # # E.g. diff --git a/app/finders/user_groups_counter.rb b/app/finders/user_groups_counter.rb index 7dbc8502be2..e8e552510cd 100644 --- a/app/finders/user_groups_counter.rb +++ b/app/finders/user_groups_counter.rb @@ -8,9 +8,9 @@ class UserGroupsCounter def execute Namespace.unscoped do Namespace.from_union([ - groups, - project_groups - ]).group(:user_id).count # rubocop: disable CodeReuse/ActiveRecord + groups, + project_groups + ]).group(:user_id).count # rubocop: disable CodeReuse/ActiveRecord end end |