diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2022-06-20 14:10:13 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2022-06-20 14:10:13 +0300 |
commit | 0ea3fcec397b69815975647f5e2aa5fe944a8486 (patch) | |
tree | 7979381b89d26011bcf9bdc989a40fcc2f1ed4ff /app/graphql/resolvers | |
parent | 72123183a20411a36d607d70b12d57c484394c8e (diff) |
Add latest changes from gitlab-org/gitlab@15-1-stable-eev15.1.0-rc42
Diffstat (limited to 'app/graphql/resolvers')
17 files changed, 231 insertions, 34 deletions
diff --git a/app/graphql/resolvers/base_issues_resolver.rb b/app/graphql/resolvers/base_issues_resolver.rb index a1fda976876..ec47a8996eb 100644 --- a/app/graphql/resolvers/base_issues_resolver.rb +++ b/app/graphql/resolvers/base_issues_resolver.rb @@ -33,13 +33,6 @@ module Resolvers end end - def prepare_params(args, parent) - return unless [:escalation_status_asc, :escalation_status_desc].include?(args[:sort]) - return if Feature.enabled?(:incident_escalations, parent) - - args[:sort] = :created_desc # default for sort argument - end - private def unconditional_includes diff --git a/app/graphql/resolvers/ci/runner_owner_project_resolver.rb b/app/graphql/resolvers/ci/runner_owner_project_resolver.rb new file mode 100644 index 00000000000..14b5f8f90eb --- /dev/null +++ b/app/graphql/resolvers/ci/runner_owner_project_resolver.rb @@ -0,0 +1,65 @@ +# frozen_string_literal: true + +module Resolvers + module Ci + class RunnerOwnerProjectResolver < BaseResolver + include LooksAhead + + type Types::ProjectType, null: true + + alias_method :runner, :object + + def resolve_with_lookahead(**args) + resolve_owner + end + + def preloads + { + full_path: [:route] + } + end + + def filtered_preloads + selection = lookahead + + preloads.each.flat_map do |name, requirements| + selection&.selects?(name) ? requirements : [] + end + end + + private + + def resolve_owner + return unless runner.project_type? + + BatchLoader::GraphQL.for(runner.id).batch(key: :runner_owner_projects) do |runner_ids, loader| + # rubocop: disable CodeReuse/ActiveRecord + runner_and_projects_with_row_number = + ::Ci::RunnerProject + .where(runner_id: runner_ids) + .select('id, runner_id, project_id, ROW_NUMBER() OVER (PARTITION BY runner_id ORDER BY id ASC)') + runner_and_owner_projects = + ::Ci::RunnerProject + .select(:id, :runner_id, :project_id) + .from("(#{runner_and_projects_with_row_number.to_sql}) temp WHERE row_number = 1") + owner_project_id_by_runner_id = + runner_and_owner_projects + .group_by(&:runner_id) + .transform_values { |runner_projects| runner_projects.first.project_id } + project_ids = owner_project_id_by_runner_id.values.uniq + + all_preloads = unconditional_includes + filtered_preloads + owner_relation = Project.all + owner_relation = owner_relation.preload(*all_preloads) if all_preloads.any? + projects = owner_relation.where(id: project_ids).index_by(&:id) + + runner_ids.each do |runner_id| + owner_project_id = owner_project_id_by_runner_id[runner_id] + loader.call(runner_id, projects[owner_project_id]) + end + # rubocop: enable CodeReuse/ActiveRecord + end + end + end + end +end diff --git a/app/graphql/resolvers/clusters/agent_tokens_resolver.rb b/app/graphql/resolvers/clusters/agent_tokens_resolver.rb index 722fbab3bb7..9740bc6bb6a 100644 --- a/app/graphql/resolvers/clusters/agent_tokens_resolver.rb +++ b/app/graphql/resolvers/clusters/agent_tokens_resolver.rb @@ -16,7 +16,7 @@ module Resolvers def resolve(**args) return ::Clusters::AgentToken.none unless can_read_agent_tokens? - tokens = agent.last_used_agent_tokens + tokens = agent.agent_tokens tokens = tokens.with_status(args[:status]) if args[:status].present? tokens diff --git a/app/graphql/resolvers/clusters/agents_resolver.rb b/app/graphql/resolvers/clusters/agents_resolver.rb index 5ad66ed7cdd..28618bef807 100644 --- a/app/graphql/resolvers/clusters/agents_resolver.rb +++ b/app/graphql/resolvers/clusters/agents_resolver.rb @@ -30,7 +30,7 @@ module Resolvers def preloads { activity_events: { activity_events: [:user, agent_token: :agent] }, - tokens: :last_used_agent_tokens + tokens: :agent_tokens } end end diff --git a/app/graphql/resolvers/concerns/issue_resolver_arguments.rb b/app/graphql/resolvers/concerns/issue_resolver_arguments.rb index de44dbb26d7..fe213936f55 100644 --- a/app/graphql/resolvers/concerns/issue_resolver_arguments.rb +++ b/app/graphql/resolvers/concerns/issue_resolver_arguments.rb @@ -66,7 +66,6 @@ module IssueResolverArguments description: 'Filter for confidential issues. If "false", excludes confidential issues. If "true", returns only confidential issues.' argument :not, Types::Issues::NegatedIssueFilterInputType, description: 'Negated arguments.', - prepare: ->(negated_args, ctx) { negated_args.to_h }, required: false argument :crm_contact_id, GraphQL::Types::String, required: false, @@ -85,12 +84,12 @@ module IssueResolverArguments # Will need to be made group & namespace aware with # https://gitlab.com/gitlab-org/gitlab-foss/issues/54520 + args[:not] = args[:not].to_h if args[:not].present? args[:iids] ||= [args.delete(:iid)].compact if args[:iid] args[:attempt_project_search_optimizations] = true if args[:search].present? prepare_assignee_username_params(args) prepare_release_tag_params(args) - prepare_params(args, parent) if defined?(prepare_params) finder = IssuesFinder.new(current_user, args) @@ -98,6 +97,8 @@ module IssueResolverArguments end def ready?(**args) + args[:not] = args[:not].to_h if args[:not].present? + params_not_mutually_exclusive(args, mutually_exclusive_assignee_username_args) params_not_mutually_exclusive(args, mutually_exclusive_milestone_args) params_not_mutually_exclusive(args.fetch(:not, {}), mutually_exclusive_milestone_args) diff --git a/app/graphql/resolvers/concerns/resolves_groups.rb b/app/graphql/resolvers/concerns/resolves_groups.rb index c451d4e7936..2a3dce80057 100644 --- a/app/graphql/resolvers/concerns/resolves_groups.rb +++ b/app/graphql/resolvers/concerns/resolves_groups.rb @@ -18,11 +18,9 @@ module ResolvesGroups def preloads { - contacts: [:contacts], container_repositories_count: [:container_repositories], custom_emoji: [:custom_emoji], full_path: [:route], - organizations: [:organizations], path: [:route], dependency_proxy_blob_count: [:dependency_proxy_blobs], dependency_proxy_blobs: [:dependency_proxy_blobs], diff --git a/app/graphql/resolvers/concerns/resolves_merge_requests.rb b/app/graphql/resolvers/concerns/resolves_merge_requests.rb index a72b9a09118..697cc6f5b03 100644 --- a/app/graphql/resolvers/concerns/resolves_merge_requests.rb +++ b/app/graphql/resolvers/concerns/resolves_merge_requests.rb @@ -52,6 +52,7 @@ module ResolvesMergeRequests security_auto_fix: [:author], head_pipeline: [:merge_request_diff, { head_pipeline: [:merge_request] }], timelogs: [:timelogs], + pipelines: [:merge_request_diffs], # used by `recent_diff_head_shas` to load pipelines committers: [merge_request_diff: [:merge_request_diff_commits]] } end diff --git a/app/graphql/resolvers/crm/contacts_resolver.rb b/app/graphql/resolvers/crm/contacts_resolver.rb new file mode 100644 index 00000000000..58d0e2ce13d --- /dev/null +++ b/app/graphql/resolvers/crm/contacts_resolver.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +module Resolvers + module Crm + class ContactsResolver < BaseResolver + include Gitlab::Graphql::Authorize::AuthorizeResource + include ResolvesIds + + authorize :read_crm_contact + + type Types::CustomerRelations::ContactType, null: true + + argument :search, GraphQL::Types::String, + required: false, + description: 'Search term to find contacts with.' + + argument :state, Types::CustomerRelations::ContactStateEnum, + required: false, + description: 'State of the contacts to search for.' + + argument :ids, [::Types::GlobalIDType[CustomerRelations::Contact]], + required: false, + description: 'Filter contacts by IDs.' + + def resolve(**args) + args[:ids] = resolve_ids(args.delete(:ids)) + + ::Crm::ContactsFinder.new(current_user, { group: group }.merge(args)).execute + end + + def group + object.respond_to?(:sync) ? object.sync : object + end + end + end +end diff --git a/app/graphql/resolvers/crm/organizations_resolver.rb b/app/graphql/resolvers/crm/organizations_resolver.rb new file mode 100644 index 00000000000..ca0a908ee22 --- /dev/null +++ b/app/graphql/resolvers/crm/organizations_resolver.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +module Resolvers + module Crm + class OrganizationsResolver < BaseResolver + include Gitlab::Graphql::Authorize::AuthorizeResource + include ResolvesIds + + authorize :read_crm_organization + + type Types::CustomerRelations::OrganizationType, null: true + + argument :search, GraphQL::Types::String, + required: false, + description: 'Search term used to find organizations with.' + + argument :state, Types::CustomerRelations::OrganizationStateEnum, + required: false, + description: 'State of the organization to search for.' + + argument :ids, [Types::GlobalIDType[CustomerRelations::Organization]], + required: false, + description: 'Filter organizations by IDs.' + + def resolve(**args) + args[:ids] = resolve_ids(args.delete(:ids)) + + ::Crm::OrganizationsFinder.new(current_user, { group: group }.merge(args)).execute + end + + def group + object.respond_to?(:sync) ? object.sync : object + end + end + end +end diff --git a/app/graphql/resolvers/design_management/versions_resolver.rb b/app/graphql/resolvers/design_management/versions_resolver.rb index de636655087..bd9b82283c3 100644 --- a/app/graphql/resolvers/design_management/versions_resolver.rb +++ b/app/graphql/resolvers/design_management/versions_resolver.rb @@ -42,8 +42,6 @@ module Resolvers def cutoff(id, sha) if sha.present? || id.present? specific_version(id, sha) - elsif at_version = context[:at_version_argument] - by_id(at_version) # See: DesignsResolver else :unconstrained end diff --git a/app/graphql/resolvers/merge_request_pipelines_resolver.rb b/app/graphql/resolvers/merge_request_pipelines_resolver.rb index f84eedb4c3b..deb698c63e1 100644 --- a/app/graphql/resolvers/merge_request_pipelines_resolver.rb +++ b/app/graphql/resolvers/merge_request_pipelines_resolver.rb @@ -21,8 +21,9 @@ module Resolvers super end - def query_for(args) - resolve_pipelines(project, args).merge(merge_request.all_pipelines) + def query_for(input) + mr, args = input + resolve_pipelines(mr.source_project, args).merge(mr.all_pipelines) end def model_class @@ -30,7 +31,7 @@ module Resolvers end def query_input(**args) - args + [merge_request, args] end def project diff --git a/app/graphql/resolvers/milestones_resolver.rb b/app/graphql/resolvers/milestones_resolver.rb index dc6d781f584..25ff783b408 100644 --- a/app/graphql/resolvers/milestones_resolver.rb +++ b/app/graphql/resolvers/milestones_resolver.rb @@ -4,6 +4,11 @@ module Resolvers class MilestonesResolver < BaseResolver include Gitlab::Graphql::Authorize::AuthorizeResource include TimeFrameArguments + include LooksAhead + + # authorize before resolution + authorize :read_milestone + authorizes_object! argument :ids, [GraphQL::Types::ID], required: false, @@ -34,12 +39,10 @@ module Resolvers NON_STABLE_CURSOR_SORTS = %i[expired_last_due_date_asc expired_last_due_date_desc].freeze - def resolve(**args) + def resolve_with_lookahead(**args) validate_timeframe_params!(args) - authorize! - - milestones = MilestonesFinder.new(milestones_finder_params(args)).execute + milestones = apply_lookahead(MilestonesFinder.new(milestones_finder_params(args)).execute) if non_stable_cursor_sort?(args[:sort]) offset_pagination(milestones) @@ -50,6 +53,12 @@ module Resolvers private + def preloads + { + releases: :releases + } + end + def milestones_finder_params(args) { ids: parse_gids(args[:ids]), @@ -69,12 +78,6 @@ module Resolvers raise NotImplementedError end - # MilestonesFinder does not check for current_user permissions, - # so for now we need to keep it here. - def authorize! - Ability.allowed?(context[:current_user], :read_milestone, parent) || raise_resource_not_available_error! - end - def parse_gids(gids) gids&.map { |gid| GitlabSchema.parse_gid(gid, expected_type: Milestone).model_id } end diff --git a/app/graphql/resolvers/paginated_tree_resolver.rb b/app/graphql/resolvers/paginated_tree_resolver.rb index d29d87ca204..1b4211366e0 100644 --- a/app/graphql/resolvers/paginated_tree_resolver.rb +++ b/app/graphql/resolvers/paginated_tree_resolver.rb @@ -17,7 +17,6 @@ module Resolvers description: 'Used to get a recursive tree. Default is false.' argument :ref, GraphQL::Types::String, required: false, - default_value: :head, description: 'Commit ref to get the tree for. Default value is HEAD.' alias_method :repository, :object @@ -26,6 +25,7 @@ module Resolvers return unless repository.exists? cursor = args.delete(:after) + args[:ref] ||= :head pagination_params = { limit: @field.max_page_size || 100, diff --git a/app/graphql/resolvers/tree_resolver.rb b/app/graphql/resolvers/tree_resolver.rb index f02eb226810..553f9aa6cd9 100644 --- a/app/graphql/resolvers/tree_resolver.rb +++ b/app/graphql/resolvers/tree_resolver.rb @@ -16,7 +16,6 @@ module Resolvers description: 'Used to get a recursive tree. Default is false.' argument :ref, GraphQL::Types::String, required: false, - default_value: :head, description: 'Commit ref to get the tree for. Default value is HEAD.' alias_method :repository, :object @@ -24,6 +23,7 @@ module Resolvers def resolve(**args) return unless repository.exists? + args[:ref] ||= :head repository.tree(args[:ref], args[:path], recursive: args[:recursive]) end end diff --git a/app/graphql/resolvers/user_resolver.rb b/app/graphql/resolvers/user_resolver.rb index 99fd0d4927d..f0fd60e9cbb 100644 --- a/app/graphql/resolvers/user_resolver.rb +++ b/app/graphql/resolvers/user_resolver.rb @@ -2,6 +2,8 @@ module Resolvers class UserResolver < BaseResolver + include Gitlab::Graphql::Authorize::AuthorizeResource + description 'Retrieve a single user' type Types::UserType, null: true @@ -23,6 +25,8 @@ module Resolvers end def resolve(id: nil, username: nil) + authorize! + if id GitlabSchema.object_from_id(id, expected_type: User) else @@ -39,5 +43,9 @@ module Resolvers end end end + + def authorize! + raise_resource_not_available_error! unless context[:current_user].present? + end end end diff --git a/app/graphql/resolvers/users_resolver.rb b/app/graphql/resolvers/users_resolver.rb index 1424c14083d..b0d704d09fc 100644 --- a/app/graphql/resolvers/users_resolver.rb +++ b/app/graphql/resolvers/users_resolver.rb @@ -47,10 +47,7 @@ module Resolvers end def authorize!(usernames) - authorized = Ability.allowed?(context[:current_user], :read_users_list) - authorized &&= usernames.present? if context[:current_user].blank? - - raise_resource_not_available_error! unless authorized + raise_resource_not_available_error! unless context[:current_user].present? end private diff --git a/app/graphql/resolvers/work_items_resolver.rb b/app/graphql/resolvers/work_items_resolver.rb new file mode 100644 index 00000000000..1bc74131b9e --- /dev/null +++ b/app/graphql/resolvers/work_items_resolver.rb @@ -0,0 +1,60 @@ +# frozen_string_literal: true + +module Resolvers + class WorkItemsResolver < BaseResolver + include SearchArguments + include LooksAhead + + type Types::WorkItemType.connection_type, null: true + + argument :iid, GraphQL::Types::String, + required: false, + description: 'IID of the issue. For example, "1".' + argument :iids, [GraphQL::Types::String], + required: false, + description: 'List of IIDs of work items. For example, `["1", "2"]`.' + argument :sort, Types::WorkItemSortEnum, + description: 'Sort work items by this criteria.', + required: false, + default_value: :created_desc + argument :state, Types::IssuableStateEnum, + required: false, + description: 'Current state of this work item.' + argument :types, [Types::IssueTypeEnum], + as: :issue_types, + description: 'Filter work items by the given work item types.', + required: false + + def resolve_with_lookahead(**args) + # The project could have been loaded in batch by `BatchLoader`. + # At this point we need the `id` of the project to query for issues, so + # make sure it's loaded and not `nil` before continuing. + parent = object.respond_to?(:sync) ? object.sync : object + return WorkItem.none if parent.nil? || !parent.work_items_feature_flag_enabled? + + args[:iids] ||= [args.delete(:iid)].compact if args[:iid] + args[:attempt_project_search_optimizations] = true if args[:search].present? + + finder = ::WorkItems::WorkItemsFinder.new(current_user, args) + + Gitlab::Graphql::Loaders::IssuableLoader.new(parent, finder).batching_find_all { |q| apply_lookahead(q) } + end + + def ready?(**args) + validate_anonymous_search_access! if args[:search].present? + + super + end + + private + + def unconditional_includes + [ + { + project: [:project_feature, :group] + }, + :author + ] + end + end +end |