diff options
Diffstat (limited to 'app/graphql/resolvers/concerns')
4 files changed, 112 insertions, 29 deletions
diff --git a/app/graphql/resolvers/concerns/issue_resolver_arguments.rb b/app/graphql/resolvers/concerns/issue_resolver_arguments.rb index fe213936f55..8295bd58388 100644 --- a/app/graphql/resolvers/concerns/issue_resolver_arguments.rb +++ b/app/graphql/resolvers/concerns/issue_resolver_arguments.rb @@ -76,24 +76,11 @@ module IssueResolverArguments end 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 Issue.none if parent.nil? - - # 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? + return Issue.none if resource_parent.nil? - prepare_assignee_username_params(args) - prepare_release_tag_params(args) + finder = IssuesFinder.new(current_user, prepare_finder_params(args)) - finder = IssuesFinder.new(current_user, args) - - continue_issue_resolve(parent, finder, **args) + continue_issue_resolve(resource_parent, finder, **args) end def ready?(**args) @@ -103,7 +90,6 @@ module IssueResolverArguments params_not_mutually_exclusive(args, mutually_exclusive_milestone_args) params_not_mutually_exclusive(args.fetch(:not, {}), mutually_exclusive_milestone_args) params_not_mutually_exclusive(args, mutually_exclusive_release_tag_args) - validate_anonymous_search_access! if args[:search].present? super end @@ -128,6 +114,17 @@ module IssueResolverArguments private + def prepare_finder_params(args) + params = super(args) + params[:iids] ||= [params.delete(:iid)].compact if params[:iid] + params[:attempt_project_search_optimizations] = true if params[:search].present? + + prepare_assignee_username_params(params) + prepare_release_tag_params(params) + + params + end + def prepare_release_tag_params(args) release_tag_wildcard = args.delete(:release_tag_wildcard_id) return if release_tag_wildcard.blank? @@ -135,20 +132,13 @@ module IssueResolverArguments args[:release_tag] ||= release_tag_wildcard end - def mutually_exclusive_release_tag_args - [:release_tag, :release_tag_wildcard_id] - end - def prepare_assignee_username_params(args) args[:assignee_username] = args.delete(:assignee_usernames) if args[:assignee_usernames].present? args[:not][:assignee_username] = args[:not].delete(:assignee_usernames) if args.dig(:not, :assignee_usernames).present? end - def params_not_mutually_exclusive(args, mutually_exclusive_args) - if args.slice(*mutually_exclusive_args).compact.size > 1 - arg_str = mutually_exclusive_args.map { |x| x.to_s.camelize(:lower) }.join(', ') - raise ::Gitlab::Graphql::Errors::ArgumentError, "only one of [#{arg_str}] arguments is allowed at the same time." - end + def mutually_exclusive_release_tag_args + [:release_tag, :release_tag_wildcard_id] end def mutually_exclusive_milestone_args @@ -158,4 +148,20 @@ module IssueResolverArguments def mutually_exclusive_assignee_username_args [:assignee_usernames, :assignee_username] end + + def params_not_mutually_exclusive(args, mutually_exclusive_args) + if args.slice(*mutually_exclusive_args).compact.size > 1 + arg_str = mutually_exclusive_args.map { |x| x.to_s.camelize(:lower) }.join(', ') + raise ::Gitlab::Graphql::Errors::ArgumentError, "only one of [#{arg_str}] arguments is allowed at the same time." + end + end + + def resource_parent + # 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. + strong_memoize(:resource_parent) do + object.respond_to?(:sync) ? object.sync : object + end + end end diff --git a/app/graphql/resolvers/concerns/looks_ahead.rb b/app/graphql/resolvers/concerns/looks_ahead.rb index 644b2a11460..b548dc1e175 100644 --- a/app/graphql/resolvers/concerns/looks_ahead.rb +++ b/app/graphql/resolvers/concerns/looks_ahead.rb @@ -33,10 +33,14 @@ module LooksAhead end def filtered_preloads - selection = node_selection + nodes = node_selection + + return [] unless nodes + + selected_fields = nodes.selections.map(&:name) preloads.each.flat_map do |name, requirements| - selection&.selects?(name) ? requirements : [] + selected_fields.include?(name) ? requirements : [] end end diff --git a/app/graphql/resolvers/concerns/project_search_arguments.rb b/app/graphql/resolvers/concerns/project_search_arguments.rb new file mode 100644 index 00000000000..7e03963f412 --- /dev/null +++ b/app/graphql/resolvers/concerns/project_search_arguments.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +module ProjectSearchArguments + extend ActiveSupport::Concern + + included do + argument :membership, GraphQL::Types::Boolean, + required: false, + description: 'Return only projects that the current user is a member of.' + + argument :search, GraphQL::Types::String, + required: false, + description: 'Search query, which can be for the project name, a path, or a description.' + + argument :search_namespaces, GraphQL::Types::Boolean, + required: false, + description: 'Include namespace in project search.' + + argument :topics, type: [GraphQL::Types::String], + required: false, + description: 'Filter projects by topics.' + end + + private + + def project_finder_params(params) + { + without_deleted: true, + non_public: params[:membership], + search: params[:search], + search_namespaces: params[:search_namespaces], + sort: params[:sort], + topic: params[:topics] + }.compact + end +end diff --git a/app/graphql/resolvers/concerns/search_arguments.rb b/app/graphql/resolvers/concerns/search_arguments.rb index 7f480f9d0b6..95c6dbf7497 100644 --- a/app/graphql/resolvers/concerns/search_arguments.rb +++ b/app/graphql/resolvers/concerns/search_arguments.rb @@ -7,12 +7,49 @@ module SearchArguments argument :search, GraphQL::Types::String, required: false, description: 'Search query for title or description.' + argument :in, [Types::IssuableSearchableFieldEnum], + required: false, + description: <<~DESC + Specify the fields to perform the search in. + Defaults to `[TITLE, DESCRIPTION]`. Requires the `search` argument.' + DESC + end + + def ready?(**args) + validate_search_in_params!(args) + validate_anonymous_search_access!(args) + + super end - def validate_anonymous_search_access! + private + + def validate_anonymous_search_access!(args) + return unless args[:search].present? return if current_user.present? || Feature.disabled?(:disable_anonymous_search, type: :ops) raise ::Gitlab::Graphql::Errors::ArgumentError, "User must be authenticated to include the `search` argument." end + + def validate_search_in_params!(args) + return unless args[:in].present? && args[:search].blank? + + raise Gitlab::Graphql::Errors::ArgumentError, + '`search` should be present when including the `in` argument' + end + + def prepare_finder_params(args) + prepare_search_params(args) + end + + def prepare_search_params(args) + return args unless args[:search].present? + + parent_type = resource_parent.is_a?(Project) ? :project : :group + args[:"attempt_#{parent_type}_search_optimizations"] = true + args[:in] = args[:in].join(',') if args[:in].present? + + args + end end |