From 09db95a9429fb552b2a0d8acf0ab5ff1f5e2ba0c Mon Sep 17 00:00:00 2001 From: Rajendra Kadam Date: Mon, 27 Jul 2020 12:37:44 +0530 Subject: [PATCH 01/22] Add CustomEmoji Type --- app/graphql/types/custom_emoji_type.rb | 26 ++++++++++++++++++++ spec/graphql/types/custom_emoji_type_spec.rb | 11 +++++++++ 2 files changed, 37 insertions(+) create mode 100644 app/graphql/types/custom_emoji_type.rb create mode 100644 spec/graphql/types/custom_emoji_type_spec.rb diff --git a/app/graphql/types/custom_emoji_type.rb b/app/graphql/types/custom_emoji_type.rb new file mode 100644 index 00000000000000..7da966bee50910 --- /dev/null +++ b/app/graphql/types/custom_emoji_type.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +module Types + class CustomEmojiType < Types::BaseObject + graphql_name 'CustomEmoji' + description 'A custom emoji uploaded by user' + + authorize :read_emoji + + field :id, GraphQL::ID_TYPE, + null: false, + description: 'The ID of the emoji' + + field :name, GraphQL::STRING_TYPE, + null: false, + description: 'The name of the emoji' + + field :file, GraphQL::STRING_TYPE, + null: false, + description: 'The link to file of the emoji' + + field :external, GraphQL::BOOLEAN_TYPE, + null: false, + description: 'Whether the emoji is external link' + end +end diff --git a/spec/graphql/types/custom_emoji_type_spec.rb b/spec/graphql/types/custom_emoji_type_spec.rb new file mode 100644 index 00000000000000..ca7400c93603a8 --- /dev/null +++ b/spec/graphql/types/custom_emoji_type_spec.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe GitlabSchema.types['CustomEmoji'] do + specify { expect(described_class.graphql_name).to eq('CustomEmoji') } + + specify { expect(described_class).to require_graphql_authorizations(:read_emoji) } + + specify { expect(described_class).to have_graphql_field(:id, :name, :file, :external) } +end -- GitLab From 4c577a11d874aec5d84f0c6225bfa767ee4684af Mon Sep 17 00:00:00 2001 From: Rajendra Kadam Date: Mon, 27 Jul 2020 13:35:55 +0530 Subject: [PATCH 02/22] Add CustomEmoji Type --- app/graphql/types/custom_emoji_type.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/graphql/types/custom_emoji_type.rb b/app/graphql/types/custom_emoji_type.rb index 7da966bee50910..e9db93fd3142e3 100644 --- a/app/graphql/types/custom_emoji_type.rb +++ b/app/graphql/types/custom_emoji_type.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module Types - class CustomEmojiType < Types::BaseObject + class CustomEmojiType < BaseObject graphql_name 'CustomEmoji' description 'A custom emoji uploaded by user' -- GitLab From 28d35c9b9d788cedb36fe3c372376fd2a109ef7d Mon Sep 17 00:00:00 2001 From: Rajendra Kadam Date: Wed, 12 Aug 2020 19:04:06 +0530 Subject: [PATCH 03/22] Add CustomEmoji Type to NameSpace --- app/graphql/types/namespace_type.rb | 3 +++ spec/graphql/types/custom_emoji_type_spec.rb | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/app/graphql/types/namespace_type.rb b/app/graphql/types/namespace_type.rb index fbdf049b755058..957faec6540aca 100644 --- a/app/graphql/types/namespace_type.rb +++ b/app/graphql/types/namespace_type.rb @@ -36,6 +36,9 @@ class NamespaceType < BaseObject field :projects, Types::ProjectType.connection_type, null: false, description: 'Projects within this namespace', resolver: ::Resolvers::NamespaceProjectsResolver + + field :custom_emoji, Types::CustomEmojiType.connection_type, null: true, + description: 'Custom emoji within this namespace' end end diff --git a/spec/graphql/types/custom_emoji_type_spec.rb b/spec/graphql/types/custom_emoji_type_spec.rb index ca7400c93603a8..53904ce354d5d5 100644 --- a/spec/graphql/types/custom_emoji_type_spec.rb +++ b/spec/graphql/types/custom_emoji_type_spec.rb @@ -7,5 +7,5 @@ specify { expect(described_class).to require_graphql_authorizations(:read_emoji) } - specify { expect(described_class).to have_graphql_field(:id, :name, :file, :external) } + specify { expect(described_class).to have_graphql_fields(:id, :name, :file, :external) } end -- GitLab From e98932b4a72b67b99b10f423cb10cab75769e1c3 Mon Sep 17 00:00:00 2001 From: Rajendra Kadam Date: Tue, 3 Nov 2020 20:33:05 +0530 Subject: [PATCH 04/22] Fix errored force push by changing all files to previous state Change and update code to match missed files --- app/graphql/mutations/custom_emoji/create.rb | 62 +++ .../resolvers/custom_emoji_resolver.rb | 36 ++ app/graphql/types/mutation_type.rb | 1 + .../types/permission_types/custom_emoji.rb | 11 + app/models/custom_emoji.rb | 2 +- app/policies/custom_emoji_policy.rb | 5 + app/policies/group_policy.rb | 2 + .../graphql/reference/gitlab_schema.graphql | 161 ++++++ doc/api/graphql/reference/gitlab_schema.json | 474 ++++++++++++++++++ .../resolvers/custom_emoji_resolver_spec.rb | 45 ++ .../mutations/custom_emoji/create_spec.rb | 44 ++ 11 files changed, 842 insertions(+), 1 deletion(-) create mode 100644 app/graphql/mutations/custom_emoji/create.rb create mode 100644 app/graphql/resolvers/custom_emoji_resolver.rb create mode 100644 app/graphql/types/permission_types/custom_emoji.rb create mode 100644 app/policies/custom_emoji_policy.rb create mode 100644 spec/graphql/resolvers/custom_emoji_resolver_spec.rb create mode 100644 spec/requests/api/graphql/mutations/custom_emoji/create_spec.rb diff --git a/app/graphql/mutations/custom_emoji/create.rb b/app/graphql/mutations/custom_emoji/create.rb new file mode 100644 index 00000000000000..835b34673bf184 --- /dev/null +++ b/app/graphql/mutations/custom_emoji/create.rb @@ -0,0 +1,62 @@ +# frozen_string_literal: true + +module Mutations + module CustomEmoji + class Create < BaseMutation + include Mutations::ResolvesGroup + + graphql_name 'CreateCustomEmoji' + + authorize :create_custom_emoji + + field :custom_emoji, + Types::CustomEmojiType, + null: true, + description: 'The new custom emoji' + + argument :group_path, GraphQL::ID_TYPE, + required: true, + description: 'Namespace full path the emoji is associated with' + + argument :name, GraphQL::STRING_TYPE, + required: true, + description: 'Name of the emoji' + + argument :file, GraphQL::STRING_TYPE, + required: true, + description: 'Location of the emoji file' + + argument :external, GraphQL::BOOLEAN_TYPE, + required: true, + description: 'Whether the emoji file is an external link' + + def resolve(args) + group_path = args.delete(:group_path) + + validate_arguments!(args) + + group = authorized_find!(group_path: group_path) + + custom_emoji = group.custom_emoji.create!(args) + + { + name: custom_emoji.valid? ? custom_emoji.name : nil, + errors: errors_on_object(custom_emoji) + } + end + + private + + def validate_arguments!(args) + if args.empty? + raise Gitlab::Graphql::Errors::ArgumentError, + 'The list of custom emoji attributes is empty' + end + end + + def find_object(group_path:) + resolve_group(full_path: group_path) + end + end + end +end diff --git a/app/graphql/resolvers/custom_emoji_resolver.rb b/app/graphql/resolvers/custom_emoji_resolver.rb new file mode 100644 index 00000000000000..08fd3f158a987b --- /dev/null +++ b/app/graphql/resolvers/custom_emoji_resolver.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +module Resolvers + class CustomEmojiResolver < BaseResolver + include Gitlab::Graphql::Authorize::AuthorizeResource + prepend FullPathResolver + + type Types::CustomEmojiType, null: true + + argument :group_path, GraphQL::ID_TYPE, + required: true, + description: 'The path of the group to use' + + def resolve(**args) + group_path = args.delete(:group_path) + + group = model_by_full_path(Group, group_path).sync + + return unless group.presence + + authorize!(group) + + emoji = group.custom_emoji rescue [] + + { + custom_emoji: emoji.presence ? emoji : nil + } + end + + private + + def authorize!(group) + Ability.allowed?(context[:current_user], :read_group, group) || raise_resource_not_available_error! + end + end +end diff --git a/app/graphql/types/mutation_type.rb b/app/graphql/types/mutation_type.rb index 802e98f7d62fd8..15e91c0dd75980 100644 --- a/app/graphql/types/mutation_type.rb +++ b/app/graphql/types/mutation_type.rb @@ -29,6 +29,7 @@ class MutationType < BaseObject mount_mutation Mutations::Boards::Lists::Destroy mount_mutation Mutations::Branches::Create, calls_gitaly: true mount_mutation Mutations::Commits::Create, calls_gitaly: true + mount_mutation Mutations::CustomEmoji::Create mount_mutation Mutations::Discussions::ToggleResolve mount_mutation Mutations::Issues::Create mount_mutation Mutations::Issues::SetAssignees diff --git a/app/graphql/types/permission_types/custom_emoji.rb b/app/graphql/types/permission_types/custom_emoji.rb new file mode 100644 index 00000000000000..6791d165805e8d --- /dev/null +++ b/app/graphql/types/permission_types/custom_emoji.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +module Types + module PermissionTypes + class CustomEmoji < BasePermissionType + graphql_name 'CustomEmojiPermissions' + + abilities :create_custom_emoji, :read_emoji + end + end +end diff --git a/app/models/custom_emoji.rb b/app/models/custom_emoji.rb index 643b4060ad6656..c51c1ef3634697 100644 --- a/app/models/custom_emoji.rb +++ b/app/models/custom_emoji.rb @@ -10,7 +10,7 @@ class CustomEmoji < ApplicationRecord uniqueness: { scope: [:namespace_id, :name] }, presence: true, length: { maximum: 36 }, - format: { with: /\A\w+\z/ } + format: { with: /\A[\w\-]+\z/ } private diff --git a/app/policies/custom_emoji_policy.rb b/app/policies/custom_emoji_policy.rb new file mode 100644 index 00000000000000..e62641f6013d83 --- /dev/null +++ b/app/policies/custom_emoji_policy.rb @@ -0,0 +1,5 @@ +# frozen_string_literal: true + +class CustomEmojiPolicy < BasePolicy + delegate { @subject.namespace } +end diff --git a/app/policies/group_policy.rb b/app/policies/group_policy.rb index 6ff6d1359ab9d2..13b7c841bed68e 100644 --- a/app/policies/group_policy.rb +++ b/app/policies/group_policy.rb @@ -101,6 +101,7 @@ class GroupPolicy < BasePolicy enable :read_label enable :read_board enable :read_group_member + enable :read_emoji end rule { ~can?(:read_group) }.policy do @@ -114,6 +115,7 @@ class GroupPolicy < BasePolicy enable :create_metrics_dashboard_annotation enable :delete_metrics_dashboard_annotation enable :update_metrics_dashboard_annotation + enable :create_custom_emoji end rule { reporter }.policy do diff --git a/doc/api/graphql/reference/gitlab_schema.graphql b/doc/api/graphql/reference/gitlab_schema.graphql index 5bb1dc0eff66aa..3633d95ecb0ccd 100644 --- a/doc/api/graphql/reference/gitlab_schema.graphql +++ b/doc/api/graphql/reference/gitlab_schema.graphql @@ -3834,6 +3834,56 @@ type CreateClusterAgentPayload { errors: [String!]! } +""" +Autogenerated input type of CreateCustomEmoji +""" +input CreateCustomEmojiInput { + """ + A unique identifier for the client performing the mutation. + """ + clientMutationId: String + + """ + Whether the emoji file is an external link + """ + external: Boolean! + + """ + Location of the emoji file + """ + file: String! + + """ + Namespace full path the emoji is associated with + """ + groupPath: ID! + + """ + Name of the emoji + """ + name: String! +} + +""" +Autogenerated return type of CreateCustomEmoji +""" +type CreateCustomEmojiPayload { + """ + A unique identifier for the client performing the mutation. + """ + clientMutationId: String + + """ + The new custom emoji + """ + customEmoji: CustomEmoji + + """ + Errors encountered during execution of the mutation. + """ + errors: [String!]! +} + """ Autogenerated input type of CreateDiffNote """ @@ -4431,6 +4481,66 @@ interface CurrentUserTodos { ): TodoConnection! } +""" +A custom emoji uploaded by user +""" +type CustomEmoji { + """ + Whether the emoji is external link + """ + external: Boolean! + + """ + The link to file of the emoji + """ + file: String! + + """ + The ID of the emoji + """ + id: ID! + + """ + The name of the emoji + """ + name: String! +} + +""" +The connection type for CustomEmoji. +""" +type CustomEmojiConnection { + """ + A list of edges. + """ + edges: [CustomEmojiEdge] + + """ + A list of nodes. + """ + nodes: [CustomEmoji] + + """ + Information to aid in pagination. + """ + pageInfo: PageInfo! +} + +""" +An edge in a connection. +""" +type CustomEmojiEdge { + """ + A cursor for use in pagination. + """ + cursor: String! + + """ + The item at the end of the edge. + """ + node: CustomEmoji +} + """ Autogenerated input type of DastOnDemandScanCreate """ @@ -8516,6 +8626,31 @@ type Group { """ containsLockedProjects: Boolean! + """ + Custom emoji within this namespace + """ + customEmoji( + """ + Returns the elements in the list that come after the specified cursor. + """ + after: String + + """ + Returns the elements in the list that come before the specified cursor. + """ + before: String + + """ + Returns the first _n_ elements from the list. + """ + first: Int + + """ + Returns the last _n_ elements from the list. + """ + last: Int + ): CustomEmojiConnection + """ Description of the namespace """ @@ -13501,6 +13636,7 @@ type Mutation { createBoard(input: CreateBoardInput!): CreateBoardPayload createBranch(input: CreateBranchInput!): CreateBranchPayload createClusterAgent(input: CreateClusterAgentInput!): CreateClusterAgentPayload + createCustomEmoji(input: CreateCustomEmojiInput!): CreateCustomEmojiPayload createDiffNote(input: CreateDiffNoteInput!): CreateDiffNotePayload createEpic(input: CreateEpicInput!): CreateEpicPayload createImageDiffNote(input: CreateImageDiffNoteInput!): CreateImageDiffNotePayload @@ -13661,6 +13797,31 @@ type Namespace { """ containsLockedProjects: Boolean! + """ + Custom emoji within this namespace + """ + customEmoji( + """ + Returns the elements in the list that come after the specified cursor. + """ + after: String + + """ + Returns the elements in the list that come before the specified cursor. + """ + before: String + + """ + Returns the first _n_ elements from the list. + """ + first: Int + + """ + Returns the last _n_ elements from the list. + """ + last: Int + ): CustomEmojiConnection + """ Description of the namespace """ diff --git a/doc/api/graphql/reference/gitlab_schema.json b/doc/api/graphql/reference/gitlab_schema.json index 6614396da7203a..483f68980ac0dc 100644 --- a/doc/api/graphql/reference/gitlab_schema.json +++ b/doc/api/graphql/reference/gitlab_schema.json @@ -10477,6 +10477,150 @@ "enumValues": null, "possibleTypes": null }, + { + "kind": "INPUT_OBJECT", + "name": "CreateCustomEmojiInput", + "description": "Autogenerated input type of CreateCustomEmoji", + "fields": null, + "inputFields": [ + { + "name": "groupPath", + "description": "Namespace full path the emoji is associated with", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "ID", + "ofType": null + } + }, + "defaultValue": null + }, + { + "name": "name", + "description": "Name of the emoji", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "defaultValue": null + }, + { + "name": "file", + "description": "Location of the emoji file", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "defaultValue": null + }, + { + "name": "external", + "description": "Whether the emoji file is an external link", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null + } + }, + "defaultValue": null + }, + { + "name": "clientMutationId", + "description": "A unique identifier for the client performing the mutation.", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null + } + ], + "interfaces": null, + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "CreateCustomEmojiPayload", + "description": "Autogenerated return type of CreateCustomEmoji", + "fields": [ + { + "name": "clientMutationId", + "description": "A unique identifier for the client performing the mutation.", + "args": [ + + ], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "customEmoji", + "description": "The new custom emoji", + "args": [ + + ], + "type": { + "kind": "OBJECT", + "name": "CustomEmoji", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "errors", + "description": "Errors encountered during execution of the mutation.", + "args": [ + + ], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + } + } + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [ + + ], + "enumValues": null, + "possibleTypes": null + }, { "kind": "INPUT_OBJECT", "name": "CreateDiffNoteInput", @@ -12100,6 +12244,203 @@ } ] }, + { + "kind": "OBJECT", + "name": "CustomEmoji", + "description": "A custom emoji uploaded by user", + "fields": [ + { + "name": "external", + "description": "Whether the emoji is external link", + "args": [ + + ], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "file", + "description": "The link to file of the emoji", + "args": [ + + ], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "id", + "description": "The ID of the emoji", + "args": [ + + ], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "ID", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "name", + "description": "The name of the emoji", + "args": [ + + ], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [ + + ], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "CustomEmojiConnection", + "description": "The connection type for CustomEmoji.", + "fields": [ + { + "name": "edges", + "description": "A list of edges.", + "args": [ + + ], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "CustomEmojiEdge", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "nodes", + "description": "A list of nodes.", + "args": [ + + ], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "CustomEmoji", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "pageInfo", + "description": "Information to aid in pagination.", + "args": [ + + ], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "PageInfo", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [ + + ], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "CustomEmojiEdge", + "description": "An edge in a connection.", + "fields": [ + { + "name": "cursor", + "description": "A cursor for use in pagination.", + "args": [ + + ], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "node", + "description": "The item at the end of the edge.", + "args": [ + + ], + "type": { + "kind": "OBJECT", + "name": "CustomEmoji", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [ + + ], + "enumValues": null, + "possibleTypes": null + }, { "kind": "INPUT_OBJECT", "name": "DastOnDemandScanCreateInput", @@ -23575,6 +23916,59 @@ "isDeprecated": false, "deprecationReason": null }, + { + "name": "customEmoji", + "description": "Custom emoji within this namespace", + "args": [ + { + "name": "after", + "description": "Returns the elements in the list that come after the specified cursor.", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "before", + "description": "Returns the elements in the list that come before the specified cursor.", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "first", + "description": "Returns the first _n_ elements from the list.", + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "last", + "description": "Returns the last _n_ elements from the list.", + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": null + } + ], + "type": { + "kind": "OBJECT", + "name": "CustomEmojiConnection", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, { "name": "description", "description": "Description of the namespace", @@ -37652,6 +38046,33 @@ "isDeprecated": false, "deprecationReason": null }, + { + "name": "createCustomEmoji", + "description": null, + "args": [ + { + "name": "input", + "description": null, + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "INPUT_OBJECT", + "name": "CreateCustomEmojiInput", + "ofType": null + } + }, + "defaultValue": null + } + ], + "type": { + "kind": "OBJECT", + "name": "CreateCustomEmojiPayload", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, { "name": "createDiffNote", "description": null, @@ -40413,6 +40834,59 @@ "isDeprecated": false, "deprecationReason": null }, + { + "name": "customEmoji", + "description": "Custom emoji within this namespace", + "args": [ + { + "name": "after", + "description": "Returns the elements in the list that come after the specified cursor.", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "before", + "description": "Returns the elements in the list that come before the specified cursor.", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "first", + "description": "Returns the first _n_ elements from the list.", + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "last", + "description": "Returns the last _n_ elements from the list.", + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": null + } + ], + "type": { + "kind": "OBJECT", + "name": "CustomEmojiConnection", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, { "name": "description", "description": "Description of the namespace", diff --git a/spec/graphql/resolvers/custom_emoji_resolver_spec.rb b/spec/graphql/resolvers/custom_emoji_resolver_spec.rb new file mode 100644 index 00000000000000..53b63edefdfdbc --- /dev/null +++ b/spec/graphql/resolvers/custom_emoji_resolver_spec.rb @@ -0,0 +1,45 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Resolvers::CustomEmojiResolver do + include GraphqlHelpers + + let(:current_user) { create(:user) } + let_it_be(:group) { create(:group, :private) } + let(:custom_emoji) { create(:custom_emoji) } + + before do + group.add_developer(current_user) + group.custom_emoji << custom_emoji + end + + describe "#resolve" do + it 'returns emojis' do + result = resolve_custom_emoji(group.full_path, current_user) + + expect(result[:custom_emoji].size).to eq(1) + expect(result[:custom_emoji].first).to eq(custom_emoji) + end + + it 'returns nil if group does not exist' do + result = resolve_custom_emoji('random/group_path', current_user) + + expect(result).to be_nil + end + + context 'when user is unauthorized_user' do + it 'raise error' do + unauthorized_user = create(:user) + + expect do + resolve_custom_emoji(group.full_path, unauthorized_user) + end.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable) + end + end + end + + def resolve_custom_emoji(full_path, user) + resolve(described_class, args: { group_path: full_path }, ctx: { current_user: user } ) + end +end diff --git a/spec/requests/api/graphql/mutations/custom_emoji/create_spec.rb b/spec/requests/api/graphql/mutations/custom_emoji/create_spec.rb new file mode 100644 index 00000000000000..f28bf2aab734a9 --- /dev/null +++ b/spec/requests/api/graphql/mutations/custom_emoji/create_spec.rb @@ -0,0 +1,44 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'Creation of a new Custom Emoji' do + include GraphqlHelpers + + let_it_be(:current_user) { create(:user) } + let_it_be(:group) { create(:group) } + + let(:attributes) do + { + name: 'my_new_emoji', + file: 'https://example.com/image.png', + external: true + } + end + + let(:mutation) do + params = { group_path: group.full_path }.merge(attributes) + + graphql_mutation(:create_custom_emoji, params) + end + + def mutation_response + graphql_mutation_response(:create_custom_emoji) + end + + context 'when the user has no permission' do + it 'does not create custom emoji' do + expect { post_graphql_mutation(mutation, current_user: current_user) }.not_to change(CustomEmoji, :count) + end + end + + context 'when user has permission' do + before do + group.add_developer(current_user) + end + + it 'creates custom emoji' do + expect { post_graphql_mutation(mutation, current_user: current_user) }.to change(CustomEmoji, :count).by(1) + end + end +end -- GitLab From 6e2b6b46ae08252d018bd1017d47c98805790997 Mon Sep 17 00:00:00 2001 From: Rajendra Kadam Date: Tue, 3 Nov 2020 21:26:23 +0530 Subject: [PATCH 05/22] Update docs to match old file changes Update docs to old stage from the commits that were missed in a rebase --- app/graphql/mutations/custom_emoji/create.rb | 17 +++------------ .../resolvers/custom_emoji_resolver.rb | 4 +--- app/graphql/types/custom_emoji_type.rb | 4 ++-- app/graphql/types/group_type.rb | 3 +++ app/graphql/types/namespace_type.rb | 3 --- .../types/permission_types/custom_emoji.rb | 2 +- app/models/custom_emoji.rb | 4 +++- app/policies/group_policy.rb | 2 +- doc/api/graphql/reference/index.md | 21 +++++++++++++++++++ .../resolvers/custom_emoji_resolver_spec.rb | 5 ++--- spec/graphql/types/custom_emoji_type_spec.rb | 2 +- .../mutations/custom_emoji/create_spec.rb | 7 +++---- 12 files changed, 41 insertions(+), 33 deletions(-) diff --git a/app/graphql/mutations/custom_emoji/create.rb b/app/graphql/mutations/custom_emoji/create.rb index 835b34673bf184..1c2460fe95a411 100644 --- a/app/graphql/mutations/custom_emoji/create.rb +++ b/app/graphql/mutations/custom_emoji/create.rb @@ -30,30 +30,19 @@ class Create < BaseMutation required: true, description: 'Whether the emoji file is an external link' - def resolve(args) - group_path = args.delete(:group_path) - - validate_arguments!(args) - + def resolve(group_path:, **args) group = authorized_find!(group_path: group_path) - custom_emoji = group.custom_emoji.create!(args) + custom_emoji = group.custom_emoji.create(args) { - name: custom_emoji.valid? ? custom_emoji.name : nil, + custom_emoji: custom_emoji.valid? ? custom_emoji : nil, errors: errors_on_object(custom_emoji) } end private - def validate_arguments!(args) - if args.empty? - raise Gitlab::Graphql::Errors::ArgumentError, - 'The list of custom emoji attributes is empty' - end - end - def find_object(group_path:) resolve_group(full_path: group_path) end diff --git a/app/graphql/resolvers/custom_emoji_resolver.rb b/app/graphql/resolvers/custom_emoji_resolver.rb index 08fd3f158a987b..0e58fb605b28a8 100644 --- a/app/graphql/resolvers/custom_emoji_resolver.rb +++ b/app/graphql/resolvers/custom_emoji_resolver.rb @@ -11,9 +11,7 @@ class CustomEmojiResolver < BaseResolver required: true, description: 'The path of the group to use' - def resolve(**args) - group_path = args.delete(:group_path) - + def resolve(group_path:) group = model_by_full_path(Group, group_path).sync return unless group.presence diff --git a/app/graphql/types/custom_emoji_type.rb b/app/graphql/types/custom_emoji_type.rb index e9db93fd3142e3..70daddb80188e1 100644 --- a/app/graphql/types/custom_emoji_type.rb +++ b/app/graphql/types/custom_emoji_type.rb @@ -5,9 +5,9 @@ class CustomEmojiType < BaseObject graphql_name 'CustomEmoji' description 'A custom emoji uploaded by user' - authorize :read_emoji + authorize :read_custom_emoji - field :id, GraphQL::ID_TYPE, + field :id, ::Types::GlobalIDType[::CustomEmoji], null: false, description: 'The ID of the emoji' diff --git a/app/graphql/types/group_type.rb b/app/graphql/types/group_type.rb index d8555684efb314..d4b460ae582ad5 100644 --- a/app/graphql/types/group_type.rb +++ b/app/graphql/types/group_type.rb @@ -17,6 +17,9 @@ class GroupType < NamespaceType group.avatar_url(only_path: false) end + field :custom_emoji, Types::CustomEmojiType.connection_type, null: true, + description: 'Custom emoji within this namespace' + field :share_with_group_lock, GraphQL::BOOLEAN_TYPE, null: true, description: 'Indicates if sharing a project with another group within this group is prevented' diff --git a/app/graphql/types/namespace_type.rb b/app/graphql/types/namespace_type.rb index 957faec6540aca..fbdf049b755058 100644 --- a/app/graphql/types/namespace_type.rb +++ b/app/graphql/types/namespace_type.rb @@ -36,9 +36,6 @@ class NamespaceType < BaseObject field :projects, Types::ProjectType.connection_type, null: false, description: 'Projects within this namespace', resolver: ::Resolvers::NamespaceProjectsResolver - - field :custom_emoji, Types::CustomEmojiType.connection_type, null: true, - description: 'Custom emoji within this namespace' end end diff --git a/app/graphql/types/permission_types/custom_emoji.rb b/app/graphql/types/permission_types/custom_emoji.rb index 6791d165805e8d..0b2e7da44f54b5 100644 --- a/app/graphql/types/permission_types/custom_emoji.rb +++ b/app/graphql/types/permission_types/custom_emoji.rb @@ -5,7 +5,7 @@ module PermissionTypes class CustomEmoji < BasePermissionType graphql_name 'CustomEmojiPermissions' - abilities :create_custom_emoji, :read_emoji + abilities :create_custom_emoji, :read_custom_emoji end end end diff --git a/app/models/custom_emoji.rb b/app/models/custom_emoji.rb index c51c1ef3634697..4e0c5721c14dc4 100644 --- a/app/models/custom_emoji.rb +++ b/app/models/custom_emoji.rb @@ -3,6 +3,8 @@ class CustomEmoji < ApplicationRecord belongs_to :namespace, inverse_of: :custom_emoji + validates :external, inclusion: { in: [true] } # for now only external emoji are supported + validate :valid_emoji_name validates :namespace, presence: true @@ -10,7 +12,7 @@ class CustomEmoji < ApplicationRecord uniqueness: { scope: [:namespace_id, :name] }, presence: true, length: { maximum: 36 }, - format: { with: /\A[\w\-]+\z/ } + format: { with: /^([a-z0-9]+[-_]?)+[a-z0-9]+$/, multiline: true } private diff --git a/app/policies/group_policy.rb b/app/policies/group_policy.rb index 13b7c841bed68e..664fb40cbcf60a 100644 --- a/app/policies/group_policy.rb +++ b/app/policies/group_policy.rb @@ -101,7 +101,7 @@ class GroupPolicy < BasePolicy enable :read_label enable :read_board enable :read_group_member - enable :read_emoji + enable :read_custom_emoji end rule { ~can?(:read_group) }.policy do diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md index 34d30e8c7f1bc6..f134cb647b440d 100644 --- a/doc/api/graphql/reference/index.md +++ b/doc/api/graphql/reference/index.md @@ -630,6 +630,16 @@ Autogenerated return type of CreateClusterAgent. | `clusterAgent` | ClusterAgent | Cluster agent created after mutation | | `errors` | String! => Array | Errors encountered during execution of the mutation. | +### CreateCustomEmojiPayload + +Autogenerated return type of CreateCustomEmoji. + +| Field | Type | Description | +| ----- | ---- | ----------- | +| `clientMutationId` | String | A unique identifier for the client performing the mutation. | +| `customEmoji` | CustomEmoji | The new custom emoji | +| `errors` | String! => Array | Errors encountered during execution of the mutation. | + ### CreateDiffNotePayload Autogenerated return type of CreateDiffNote. @@ -721,6 +731,17 @@ Autogenerated return type of CreateTestCase. | `errors` | String! => Array | Errors encountered during execution of the mutation. | | `testCase` | Issue | The test case created | +### CustomEmoji + +A custom emoji uploaded by user. + +| Field | Type | Description | +| ----- | ---- | ----------- | +| `external` | Boolean! | Whether the emoji is external link | +| `file` | String! | The link to file of the emoji | +| `id` | CustomEmojiID! | The ID of the emoji | +| `name` | String! | The name of the emoji | + ### DastOnDemandScanCreatePayload Autogenerated return type of DastOnDemandScanCreate. diff --git a/spec/graphql/resolvers/custom_emoji_resolver_spec.rb b/spec/graphql/resolvers/custom_emoji_resolver_spec.rb index 53b63edefdfdbc..fd585a53f2f9c2 100644 --- a/spec/graphql/resolvers/custom_emoji_resolver_spec.rb +++ b/spec/graphql/resolvers/custom_emoji_resolver_spec.rb @@ -5,13 +5,12 @@ RSpec.describe Resolvers::CustomEmojiResolver do include GraphqlHelpers - let(:current_user) { create(:user) } + let_it_be(:current_user) { create(:user) } let_it_be(:group) { create(:group, :private) } - let(:custom_emoji) { create(:custom_emoji) } + let_it_be(:custom_emoji) { create(:custom_emoji, group: group) } before do group.add_developer(current_user) - group.custom_emoji << custom_emoji end describe "#resolve" do diff --git a/spec/graphql/types/custom_emoji_type_spec.rb b/spec/graphql/types/custom_emoji_type_spec.rb index 53904ce354d5d5..57e518c8d39f3c 100644 --- a/spec/graphql/types/custom_emoji_type_spec.rb +++ b/spec/graphql/types/custom_emoji_type_spec.rb @@ -5,7 +5,7 @@ RSpec.describe GitlabSchema.types['CustomEmoji'] do specify { expect(described_class.graphql_name).to eq('CustomEmoji') } - specify { expect(described_class).to require_graphql_authorizations(:read_emoji) } + specify { expect(described_class).to require_graphql_authorizations(:read_custom_emoji) } specify { expect(described_class).to have_graphql_fields(:id, :name, :file, :external) } end diff --git a/spec/requests/api/graphql/mutations/custom_emoji/create_spec.rb b/spec/requests/api/graphql/mutations/custom_emoji/create_spec.rb index f28bf2aab734a9..f1a5d8b70f8f97 100644 --- a/spec/requests/api/graphql/mutations/custom_emoji/create_spec.rb +++ b/spec/requests/api/graphql/mutations/custom_emoji/create_spec.rb @@ -12,14 +12,13 @@ { name: 'my_new_emoji', file: 'https://example.com/image.png', - external: true + external: true, + group_path: group.full_path } end let(:mutation) do - params = { group_path: group.full_path }.merge(attributes) - - graphql_mutation(:create_custom_emoji, params) + graphql_mutation(:create_custom_emoji, attributes) end def mutation_response -- GitLab From 21b9eacef0ace3b5944fbd6ac9173adfcce4552a Mon Sep 17 00:00:00 2001 From: Rajendra Kadam Date: Tue, 3 Nov 2020 22:08:19 +0530 Subject: [PATCH 06/22] Update docs with command bundle exec rake gitlab:graphql:schema:dump --- .../graphql/reference/gitlab_schema.graphql | 32 ++------- doc/api/graphql/reference/gitlab_schema.json | 65 ++++--------------- 2 files changed, 17 insertions(+), 80 deletions(-) diff --git a/doc/api/graphql/reference/gitlab_schema.graphql b/doc/api/graphql/reference/gitlab_schema.graphql index 3633d95ecb0ccd..5eab149b326b5f 100644 --- a/doc/api/graphql/reference/gitlab_schema.graphql +++ b/doc/api/graphql/reference/gitlab_schema.graphql @@ -4498,7 +4498,7 @@ type CustomEmoji { """ The ID of the emoji """ - id: ID! + id: CustomEmojiID! """ The name of the emoji @@ -4541,6 +4541,11 @@ type CustomEmojiEdge { node: CustomEmoji } +""" +Identifier of CustomEmoji +""" +scalar CustomEmojiID + """ Autogenerated input type of DastOnDemandScanCreate """ @@ -13797,31 +13802,6 @@ type Namespace { """ containsLockedProjects: Boolean! - """ - Custom emoji within this namespace - """ - customEmoji( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): CustomEmojiConnection - """ Description of the namespace """ diff --git a/doc/api/graphql/reference/gitlab_schema.json b/doc/api/graphql/reference/gitlab_schema.json index 483f68980ac0dc..4604135922c6ae 100644 --- a/doc/api/graphql/reference/gitlab_schema.json +++ b/doc/api/graphql/reference/gitlab_schema.json @@ -12296,7 +12296,7 @@ "name": null, "ofType": { "kind": "SCALAR", - "name": "ID", + "name": "CustomEmojiID", "ofType": null } }, @@ -12441,6 +12441,16 @@ "enumValues": null, "possibleTypes": null }, + { + "kind": "SCALAR", + "name": "CustomEmojiID", + "description": "Identifier of CustomEmoji", + "fields": null, + "inputFields": null, + "interfaces": null, + "enumValues": null, + "possibleTypes": null + }, { "kind": "INPUT_OBJECT", "name": "DastOnDemandScanCreateInput", @@ -40834,59 +40844,6 @@ "isDeprecated": false, "deprecationReason": null }, - { - "name": "customEmoji", - "description": "Custom emoji within this namespace", - "args": [ - { - "name": "after", - "description": "Returns the elements in the list that come after the specified cursor.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": "Returns the elements in the list that come before the specified cursor.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": "Returns the first _n_ elements from the list.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": "Returns the last _n_ elements from the list.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "CustomEmojiConnection", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, { "name": "description", "description": "Description of the namespace", -- GitLab From 4581a47d0f925c63b09148a5683177c97815d0e4 Mon Sep 17 00:00:00 2001 From: Rajendra Kadam Date: Tue, 3 Nov 2020 22:18:58 +0530 Subject: [PATCH 07/22] Remove resolver --- .../resolvers/custom_emoji_resolver.rb | 34 -------------- .../resolvers/custom_emoji_resolver_spec.rb | 44 ------------------- 2 files changed, 78 deletions(-) delete mode 100644 app/graphql/resolvers/custom_emoji_resolver.rb delete mode 100644 spec/graphql/resolvers/custom_emoji_resolver_spec.rb diff --git a/app/graphql/resolvers/custom_emoji_resolver.rb b/app/graphql/resolvers/custom_emoji_resolver.rb deleted file mode 100644 index 0e58fb605b28a8..00000000000000 --- a/app/graphql/resolvers/custom_emoji_resolver.rb +++ /dev/null @@ -1,34 +0,0 @@ -# frozen_string_literal: true - -module Resolvers - class CustomEmojiResolver < BaseResolver - include Gitlab::Graphql::Authorize::AuthorizeResource - prepend FullPathResolver - - type Types::CustomEmojiType, null: true - - argument :group_path, GraphQL::ID_TYPE, - required: true, - description: 'The path of the group to use' - - def resolve(group_path:) - group = model_by_full_path(Group, group_path).sync - - return unless group.presence - - authorize!(group) - - emoji = group.custom_emoji rescue [] - - { - custom_emoji: emoji.presence ? emoji : nil - } - end - - private - - def authorize!(group) - Ability.allowed?(context[:current_user], :read_group, group) || raise_resource_not_available_error! - end - end -end diff --git a/spec/graphql/resolvers/custom_emoji_resolver_spec.rb b/spec/graphql/resolvers/custom_emoji_resolver_spec.rb deleted file mode 100644 index fd585a53f2f9c2..00000000000000 --- a/spec/graphql/resolvers/custom_emoji_resolver_spec.rb +++ /dev/null @@ -1,44 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe Resolvers::CustomEmojiResolver do - include GraphqlHelpers - - let_it_be(:current_user) { create(:user) } - let_it_be(:group) { create(:group, :private) } - let_it_be(:custom_emoji) { create(:custom_emoji, group: group) } - - before do - group.add_developer(current_user) - end - - describe "#resolve" do - it 'returns emojis' do - result = resolve_custom_emoji(group.full_path, current_user) - - expect(result[:custom_emoji].size).to eq(1) - expect(result[:custom_emoji].first).to eq(custom_emoji) - end - - it 'returns nil if group does not exist' do - result = resolve_custom_emoji('random/group_path', current_user) - - expect(result).to be_nil - end - - context 'when user is unauthorized_user' do - it 'raise error' do - unauthorized_user = create(:user) - - expect do - resolve_custom_emoji(group.full_path, unauthorized_user) - end.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable) - end - end - end - - def resolve_custom_emoji(full_path, user) - resolve(described_class, args: { group_path: full_path }, ctx: { current_user: user } ) - end -end -- GitLab From 86c6e803b25b9769f0b8f8de8ebe6940978f7f9d Mon Sep 17 00:00:00 2001 From: Rajendra Kadam Date: Wed, 4 Nov 2020 10:57:08 +0530 Subject: [PATCH 08/22] Add test for checking response and remove reduntant method --- .../api/graphql/mutations/custom_emoji/create_spec.rb | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/spec/requests/api/graphql/mutations/custom_emoji/create_spec.rb b/spec/requests/api/graphql/mutations/custom_emoji/create_spec.rb index f1a5d8b70f8f97..0cd581ba6b67ba 100644 --- a/spec/requests/api/graphql/mutations/custom_emoji/create_spec.rb +++ b/spec/requests/api/graphql/mutations/custom_emoji/create_spec.rb @@ -21,10 +21,6 @@ graphql_mutation(:create_custom_emoji, attributes) end - def mutation_response - graphql_mutation_response(:create_custom_emoji) - end - context 'when the user has no permission' do it 'does not create custom emoji' do expect { post_graphql_mutation(mutation, current_user: current_user) }.not_to change(CustomEmoji, :count) @@ -38,6 +34,11 @@ def mutation_response it 'creates custom emoji' do expect { post_graphql_mutation(mutation, current_user: current_user) }.to change(CustomEmoji, :count).by(1) + + gql_response = graphql_mutation_response(:create_custom_emoji) + expect(gql_response['errors']).to eq([]) + expect(gql_response['customEmoji']['name']).to eq(attributes[:name]) + expect(gql_response['customEmoji']['file']).to eq(attributes[:file]) end end end -- GitLab From ae7bdd1b427af80c990d87c10e3c9e8164728b49 Mon Sep 17 00:00:00 2001 From: Rajendra Kadam Date: Thu, 5 Nov 2020 13:06:55 +0530 Subject: [PATCH 09/22] Add query request specs and add suggestions to custom_emoji model Update query request to check response in groups and implement suggestions in model to add validations --- app/models/custom_emoji.rb | 6 ++-- app/policies/custom_emoji_policy.rb | 2 +- spec/models/custom_emoji_spec.rb | 12 +++++-- .../api/graphql/custom_emoji_query_spec.rb | 36 +++++++++++++++++++ 4 files changed, 51 insertions(+), 5 deletions(-) create mode 100644 spec/requests/api/graphql/custom_emoji_query_spec.rb diff --git a/app/models/custom_emoji.rb b/app/models/custom_emoji.rb index 4e0c5721c14dc4..0a5cb0e2ab5466 100644 --- a/app/models/custom_emoji.rb +++ b/app/models/custom_emoji.rb @@ -3,16 +3,18 @@ class CustomEmoji < ApplicationRecord belongs_to :namespace, inverse_of: :custom_emoji + belongs_to :group, -> { where(type: 'Group') }, foreign_key: 'namespace_id' + validates :external, inclusion: { in: [true] } # for now only external emoji are supported validate :valid_emoji_name - validates :namespace, presence: true + validates :group, presence: true validates :name, uniqueness: { scope: [:namespace_id, :name] }, presence: true, length: { maximum: 36 }, - format: { with: /^([a-z0-9]+[-_]?)+[a-z0-9]+$/, multiline: true } + format: { with: /([a-z0-9]+[-_]?)+[a-z0-9]+/ } private diff --git a/app/policies/custom_emoji_policy.rb b/app/policies/custom_emoji_policy.rb index e62641f6013d83..ba73b9a378206a 100644 --- a/app/policies/custom_emoji_policy.rb +++ b/app/policies/custom_emoji_policy.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true class CustomEmojiPolicy < BasePolicy - delegate { @subject.namespace } + delegate { @subject.group } end diff --git a/spec/models/custom_emoji_spec.rb b/spec/models/custom_emoji_spec.rb index 836c41391074ae..c7a9682aeff39c 100644 --- a/spec/models/custom_emoji_spec.rb +++ b/spec/models/custom_emoji_spec.rb @@ -13,20 +13,28 @@ describe 'exclusion of duplicated emoji' do let(:emoji_name) { Gitlab::Emoji.emojis_names.sample } + let(:group) { create(:group, :private) } it 'disallows emoji names of built-in emoji' do - new_emoji = build(:custom_emoji, name: emoji_name) + new_emoji = build(:custom_emoji, name: emoji_name, group: group) expect(new_emoji).not_to be_valid expect(new_emoji.errors.messages).to eq(name: ["#{emoji_name} is already being used for another emoji"]) end it 'disallows duplicate custom emoji names within namespace' do - old_emoji = create(:custom_emoji) + old_emoji = create(:custom_emoji, group: group) new_emoji = build(:custom_emoji, name: old_emoji.name, namespace: old_emoji.namespace) expect(new_emoji).not_to be_valid expect(new_emoji.errors.messages).to eq(name: ["has already been taken"]) end + + it 'disallows custom emoji without a group' do + emoji = build(:custom_emoji, name: 'new_name') + + expect(emoji).not_to be_valid + expect(emoji.errors.messages).to eq(group: ["can't be blank"]) + end end end diff --git a/spec/requests/api/graphql/custom_emoji_query_spec.rb b/spec/requests/api/graphql/custom_emoji_query_spec.rb new file mode 100644 index 00000000000000..c6775284a1e49c --- /dev/null +++ b/spec/requests/api/graphql/custom_emoji_query_spec.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'getting custom emoji within namespace' do + include GraphqlHelpers + + let_it_be(:current_user) { create(:user) } + let_it_be(:group) { create(:group, :private) } + let_it_be(:custom_emoji) { create(:custom_emoji, group: group) } + + before do + group.add_developer(current_user) + end + + describe "Query CustomEmoji on Group" do + def custom_emoji_query(group) + graphql_query_for('group', 'fullPath' => group.full_path) + end + + it 'returns emojis when authorised' do + post_graphql(custom_emoji_query(group), current_user: current_user) + + expect(response).to have_gitlab_http_status(:ok) + expect(graphql_data['group']['customEmoji']['nodes'].count). to eq(1) + expect(graphql_data['group']['customEmoji']['nodes'].first['name']). to eq(custom_emoji.name) + end + + it 'returns nil when unauthorised' do + user = create(:user) + post_graphql(custom_emoji_query(group), current_user: user) + + expect(graphql_data['group']).to be_nil + end + end +end -- GitLab From ce1836817a222d05b80271eae046616b841af7ae Mon Sep 17 00:00:00 2001 From: Rajendra Kadam Date: Thu, 5 Nov 2020 13:21:09 +0530 Subject: [PATCH 10/22] Add link to issue in the model --- app/models/custom_emoji.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/app/models/custom_emoji.rb b/app/models/custom_emoji.rb index 0a5cb0e2ab5466..5e1d19452cc985 100644 --- a/app/models/custom_emoji.rb +++ b/app/models/custom_emoji.rb @@ -5,6 +5,7 @@ class CustomEmoji < ApplicationRecord belongs_to :group, -> { where(type: 'Group') }, foreign_key: 'namespace_id' + # See https://gitlab.com/gitlab-org/gitlab/-/issues/230467 validates :external, inclusion: { in: [true] } # for now only external emoji are supported validate :valid_emoji_name -- GitLab From 9e0d2eafd36013dacb87c7eb561572114107048e Mon Sep 17 00:00:00 2001 From: Rajendra Kadam Date: Thu, 5 Nov 2020 16:29:13 +0530 Subject: [PATCH 11/22] Fix factory failure and model failure with updated factories --- spec/factories/custom_emoji.rb | 1 + spec/models/custom_emoji_spec.rb | 9 +-------- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/spec/factories/custom_emoji.rb b/spec/factories/custom_emoji.rb index 2d185794ac9967..1b2a92a11a4058 100644 --- a/spec/factories/custom_emoji.rb +++ b/spec/factories/custom_emoji.rb @@ -4,6 +4,7 @@ factory :custom_emoji, class: 'CustomEmoji' do sequence(:name) { |n| "custom_emoji#{n}" } namespace + group file { fixture_file_upload(Rails.root.join('spec/fixtures/dk.png')) } end end diff --git a/spec/models/custom_emoji_spec.rb b/spec/models/custom_emoji_spec.rb index c7a9682aeff39c..3174fbce61289c 100644 --- a/spec/models/custom_emoji_spec.rb +++ b/spec/models/custom_emoji_spec.rb @@ -24,17 +24,10 @@ it 'disallows duplicate custom emoji names within namespace' do old_emoji = create(:custom_emoji, group: group) - new_emoji = build(:custom_emoji, name: old_emoji.name, namespace: old_emoji.namespace) + new_emoji = build(:custom_emoji, name: old_emoji.name, namespace: old_emoji.namespace, group: group) expect(new_emoji).not_to be_valid expect(new_emoji.errors.messages).to eq(name: ["has already been taken"]) end - - it 'disallows custom emoji without a group' do - emoji = build(:custom_emoji, name: 'new_name') - - expect(emoji).not_to be_valid - expect(emoji.errors.messages).to eq(group: ["can't be blank"]) - end end end -- GitLab From 3d6a2d286cef90178734dfb353f162c77264c264 Mon Sep 17 00:00:00 2001 From: Rajendra Kadam Date: Thu, 5 Nov 2020 16:58:28 +0530 Subject: [PATCH 12/22] Add custom_emoji GQL API behind feature flag --- app/graphql/types/group_type.rb | 3 ++- app/graphql/types/mutation_type.rb | 2 +- config/feature_flags/ops/custom_emoji.yml | 8 ++++++++ 3 files changed, 11 insertions(+), 2 deletions(-) create mode 100644 config/feature_flags/ops/custom_emoji.yml diff --git a/app/graphql/types/group_type.rb b/app/graphql/types/group_type.rb index d4b460ae582ad5..2f17a4f936510e 100644 --- a/app/graphql/types/group_type.rb +++ b/app/graphql/types/group_type.rb @@ -18,7 +18,8 @@ class GroupType < NamespaceType end field :custom_emoji, Types::CustomEmojiType.connection_type, null: true, - description: 'Custom emoji within this namespace' + description: 'Custom emoji within this namespace', + feature_flag: :custom_emoji field :share_with_group_lock, GraphQL::BOOLEAN_TYPE, null: true, description: 'Indicates if sharing a project with another group within this group is prevented' diff --git a/app/graphql/types/mutation_type.rb b/app/graphql/types/mutation_type.rb index 15e91c0dd75980..75ccac6d590b6b 100644 --- a/app/graphql/types/mutation_type.rb +++ b/app/graphql/types/mutation_type.rb @@ -29,7 +29,7 @@ class MutationType < BaseObject mount_mutation Mutations::Boards::Lists::Destroy mount_mutation Mutations::Branches::Create, calls_gitaly: true mount_mutation Mutations::Commits::Create, calls_gitaly: true - mount_mutation Mutations::CustomEmoji::Create + mount_mutation Mutations::CustomEmoji::Create, feature_flag: :custom_emoji mount_mutation Mutations::Discussions::ToggleResolve mount_mutation Mutations::Issues::Create mount_mutation Mutations::Issues::SetAssignees diff --git a/config/feature_flags/ops/custom_emoji.yml b/config/feature_flags/ops/custom_emoji.yml new file mode 100644 index 00000000000000..34fb9f6f965c2e --- /dev/null +++ b/config/feature_flags/ops/custom_emoji.yml @@ -0,0 +1,8 @@ +--- +name: custom_emoji +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/37911 +rollout_issue_url: +milestone: '13.6' +type: ops +group: group::project management +default_enabled: false -- GitLab From fd45534da117d18b59436d7ba8cc53f10ba6da6f Mon Sep 17 00:00:00 2001 From: Rajendra Kadam Date: Thu, 5 Nov 2020 17:01:19 +0530 Subject: [PATCH 13/22] Update docs after adding feature flag --- doc/api/graphql/reference/gitlab_schema.graphql | 6 +++++- doc/api/graphql/reference/gitlab_schema.json | 4 ++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/doc/api/graphql/reference/gitlab_schema.graphql b/doc/api/graphql/reference/gitlab_schema.graphql index 5eab149b326b5f..0126bf0ba44610 100644 --- a/doc/api/graphql/reference/gitlab_schema.graphql +++ b/doc/api/graphql/reference/gitlab_schema.graphql @@ -8632,7 +8632,7 @@ type Group { containsLockedProjects: Boolean! """ - Custom emoji within this namespace + Custom emoji within this namespace. Available only when feature flag `custom_emoji` is enabled """ customEmoji( """ @@ -13641,6 +13641,10 @@ type Mutation { createBoard(input: CreateBoardInput!): CreateBoardPayload createBranch(input: CreateBranchInput!): CreateBranchPayload createClusterAgent(input: CreateClusterAgentInput!): CreateClusterAgentPayload + + """ + . Available only when feature flag `custom_emoji` is enabled + """ createCustomEmoji(input: CreateCustomEmojiInput!): CreateCustomEmojiPayload createDiffNote(input: CreateDiffNoteInput!): CreateDiffNotePayload createEpic(input: CreateEpicInput!): CreateEpicPayload diff --git a/doc/api/graphql/reference/gitlab_schema.json b/doc/api/graphql/reference/gitlab_schema.json index 4604135922c6ae..5cfccde4f7eb56 100644 --- a/doc/api/graphql/reference/gitlab_schema.json +++ b/doc/api/graphql/reference/gitlab_schema.json @@ -23928,7 +23928,7 @@ }, { "name": "customEmoji", - "description": "Custom emoji within this namespace", + "description": "Custom emoji within this namespace. Available only when feature flag `custom_emoji` is enabled", "args": [ { "name": "after", @@ -38058,7 +38058,7 @@ }, { "name": "createCustomEmoji", - "description": null, + "description": ". Available only when feature flag `custom_emoji` is enabled", "args": [ { "name": "input", -- GitLab From 9c1eae94ab3031c9910a64bf66726cbebadb4468 Mon Sep 17 00:00:00 2001 From: Rajendra Kadam Date: Thu, 5 Nov 2020 20:17:58 +0530 Subject: [PATCH 14/22] Move feature flag to development, and stub ff in tests --- config/feature_flags/ops/custom_emoji.yml | 8 -------- spec/requests/api/graphql/custom_emoji_query_spec.rb | 1 + 2 files changed, 1 insertion(+), 8 deletions(-) delete mode 100644 config/feature_flags/ops/custom_emoji.yml diff --git a/config/feature_flags/ops/custom_emoji.yml b/config/feature_flags/ops/custom_emoji.yml deleted file mode 100644 index 34fb9f6f965c2e..00000000000000 --- a/config/feature_flags/ops/custom_emoji.yml +++ /dev/null @@ -1,8 +0,0 @@ ---- -name: custom_emoji -introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/37911 -rollout_issue_url: -milestone: '13.6' -type: ops -group: group::project management -default_enabled: false diff --git a/spec/requests/api/graphql/custom_emoji_query_spec.rb b/spec/requests/api/graphql/custom_emoji_query_spec.rb index c6775284a1e49c..d5a423d0ebae09 100644 --- a/spec/requests/api/graphql/custom_emoji_query_spec.rb +++ b/spec/requests/api/graphql/custom_emoji_query_spec.rb @@ -10,6 +10,7 @@ let_it_be(:custom_emoji) { create(:custom_emoji, group: group) } before do + stub_feature_flags(custom_emoji: true) group.add_developer(current_user) end -- GitLab From e67263140446e7dcc70dac254212dd274df83c8c Mon Sep 17 00:00:00 2001 From: Rajendra Kadam Date: Thu, 5 Nov 2020 20:21:24 +0530 Subject: [PATCH 15/22] Add ff yml file --- config/feature_flags/development/custom_emoji.yml | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 config/feature_flags/development/custom_emoji.yml diff --git a/config/feature_flags/development/custom_emoji.yml b/config/feature_flags/development/custom_emoji.yml new file mode 100644 index 00000000000000..64c53c29fdb85f --- /dev/null +++ b/config/feature_flags/development/custom_emoji.yml @@ -0,0 +1,8 @@ +--- +name: custom_emoji +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/37911 +rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/231317 +milestone: '13.6' +type: development +group: group::project management +default_enabled: false -- GitLab From 31b8c9b2c303b95ff8a7f540ee1e34a4396132f7 Mon Sep 17 00:00:00 2001 From: Rajendra Kadam Date: Fri, 6 Nov 2020 08:57:33 +0530 Subject: [PATCH 16/22] Add public url check on file and fix factory to use file link --- app/models/custom_emoji.rb | 4 +++- spec/factories/custom_emoji.rb | 2 +- spec/models/custom_emoji_spec.rb | 7 +++++++ 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/app/models/custom_emoji.rb b/app/models/custom_emoji.rb index 5e1d19452cc985..6c672f6a33de29 100644 --- a/app/models/custom_emoji.rb +++ b/app/models/custom_emoji.rb @@ -8,6 +8,8 @@ class CustomEmoji < ApplicationRecord # See https://gitlab.com/gitlab-org/gitlab/-/issues/230467 validates :external, inclusion: { in: [true] } # for now only external emoji are supported + validates :file, public_url: true, if: :external + validate :valid_emoji_name validates :group, presence: true @@ -15,7 +17,7 @@ class CustomEmoji < ApplicationRecord uniqueness: { scope: [:namespace_id, :name] }, presence: true, length: { maximum: 36 }, - format: { with: /([a-z0-9]+[-_]?)+[a-z0-9]+/ } + format: { with: /\A([a-z0-9]+[-_]?)+[a-z0-9]+\z/ } private diff --git a/spec/factories/custom_emoji.rb b/spec/factories/custom_emoji.rb index 1b2a92a11a4058..ba1ae11c18d668 100644 --- a/spec/factories/custom_emoji.rb +++ b/spec/factories/custom_emoji.rb @@ -5,6 +5,6 @@ sequence(:name) { |n| "custom_emoji#{n}" } namespace group - file { fixture_file_upload(Rails.root.join('spec/fixtures/dk.png')) } + file { 'https://gitlab.com/images/partyparrot.png' } end end diff --git a/spec/models/custom_emoji_spec.rb b/spec/models/custom_emoji_spec.rb index 3174fbce61289c..62380299ea09b6 100644 --- a/spec/models/custom_emoji_spec.rb +++ b/spec/models/custom_emoji_spec.rb @@ -29,5 +29,12 @@ expect(new_emoji).not_to be_valid expect(new_emoji.errors.messages).to eq(name: ["has already been taken"]) end + + it 'disallows non http and https file value' do + emoji = build(:custom_emoji, name: 'new-name', group: group, file: 'ftp://some-url.in') + + expect(emoji).not_to be_valid + expect(emoji.errors.messages).to eq(file: ["is blocked: Only allowed schemes are http, https"]) + end end end -- GitLab From d9d07acb8bdc6e76e166fdc025733c8053410edb Mon Sep 17 00:00:00 2001 From: Rajendra Kadam Date: Sat, 7 Nov 2020 15:04:55 +0530 Subject: [PATCH 17/22] Add suggestion on comment --- app/models/custom_emoji.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/models/custom_emoji.rb b/app/models/custom_emoji.rb index 6c672f6a33de29..ed22d4ba231f9a 100644 --- a/app/models/custom_emoji.rb +++ b/app/models/custom_emoji.rb @@ -5,8 +5,8 @@ class CustomEmoji < ApplicationRecord belongs_to :group, -> { where(type: 'Group') }, foreign_key: 'namespace_id' - # See https://gitlab.com/gitlab-org/gitlab/-/issues/230467 - validates :external, inclusion: { in: [true] } # for now only external emoji are supported + # For now only external emoji are supported. See https://gitlab.com/gitlab-org/gitlab/-/issues/230467 + validates :external, inclusion: { in: [true] } validates :file, public_url: true, if: :external -- GitLab From eb92bc5ebcf215f86d9de0f05c20373a362423bf Mon Sep 17 00:00:00 2001 From: Rajendra Kadam Date: Sat, 7 Nov 2020 16:12:42 +0530 Subject: [PATCH 18/22] Update docs --- doc/api/graphql/reference/index.md | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md index f134cb647b440d..42a4c9b61f5325 100644 --- a/doc/api/graphql/reference/index.md +++ b/doc/api/graphql/reference/index.md @@ -1413,6 +1413,7 @@ Autogenerated return type of EpicTreeReorder. | `codeCoverageActivities` | CodeCoverageActivityConnection | Represents the code coverage activity for this group. Available only when feature flag `group_coverage_data_report_graph` is enabled | | `containerRepositories` | ContainerRepositoryConnection | Container repositories of the project | | `containsLockedProjects` | Boolean! | Includes at least one project where the repository size exceeds the limit | +| `customEmoji` | CustomEmojiConnection | Custom emoji within this namespace. Available only when feature flag `custom_emoji` is enabled | | `description` | String | Description of the namespace | | `descriptionHtml` | String | The GitLab Flavored Markdown rendering of `description` | | `emailsDisabled` | Boolean | Indicates if a group has email notifications disabled | -- GitLab From dbfef1060539b5a1ae10479ad253a5831988b9c4 Mon Sep 17 00:00:00 2001 From: Rajendra Kadam Date: Fri, 13 Nov 2020 12:20:04 +0530 Subject: [PATCH 19/22] Remove external from create fields and add file --- app/graphql/mutations/custom_emoji/create.rb | 9 ++++----- doc/api/graphql/reference/gitlab_schema.graphql | 15 +++++---------- doc/api/graphql/reference/gitlab_schema.json | 16 +--------------- .../mutations/custom_emoji/create_spec.rb | 5 ++--- 4 files changed, 12 insertions(+), 33 deletions(-) diff --git a/app/graphql/mutations/custom_emoji/create.rb b/app/graphql/mutations/custom_emoji/create.rb index 1c2460fe95a411..34c00af430f234 100644 --- a/app/graphql/mutations/custom_emoji/create.rb +++ b/app/graphql/mutations/custom_emoji/create.rb @@ -22,16 +22,15 @@ class Create < BaseMutation required: true, description: 'Name of the emoji' - argument :file, GraphQL::STRING_TYPE, + argument :url, GraphQL::STRING_TYPE, required: true, description: 'Location of the emoji file' - argument :external, GraphQL::BOOLEAN_TYPE, - required: true, - description: 'Whether the emoji file is an external link' - def resolve(group_path:, **args) group = authorized_find!(group_path: group_path) + # See https://gitlab.com/gitlab-org/gitlab/-/merge_requests/37911#note_444682238 + args[:file] = args.delete(:url) + args[:external] = true custom_emoji = group.custom_emoji.create(args) diff --git a/doc/api/graphql/reference/gitlab_schema.graphql b/doc/api/graphql/reference/gitlab_schema.graphql index 0126bf0ba44610..4d138d0d2092cd 100644 --- a/doc/api/graphql/reference/gitlab_schema.graphql +++ b/doc/api/graphql/reference/gitlab_schema.graphql @@ -3843,16 +3843,6 @@ input CreateCustomEmojiInput { """ clientMutationId: String - """ - Whether the emoji file is an external link - """ - external: Boolean! - - """ - Location of the emoji file - """ - file: String! - """ Namespace full path the emoji is associated with """ @@ -3862,6 +3852,11 @@ input CreateCustomEmojiInput { Name of the emoji """ name: String! + + """ + Location of the emoji file + """ + url: String! } """ diff --git a/doc/api/graphql/reference/gitlab_schema.json b/doc/api/graphql/reference/gitlab_schema.json index 5cfccde4f7eb56..ade60b04fd8fb8 100644 --- a/doc/api/graphql/reference/gitlab_schema.json +++ b/doc/api/graphql/reference/gitlab_schema.json @@ -10512,7 +10512,7 @@ "defaultValue": null }, { - "name": "file", + "name": "url", "description": "Location of the emoji file", "type": { "kind": "NON_NULL", @@ -10525,20 +10525,6 @@ }, "defaultValue": null }, - { - "name": "external", - "description": "Whether the emoji file is an external link", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - } - }, - "defaultValue": null - }, { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", diff --git a/spec/requests/api/graphql/mutations/custom_emoji/create_spec.rb b/spec/requests/api/graphql/mutations/custom_emoji/create_spec.rb index 0cd581ba6b67ba..bf36c288298127 100644 --- a/spec/requests/api/graphql/mutations/custom_emoji/create_spec.rb +++ b/spec/requests/api/graphql/mutations/custom_emoji/create_spec.rb @@ -11,8 +11,7 @@ let(:attributes) do { name: 'my_new_emoji', - file: 'https://example.com/image.png', - external: true, + url: 'https://example.com/image.png', group_path: group.full_path } end @@ -38,7 +37,7 @@ gql_response = graphql_mutation_response(:create_custom_emoji) expect(gql_response['errors']).to eq([]) expect(gql_response['customEmoji']['name']).to eq(attributes[:name]) - expect(gql_response['customEmoji']['file']).to eq(attributes[:file]) + expect(gql_response['customEmoji']['file']).to eq(attributes[:url]) end end end -- GitLab From 18140c5b0f265ff68e547b4031db612bfc82fe02 Mon Sep 17 00:00:00 2001 From: Rajendra Kadam Date: Sat, 14 Nov 2020 15:17:02 +0530 Subject: [PATCH 20/22] Use as: :file to avoid var injection --- app/graphql/mutations/custom_emoji/create.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/graphql/mutations/custom_emoji/create.rb b/app/graphql/mutations/custom_emoji/create.rb index 34c00af430f234..d912a29d12e7b9 100644 --- a/app/graphql/mutations/custom_emoji/create.rb +++ b/app/graphql/mutations/custom_emoji/create.rb @@ -24,12 +24,12 @@ class Create < BaseMutation argument :url, GraphQL::STRING_TYPE, required: true, + as: :file, description: 'Location of the emoji file' def resolve(group_path:, **args) group = authorized_find!(group_path: group_path) # See https://gitlab.com/gitlab-org/gitlab/-/merge_requests/37911#note_444682238 - args[:file] = args.delete(:url) args[:external] = true custom_emoji = group.custom_emoji.create(args) -- GitLab From f72175f894a96fe05e988f41cfc352b430a73f98 Mon Sep 17 00:00:00 2001 From: Rajendra Kadam Date: Sun, 15 Nov 2020 12:44:33 +0530 Subject: [PATCH 21/22] Change file field to url and update docs --- app/graphql/types/custom_emoji_type.rb | 5 +++-- .../graphql/reference/gitlab_schema.graphql | 12 ++++++------ doc/api/graphql/reference/gitlab_schema.json | 18 +++++++++--------- doc/api/graphql/reference/index.md | 4 ++-- 4 files changed, 20 insertions(+), 19 deletions(-) diff --git a/app/graphql/types/custom_emoji_type.rb b/app/graphql/types/custom_emoji_type.rb index 70daddb80188e1..f7d1a7800bca25 100644 --- a/app/graphql/types/custom_emoji_type.rb +++ b/app/graphql/types/custom_emoji_type.rb @@ -15,12 +15,13 @@ class CustomEmojiType < BaseObject null: false, description: 'The name of the emoji' - field :file, GraphQL::STRING_TYPE, + field :url, GraphQL::STRING_TYPE, null: false, + method: :file, description: 'The link to file of the emoji' field :external, GraphQL::BOOLEAN_TYPE, null: false, - description: 'Whether the emoji is external link' + description: 'Whether the emoji is an external link' end end diff --git a/doc/api/graphql/reference/gitlab_schema.graphql b/doc/api/graphql/reference/gitlab_schema.graphql index 4d138d0d2092cd..aab580b8888b6e 100644 --- a/doc/api/graphql/reference/gitlab_schema.graphql +++ b/doc/api/graphql/reference/gitlab_schema.graphql @@ -4481,15 +4481,10 @@ A custom emoji uploaded by user """ type CustomEmoji { """ - Whether the emoji is external link + Whether the emoji is an external link """ external: Boolean! - """ - The link to file of the emoji - """ - file: String! - """ The ID of the emoji """ @@ -4499,6 +4494,11 @@ type CustomEmoji { The name of the emoji """ name: String! + + """ + The link to file of the emoji + """ + url: String! } """ diff --git a/doc/api/graphql/reference/gitlab_schema.json b/doc/api/graphql/reference/gitlab_schema.json index ade60b04fd8fb8..eaad13eeef2f44 100644 --- a/doc/api/graphql/reference/gitlab_schema.json +++ b/doc/api/graphql/reference/gitlab_schema.json @@ -12237,7 +12237,7 @@ "fields": [ { "name": "external", - "description": "Whether the emoji is external link", + "description": "Whether the emoji is an external link", "args": [ ], @@ -12254,8 +12254,8 @@ "deprecationReason": null }, { - "name": "file", - "description": "The link to file of the emoji", + "name": "id", + "description": "The ID of the emoji", "args": [ ], @@ -12264,7 +12264,7 @@ "name": null, "ofType": { "kind": "SCALAR", - "name": "String", + "name": "CustomEmojiID", "ofType": null } }, @@ -12272,8 +12272,8 @@ "deprecationReason": null }, { - "name": "id", - "description": "The ID of the emoji", + "name": "name", + "description": "The name of the emoji", "args": [ ], @@ -12282,7 +12282,7 @@ "name": null, "ofType": { "kind": "SCALAR", - "name": "CustomEmojiID", + "name": "String", "ofType": null } }, @@ -12290,8 +12290,8 @@ "deprecationReason": null }, { - "name": "name", - "description": "The name of the emoji", + "name": "url", + "description": "The link to file of the emoji", "args": [ ], diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md index 42a4c9b61f5325..383024336580ce 100644 --- a/doc/api/graphql/reference/index.md +++ b/doc/api/graphql/reference/index.md @@ -737,10 +737,10 @@ A custom emoji uploaded by user. | Field | Type | Description | | ----- | ---- | ----------- | -| `external` | Boolean! | Whether the emoji is external link | -| `file` | String! | The link to file of the emoji | +| `external` | Boolean! | Whether the emoji is an external link | | `id` | CustomEmojiID! | The ID of the emoji | | `name` | String! | The name of the emoji | +| `url` | String! | The link to file of the emoji | ### DastOnDemandScanCreatePayload -- GitLab From 8256649686d22da871c46cd0a9141d279feed514 Mon Sep 17 00:00:00 2001 From: Rajendra Kadam Date: Sun, 15 Nov 2020 14:56:46 +0530 Subject: [PATCH 22/22] Fix specs --- spec/graphql/types/custom_emoji_type_spec.rb | 2 +- spec/requests/api/graphql/mutations/custom_emoji/create_spec.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/graphql/types/custom_emoji_type_spec.rb b/spec/graphql/types/custom_emoji_type_spec.rb index 57e518c8d39f3c..7f3c99e4b637ab 100644 --- a/spec/graphql/types/custom_emoji_type_spec.rb +++ b/spec/graphql/types/custom_emoji_type_spec.rb @@ -7,5 +7,5 @@ specify { expect(described_class).to require_graphql_authorizations(:read_custom_emoji) } - specify { expect(described_class).to have_graphql_fields(:id, :name, :file, :external) } + specify { expect(described_class).to have_graphql_fields(:id, :name, :url, :external) } end diff --git a/spec/requests/api/graphql/mutations/custom_emoji/create_spec.rb b/spec/requests/api/graphql/mutations/custom_emoji/create_spec.rb index bf36c288298127..c91437fa355767 100644 --- a/spec/requests/api/graphql/mutations/custom_emoji/create_spec.rb +++ b/spec/requests/api/graphql/mutations/custom_emoji/create_spec.rb @@ -37,7 +37,7 @@ gql_response = graphql_mutation_response(:create_custom_emoji) expect(gql_response['errors']).to eq([]) expect(gql_response['customEmoji']['name']).to eq(attributes[:name]) - expect(gql_response['customEmoji']['file']).to eq(attributes[:url]) + expect(gql_response['customEmoji']['url']).to eq(attributes[:url]) end end end -- GitLab