Commit affacae0 authored by Rajendra Kadam's avatar Rajendra Kadam Committed by Douglas Barbosa Alexandre

Fix errored force push by changing all files to previous state

Change and update code to match missed files
parent a7ccc61e
# 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 :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[:external] = true
custom_emoji = group.custom_emoji.create(args)
{
custom_emoji: custom_emoji.valid? ? custom_emoji : nil,
errors: errors_on_object(custom_emoji)
}
end
private
def find_object(group_path:)
resolve_group(full_path: group_path)
end
end
end
end
# frozen_string_literal: true
module Types
class CustomEmojiType < BaseObject
graphql_name 'CustomEmoji'
description 'A custom emoji uploaded by user'
authorize :read_custom_emoji
field :id, ::Types::GlobalIDType[::CustomEmoji],
null: false,
description: 'The ID of the emoji'
field :name, GraphQL::STRING_TYPE,
null: false,
description: 'The name of the emoji'
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 an external link'
end
end
...@@ -17,6 +17,10 @@ module Types ...@@ -17,6 +17,10 @@ module Types
group.avatar_url(only_path: false) group.avatar_url(only_path: false)
end end
field :custom_emoji, Types::CustomEmojiType.connection_type, null: true,
description: 'Custom emoji within this namespace',
feature_flag: :custom_emoji
field :share_with_group_lock, GraphQL::BOOLEAN_TYPE, null: true, field :share_with_group_lock, GraphQL::BOOLEAN_TYPE, null: true,
description: 'Indicates if sharing a project with another group within this group is prevented' description: 'Indicates if sharing a project with another group within this group is prevented'
......
...@@ -29,6 +29,7 @@ module Types ...@@ -29,6 +29,7 @@ module Types
mount_mutation Mutations::Boards::Lists::Destroy mount_mutation Mutations::Boards::Lists::Destroy
mount_mutation Mutations::Branches::Create, calls_gitaly: true mount_mutation Mutations::Branches::Create, calls_gitaly: true
mount_mutation Mutations::Commits::Create, calls_gitaly: true mount_mutation Mutations::Commits::Create, calls_gitaly: true
mount_mutation Mutations::CustomEmoji::Create, feature_flag: :custom_emoji
mount_mutation Mutations::Discussions::ToggleResolve mount_mutation Mutations::Discussions::ToggleResolve
mount_mutation Mutations::Issues::Create mount_mutation Mutations::Issues::Create
mount_mutation Mutations::Issues::SetAssignees mount_mutation Mutations::Issues::SetAssignees
......
# frozen_string_literal: true
module Types
module PermissionTypes
class CustomEmoji < BasePermissionType
graphql_name 'CustomEmojiPermissions'
abilities :create_custom_emoji, :read_custom_emoji
end
end
end
...@@ -3,14 +3,21 @@ ...@@ -3,14 +3,21 @@
class CustomEmoji < ApplicationRecord class CustomEmoji < ApplicationRecord
belongs_to :namespace, inverse_of: :custom_emoji belongs_to :namespace, inverse_of: :custom_emoji
belongs_to :group, -> { where(type: 'Group') }, foreign_key: 'namespace_id'
# 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
validate :valid_emoji_name validate :valid_emoji_name
validates :namespace, presence: true validates :group, presence: true
validates :name, validates :name,
uniqueness: { scope: [:namespace_id, :name] }, uniqueness: { scope: [:namespace_id, :name] },
presence: true, presence: true,
length: { maximum: 36 }, length: { maximum: 36 },
format: { with: /\A\w+\z/ } format: { with: /\A([a-z0-9]+[-_]?)+[a-z0-9]+\z/ }
private private
......
# frozen_string_literal: true
class CustomEmojiPolicy < BasePolicy
delegate { @subject.group }
end
...@@ -101,6 +101,7 @@ class GroupPolicy < BasePolicy ...@@ -101,6 +101,7 @@ class GroupPolicy < BasePolicy
enable :read_label enable :read_label
enable :read_board enable :read_board
enable :read_group_member enable :read_group_member
enable :read_custom_emoji
end end
rule { ~can?(:read_group) }.policy do rule { ~can?(:read_group) }.policy do
...@@ -114,6 +115,7 @@ class GroupPolicy < BasePolicy ...@@ -114,6 +115,7 @@ class GroupPolicy < BasePolicy
enable :create_metrics_dashboard_annotation enable :create_metrics_dashboard_annotation
enable :delete_metrics_dashboard_annotation enable :delete_metrics_dashboard_annotation
enable :update_metrics_dashboard_annotation enable :update_metrics_dashboard_annotation
enable :create_custom_emoji
end end
rule { reporter }.policy do rule { reporter }.policy do
......
---
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
...@@ -3834,6 +3834,51 @@ type CreateClusterAgentPayload { ...@@ -3834,6 +3834,51 @@ type CreateClusterAgentPayload {
errors: [String!]! errors: [String!]!
} }
"""
Autogenerated input type of CreateCustomEmoji
"""
input CreateCustomEmojiInput {
"""
A unique identifier for the client performing the mutation.
"""
clientMutationId: String
"""
Namespace full path the emoji is associated with
"""
groupPath: ID!
"""
Name of the emoji
"""
name: String!
"""
Location of the emoji file
"""
url: 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 Autogenerated input type of CreateDiffNote
""" """
...@@ -4431,6 +4476,71 @@ interface CurrentUserTodos { ...@@ -4431,6 +4476,71 @@ interface CurrentUserTodos {
): TodoConnection! ): TodoConnection!
} }
"""
A custom emoji uploaded by user
"""
type CustomEmoji {
"""
Whether the emoji is an external link
"""
external: Boolean!
"""
The ID of the emoji
"""
id: CustomEmojiID!
"""
The name of the emoji
"""
name: String!
"""
The link to file of the emoji
"""
url: 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
}
"""
Identifier of CustomEmoji
"""
scalar CustomEmojiID
""" """
Autogenerated input type of DastOnDemandScanCreate Autogenerated input type of DastOnDemandScanCreate
""" """
...@@ -8516,6 +8626,31 @@ type Group { ...@@ -8516,6 +8626,31 @@ type Group {
""" """
containsLockedProjects: Boolean! containsLockedProjects: Boolean!
"""
Custom emoji within this namespace. Available only when feature flag `custom_emoji` is enabled
"""
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 Description of the namespace
""" """
...@@ -13501,6 +13636,11 @@ type Mutation { ...@@ -13501,6 +13636,11 @@ type Mutation {
createBoard(input: CreateBoardInput!): CreateBoardPayload createBoard(input: CreateBoardInput!): CreateBoardPayload
createBranch(input: CreateBranchInput!): CreateBranchPayload createBranch(input: CreateBranchInput!): CreateBranchPayload
createClusterAgent(input: CreateClusterAgentInput!): CreateClusterAgentPayload createClusterAgent(input: CreateClusterAgentInput!): CreateClusterAgentPayload
"""
. Available only when feature flag `custom_emoji` is enabled
"""
createCustomEmoji(input: CreateCustomEmojiInput!): CreateCustomEmojiPayload
createDiffNote(input: CreateDiffNoteInput!): CreateDiffNotePayload createDiffNote(input: CreateDiffNoteInput!): CreateDiffNotePayload
createEpic(input: CreateEpicInput!): CreateEpicPayload createEpic(input: CreateEpicInput!): CreateEpicPayload
createImageDiffNote(input: CreateImageDiffNoteInput!): CreateImageDiffNotePayload createImageDiffNote(input: CreateImageDiffNoteInput!): CreateImageDiffNotePayload
......
...@@ -630,6 +630,16 @@ Autogenerated return type of CreateClusterAgent. ...@@ -630,6 +630,16 @@ Autogenerated return type of CreateClusterAgent.
| `clusterAgent` | ClusterAgent | Cluster agent created after mutation | | `clusterAgent` | ClusterAgent | Cluster agent created after mutation |
| `errors` | String! => Array | Errors encountered during execution of the 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 ### CreateDiffNotePayload
Autogenerated return type of CreateDiffNote. Autogenerated return type of CreateDiffNote.
...@@ -721,6 +731,17 @@ Autogenerated return type of CreateTestCase. ...@@ -721,6 +731,17 @@ Autogenerated return type of CreateTestCase.
| `errors` | String! => Array | Errors encountered during execution of the mutation. | | `errors` | String! => Array | Errors encountered during execution of the mutation. |
| `testCase` | Issue | The test case created | | `testCase` | Issue | The test case created |
### CustomEmoji
A custom emoji uploaded by user.
| Field | Type | Description |
| ----- | ---- | ----------- |
| `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 ### DastOnDemandScanCreatePayload
Autogenerated return type of DastOnDemandScanCreate. Autogenerated return type of DastOnDemandScanCreate.
...@@ -1392,6 +1413,7 @@ Autogenerated return type of EpicTreeReorder. ...@@ -1392,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 | | `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 | | `containerRepositories` | ContainerRepositoryConnection | Container repositories of the project |
| `containsLockedProjects` | Boolean! | Includes at least one project where the repository size exceeds the limit | | `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 | | `description` | String | Description of the namespace |
| `descriptionHtml` | String | The GitLab Flavored Markdown rendering of `description` | | `descriptionHtml` | String | The GitLab Flavored Markdown rendering of `description` |
| `emailsDisabled` | Boolean | Indicates if a group has email notifications disabled | | `emailsDisabled` | Boolean | Indicates if a group has email notifications disabled |
......
...@@ -4,6 +4,7 @@ FactoryBot.define do ...@@ -4,6 +4,7 @@ FactoryBot.define do
factory :custom_emoji, class: 'CustomEmoji' do factory :custom_emoji, class: 'CustomEmoji' do
sequence(:name) { |n| "custom_emoji#{n}" } sequence(:name) { |n| "custom_emoji#{n}" }
namespace namespace
file { fixture_file_upload(Rails.root.join('spec/fixtures/dk.png')) } group
file { 'https://gitlab.com/images/partyparrot.png' }
end end
end end
# 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_custom_emoji) }
specify { expect(described_class).to have_graphql_fields(:id, :name, :url, :external) }
end
...@@ -13,20 +13,28 @@ RSpec.describe CustomEmoji do ...@@ -13,20 +13,28 @@ RSpec.describe CustomEmoji do
describe 'exclusion of duplicated emoji' do describe 'exclusion of duplicated emoji' do
let(:emoji_name) { Gitlab::Emoji.emojis_names.sample } let(:emoji_name) { Gitlab::Emoji.emojis_names.sample }
let(:group) { create(:group, :private) }
it 'disallows emoji names of built-in emoji' do 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).not_to be_valid
expect(new_emoji.errors.messages).to eq(name: ["#{emoji_name} is already being used for another emoji"]) expect(new_emoji.errors.messages).to eq(name: ["#{emoji_name} is already being used for another emoji"])
end end
it 'disallows duplicate custom emoji names within namespace' do 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) 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).not_to be_valid
expect(new_emoji.errors.messages).to eq(name: ["has already been taken"]) expect(new_emoji.errors.messages).to eq(name: ["has already been taken"])
end 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
end end
# 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
stub_feature_flags(custom_emoji: true)
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
# 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',
url: 'https://example.com/image.png',
group_path: group.full_path
}
end
let(:mutation) do
graphql_mutation(:create_custom_emoji, attributes)
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)
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']['url']).to eq(attributes[:url])
end
end
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment