summaryrefslogtreecommitdiff
path: root/app/graphql
diff options
context:
space:
mode:
Diffstat (limited to 'app/graphql')
-rw-r--r--app/graphql/resolvers/concerns/resolves_snippets.rb57
-rw-r--r--app/graphql/resolvers/projects/snippets_resolver.rb23
-rw-r--r--app/graphql/resolvers/snippets_resolver.rb45
-rw-r--r--app/graphql/resolvers/users/snippets_resolver.rb21
-rw-r--r--app/graphql/types/notes/noteable_type.rb2
-rw-r--r--app/graphql/types/permission_types/project.rb8
-rw-r--r--app/graphql/types/permission_types/snippet.rb15
-rw-r--r--app/graphql/types/permission_types/user.rb15
-rw-r--r--app/graphql/types/project_type.rb6
-rw-r--r--app/graphql/types/query_type.rb6
-rw-r--r--app/graphql/types/snippet_type.rb69
-rw-r--r--app/graphql/types/snippets/type_enum.rb10
-rw-r--r--app/graphql/types/snippets/visibility_scopes_enum.rb11
-rw-r--r--app/graphql/types/user_type.rb8
14 files changed, 295 insertions, 1 deletions
diff --git a/app/graphql/resolvers/concerns/resolves_snippets.rb b/app/graphql/resolvers/concerns/resolves_snippets.rb
new file mode 100644
index 00000000000..483372bbf63
--- /dev/null
+++ b/app/graphql/resolvers/concerns/resolves_snippets.rb
@@ -0,0 +1,57 @@
+# frozen_string_literal: true
+
+module ResolvesSnippets
+ extend ActiveSupport::Concern
+
+ included do
+ type Types::SnippetType, null: false
+
+ argument :ids, [GraphQL::ID_TYPE],
+ required: false,
+ description: 'Array of global snippet ids, e.g., "gid://gitlab/ProjectSnippet/1"'
+
+ argument :visibility, Types::Snippets::VisibilityScopesEnum,
+ required: false,
+ description: 'The visibility of the snippet'
+ end
+
+ def resolve(**args)
+ resolve_snippets(args)
+ end
+
+ private
+
+ def resolve_snippets(args)
+ SnippetsFinder.new(context[:current_user], snippet_finder_params(args)).execute
+ end
+
+ def snippet_finder_params(args)
+ {
+ ids: resolve_ids(args[:ids]),
+ scope: args[:visibility]
+ }.merge(options_by_type(args[:type]))
+ end
+
+ def resolve_ids(ids)
+ Array.wrap(ids).map { |id| resolve_gid(id, :id) }
+ end
+
+ def resolve_gid(gid, argument)
+ return unless gid.present?
+
+ GlobalID.parse(gid)&.model_id.tap do |id|
+ raise Gitlab::Graphql::Errors::ArgumentError, "Invalid global id format for param #{argument}" if id.nil?
+ end
+ end
+
+ def options_by_type(type)
+ case type
+ when 'personal'
+ { only_personal: true }
+ when 'project'
+ { only_project: true }
+ else
+ {}
+ end
+ end
+end
diff --git a/app/graphql/resolvers/projects/snippets_resolver.rb b/app/graphql/resolvers/projects/snippets_resolver.rb
new file mode 100644
index 00000000000..bf9aa45349f
--- /dev/null
+++ b/app/graphql/resolvers/projects/snippets_resolver.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+module Resolvers
+ module Projects
+ class SnippetsResolver < BaseResolver
+ include ResolvesSnippets
+
+ alias_method :project, :object
+
+ def resolve(**args)
+ return Snippet.none if project.nil?
+
+ super
+ end
+
+ private
+
+ def snippet_finder_params(args)
+ super.merge(project: project)
+ end
+ end
+ end
+end
diff --git a/app/graphql/resolvers/snippets_resolver.rb b/app/graphql/resolvers/snippets_resolver.rb
new file mode 100644
index 00000000000..530a288a25b
--- /dev/null
+++ b/app/graphql/resolvers/snippets_resolver.rb
@@ -0,0 +1,45 @@
+# frozen_string_literal: true
+
+module Resolvers
+ class SnippetsResolver < BaseResolver
+ include ResolvesSnippets
+
+ ERROR_MESSAGE = 'Filtering by both an author and a project is not supported'
+
+ alias_method :user, :object
+
+ argument :author_id, GraphQL::ID_TYPE,
+ required: false,
+ description: 'The ID of an author'
+
+ argument :project_id, GraphQL::ID_TYPE,
+ required: false,
+ description: 'The ID of a project'
+
+ argument :type, Types::Snippets::TypeEnum,
+ required: false,
+ description: 'The type of snippet'
+
+ argument :explore,
+ GraphQL::BOOLEAN_TYPE,
+ required: false,
+ description: 'Explore personal snippets'
+
+ def resolve(**args)
+ if args[:author_id].present? && args[:project_id].present?
+ raise Gitlab::Graphql::Errors::ArgumentError, ERROR_MESSAGE
+ end
+
+ super
+ end
+
+ private
+
+ def snippet_finder_params(args)
+ super
+ .merge(author: resolve_gid(args[:author_id], :author),
+ project: resolve_gid(args[:project_id], :project),
+ explore: args[:explore])
+ end
+ end
+end
diff --git a/app/graphql/resolvers/users/snippets_resolver.rb b/app/graphql/resolvers/users/snippets_resolver.rb
new file mode 100644
index 00000000000..d757640b5ff
--- /dev/null
+++ b/app/graphql/resolvers/users/snippets_resolver.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+module Resolvers
+ module Users
+ class SnippetsResolver < BaseResolver
+ include ResolvesSnippets
+
+ alias_method :user, :object
+
+ argument :type, Types::Snippets::TypeEnum,
+ required: false,
+ description: 'The type of snippet'
+
+ private
+
+ def snippet_finder_params(args)
+ super.merge(author: user)
+ end
+ end
+ end
+end
diff --git a/app/graphql/types/notes/noteable_type.rb b/app/graphql/types/notes/noteable_type.rb
index ab4a170b123..2ac66452841 100644
--- a/app/graphql/types/notes/noteable_type.rb
+++ b/app/graphql/types/notes/noteable_type.rb
@@ -15,6 +15,8 @@ module Types
Types::IssueType
when MergeRequest
Types::MergeRequestType
+ when Snippet
+ Types::SnippetType
else
raise "Unknown GraphQL type for #{object}"
end
diff --git a/app/graphql/types/permission_types/project.rb b/app/graphql/types/permission_types/project.rb
index 3a6ba371154..2879dbd2b5c 100644
--- a/app/graphql/types/permission_types/project.rb
+++ b/app/graphql/types/permission_types/project.rb
@@ -10,13 +10,19 @@ module Types
:remove_pages, :read_project, :create_merge_request_in,
:read_wiki, :read_project_member, :create_issue, :upload_file,
:read_cycle_analytics, :download_code, :download_wiki_code,
- :fork_project, :create_project_snippet, :read_commit_status,
+ :fork_project, :read_commit_status,
:request_access, :create_pipeline, :create_pipeline_schedule,
:create_merge_request_from, :create_wiki, :push_code,
:create_deployment, :push_to_delete_protected_branch,
:admin_wiki, :admin_project, :update_pages,
:admin_remote_mirror, :create_label, :update_wiki, :destroy_wiki,
:create_pages, :destroy_pages, :read_pages_content, :admin_operations
+
+ permission_field :create_snippet
+
+ def create_snippet
+ Ability.allowed?(context[:current_user], :create_project_snippet, object)
+ end
end
end
end
diff --git a/app/graphql/types/permission_types/snippet.rb b/app/graphql/types/permission_types/snippet.rb
new file mode 100644
index 00000000000..1e21efe790a
--- /dev/null
+++ b/app/graphql/types/permission_types/snippet.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+module Types
+ module PermissionTypes
+ class Snippet < BasePermissionType
+ graphql_name 'SnippetPermissions'
+
+ abilities :create_note, :award_emoji
+
+ permission_field :read_snippet, method: :can_read_snippet?
+ permission_field :update_snippet, method: :can_update_snippet?
+ permission_field :admin_snippet, method: :can_admin_snippet?
+ end
+ end
+end
diff --git a/app/graphql/types/permission_types/user.rb b/app/graphql/types/permission_types/user.rb
new file mode 100644
index 00000000000..dba4de2dacc
--- /dev/null
+++ b/app/graphql/types/permission_types/user.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+module Types
+ module PermissionTypes
+ class User < BasePermissionType
+ graphql_name 'UserPermissions'
+
+ permission_field :create_snippet
+
+ def create_snippet
+ Ability.allowed?(context[:current_user], :create_personal_snippet)
+ end
+ end
+ end
+end
diff --git a/app/graphql/types/project_type.rb b/app/graphql/types/project_type.rb
index d2a163b70db..a11676770a9 100644
--- a/app/graphql/types/project_type.rb
+++ b/app/graphql/types/project_type.rb
@@ -151,5 +151,11 @@ module Types
null: true,
description: 'Detailed version of a Sentry error on the project',
resolver: Resolvers::ErrorTracking::SentryDetailedErrorResolver
+
+ field :snippets,
+ Types::SnippetType.connection_type,
+ null: true,
+ description: 'Snippets of the project',
+ resolver: Resolvers::Projects::SnippetsResolver
end
end
diff --git a/app/graphql/types/query_type.rb b/app/graphql/types/query_type.rb
index 996bf225976..06188d99490 100644
--- a/app/graphql/types/query_type.rb
+++ b/app/graphql/types/query_type.rb
@@ -29,6 +29,12 @@ module Types
resolver: Resolvers::MetadataResolver,
description: 'Metadata about GitLab'
+ field :snippets,
+ Types::SnippetType.connection_type,
+ null: true,
+ resolver: Resolvers::SnippetsResolver,
+ description: 'Find Snippets visible to the current user'
+
field :echo, GraphQL::STRING_TYPE, null: false, resolver: Resolvers::EchoResolver # rubocop:disable Graphql/Descriptions
end
end
diff --git a/app/graphql/types/snippet_type.rb b/app/graphql/types/snippet_type.rb
new file mode 100644
index 00000000000..3b4dce1d486
--- /dev/null
+++ b/app/graphql/types/snippet_type.rb
@@ -0,0 +1,69 @@
+# frozen_string_literal: true
+
+module Types
+ class SnippetType < BaseObject
+ graphql_name 'Snippet'
+ description 'Represents a snippet entry'
+
+ implements(Types::Notes::NoteableType)
+
+ present_using SnippetPresenter
+
+ authorize :read_snippet
+
+ expose_permissions Types::PermissionTypes::Snippet
+
+ field :id, GraphQL::ID_TYPE,
+ description: 'Id of the snippet',
+ null: false
+
+ field :title, GraphQL::STRING_TYPE,
+ description: 'Title of the snippet',
+ null: false
+
+ field :project, Types::ProjectType,
+ description: 'The project the snippet is associated with',
+ null: true,
+ authorize: :read_project,
+ resolve: -> (snippet, args, context) { Gitlab::Graphql::Loaders::BatchModelLoader.new(Project, snippet.project_id).find }
+
+ field :author, Types::UserType,
+ description: 'The owner of the snippet',
+ null: false,
+ resolve: -> (snippet, args, context) { Gitlab::Graphql::Loaders::BatchModelLoader.new(User, snippet.author_id).find }
+
+ field :file_name, GraphQL::STRING_TYPE,
+ description: 'File Name of the snippet',
+ null: true
+
+ field :content, GraphQL::STRING_TYPE,
+ description: 'Content of the snippet',
+ null: false
+
+ field :description, GraphQL::STRING_TYPE,
+ description: 'Description of the snippet',
+ null: true
+
+ field :visibility, GraphQL::STRING_TYPE,
+ description: 'Visibility of the snippet',
+ null: false
+
+ field :created_at, Types::TimeType,
+ description: 'Timestamp this snippet was created',
+ null: false
+
+ field :updated_at, Types::TimeType,
+ description: 'Timestamp this snippet was updated',
+ null: false
+
+ field :web_url, type: GraphQL::STRING_TYPE,
+ description: 'Web URL of the snippet',
+ null: false
+
+ field :raw_url, type: GraphQL::STRING_TYPE,
+ description: 'Raw URL of the snippet',
+ null: false
+
+ markdown_field :description_html, null: true, method: :description
+ end
+end
diff --git a/app/graphql/types/snippets/type_enum.rb b/app/graphql/types/snippets/type_enum.rb
new file mode 100644
index 00000000000..243f05359db
--- /dev/null
+++ b/app/graphql/types/snippets/type_enum.rb
@@ -0,0 +1,10 @@
+# frozen_string_literal: true
+
+module Types
+ module Snippets
+ class TypeEnum < BaseEnum
+ value 'personal', value: 'personal'
+ value 'project', value: 'project'
+ end
+ end
+end
diff --git a/app/graphql/types/snippets/visibility_scopes_enum.rb b/app/graphql/types/snippets/visibility_scopes_enum.rb
new file mode 100644
index 00000000000..5488e05b95d
--- /dev/null
+++ b/app/graphql/types/snippets/visibility_scopes_enum.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+module Types
+ module Snippets
+ class VisibilityScopesEnum < BaseEnum
+ value 'private', value: 'are_private'
+ value 'internal', value: 'are_internal'
+ value 'public', value: 'are_public'
+ end
+ end
+end
diff --git a/app/graphql/types/user_type.rb b/app/graphql/types/user_type.rb
index b45c7893e75..3943c891335 100644
--- a/app/graphql/types/user_type.rb
+++ b/app/graphql/types/user_type.rb
@@ -8,6 +8,8 @@ module Types
present_using UserPresenter
+ expose_permissions Types::PermissionTypes::User
+
field :name, GraphQL::STRING_TYPE, null: false,
description: 'Human-readable name of the user'
field :username, GraphQL::STRING_TYPE, null: false,
@@ -19,5 +21,11 @@ module Types
field :todos, Types::TodoType.connection_type, null: false,
resolver: Resolvers::TodoResolver,
description: 'Todos of the user'
+
+ field :snippets,
+ Types::SnippetType.connection_type,
+ null: true,
+ description: 'Snippets authored by the user',
+ resolver: Resolvers::Users::SnippetsResolver
end
end