Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2022-11-05 06:09:27 +00:00
parent e17e27b84b
commit 9a35de9bc5
12 changed files with 335 additions and 0 deletions

View File

@ -0,0 +1,25 @@
# frozen_string_literal: true
module Mutations
module IncidentManagement
module TimelineEventTag
class Base < BaseMutation
field :timeline_event_tag,
::Types::IncidentManagement::TimelineEventTagType,
null: true,
description: 'Timeline event tag.'
authorize :admin_incident_management_timeline_event_tag
private
def response(result)
{
timeline_event_tag: result.payload[:timeline_event_tag],
errors: result.errors
}
end
end
end
end
end

View File

@ -0,0 +1,29 @@
# frozen_string_literal: true
module Mutations
module IncidentManagement
module TimelineEventTag
class Create < Base
graphql_name 'TimelineEventTagCreate'
include FindsProject
argument :project_path, GraphQL::Types::ID,
required: true,
description: 'Project to create the timeline event tag in.'
argument :name, GraphQL::Types::String,
required: true,
description: 'Name of the tag.'
def resolve(project_path:, **args)
project = authorized_find!(project_path)
response ::IncidentManagement::TimelineEventTags::CreateService.new(
project, current_user, args
).execute
end
end
end
end
end

View File

@ -51,6 +51,7 @@ module Types
mount_mutation Mutations::IncidentManagement::TimelineEvent::PromoteFromNote
mount_mutation Mutations::IncidentManagement::TimelineEvent::Update
mount_mutation Mutations::IncidentManagement::TimelineEvent::Destroy
mount_mutation Mutations::IncidentManagement::TimelineEventTag::Create
mount_mutation Mutations::Issues::Create
mount_mutation Mutations::Issues::SetAssignees
mount_mutation Mutations::Issues::SetCrmContacts

View File

@ -537,6 +537,7 @@ class ProjectPolicy < BasePolicy
enable :read_web_hooks
enable :read_upload
enable :destroy_upload
enable :admin_incident_management_timeline_event_tag
end
rule { public_project & metrics_dashboard_allowed }.policy do

View File

@ -0,0 +1,27 @@
# frozen_string_literal: true
module IncidentManagement
module TimelineEventTags
class BaseService
def allowed?
user&.can?(:admin_incident_management_timeline_event_tag, project)
end
def success(timeline_event_tag)
ServiceResponse.success(payload: { timeline_event_tag: timeline_event_tag })
end
def error(message)
ServiceResponse.error(message: message)
end
def error_no_permissions
error(_('You have insufficient permissions to manage timeline event tags for this project'))
end
def error_in_save(timeline_event_tag)
error(timeline_event_tag.errors.full_messages.to_sentence)
end
end
end
end

View File

@ -0,0 +1,32 @@
# frozen_string_literal: true
module IncidentManagement
module TimelineEventTags
class CreateService < TimelineEventTags::BaseService
attr_reader :project, :user, :params
def initialize(project, user, params)
@project = project
@user = user
@params = params
end
def execute
return error_no_permissions unless allowed?
timeline_event_tag_params = {
project: project,
name: params[:name]
}
timeline_event_tag = IncidentManagement::TimelineEventTag.new(timeline_event_tag_params)
if timeline_event_tag.save
success(timeline_event_tag)
else
error_in_save(timeline_event_tag)
end
end
end
end
end

View File

@ -4944,6 +4944,26 @@ Input type: `TimelineEventPromoteFromNoteInput`
| <a id="mutationtimelineeventpromotefromnoteerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
| <a id="mutationtimelineeventpromotefromnotetimelineevent"></a>`timelineEvent` | [`TimelineEventType`](#timelineeventtype) | Timeline event. |
### `Mutation.timelineEventTagCreate`
Input type: `TimelineEventTagCreateInput`
#### Arguments
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="mutationtimelineeventtagcreateclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
| <a id="mutationtimelineeventtagcreatename"></a>`name` | [`String!`](#string) | Name of the tag. |
| <a id="mutationtimelineeventtagcreateprojectpath"></a>`projectPath` | [`ID!`](#id) | Project to create the timeline event tag in. |
#### Fields
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="mutationtimelineeventtagcreateclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
| <a id="mutationtimelineeventtagcreateerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
| <a id="mutationtimelineeventtagcreatetimelineeventtag"></a>`timelineEventTag` | [`TimelineEventTagType`](#timelineeventtagtype) | Timeline event tag. |
### `Mutation.timelineEventUpdate`
Input type: `TimelineEventUpdateInput`

View File

@ -46753,6 +46753,9 @@ msgstr ""
msgid "You have insufficient permissions to manage resource links for this incident"
msgstr ""
msgid "You have insufficient permissions to manage timeline event tags for this project"
msgstr ""
msgid "You have insufficient permissions to manage timeline events for this incident"
msgstr ""

View File

@ -0,0 +1,52 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Mutations::IncidentManagement::TimelineEventTag::Create do
let_it_be(:current_user) { create(:user) }
let_it_be_with_reload(:project) { create(:project) }
let(:args) { { name: 'Test tag 1' } }
before do
project.add_maintainer(current_user)
end
specify { expect(described_class).to require_graphql_authorizations(:admin_incident_management_timeline_event_tag) }
describe '#resolve' do
subject(:resolve) { mutation_for(project, current_user).resolve(project_path: project.full_path, **args) }
context 'when user has permission to create timeline event tag' do
it 'adds the tag to the project' do
expect { resolve }.to change(IncidentManagement::TimelineEventTag, :count).by(1)
expect(project.incident_management_timeline_event_tags.by_names(['Test tag 1']).pluck_names)
.to match_array(['Test tag 1'])
end
end
context 'when TimelineEventTags::CreateService responds with an error' do
let(:args) { {} }
it 'returns errors' do
expect(resolve).to eq(timeline_event_tag: nil, errors: ["Name can't be blank and Name is invalid"])
end
end
context 'when user has no permissions to create tags on a project' do
before do
project.add_developer(current_user)
end
it 'raises an error' do
expect { resolve }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
end
end
end
private
def mutation_for(project, user)
described_class.new(object: project, context: { current_user: user }, field: nil)
end
end

View File

@ -538,15 +538,32 @@ RSpec.describe ProjectPolicy do
it 'allows access to timeline event tags' do
expect(described_class.new(owner, project)).to be_allowed(:read_incident_management_timeline_event_tag)
expect(described_class.new(developer, project)).to be_allowed(:read_incident_management_timeline_event_tag)
expect(described_class.new(guest, project)).to be_allowed(:read_incident_management_timeline_event_tag)
expect(described_class.new(admin, project)).to be_allowed(:read_incident_management_timeline_event_tag)
end
end
context 'when user is a maintainer/owner' do
it 'allows to create timeline event tags' do
expect(described_class.new(maintainer, project)).to be_allowed(:admin_incident_management_timeline_event_tag)
expect(described_class.new(owner, project)).to be_allowed(:admin_incident_management_timeline_event_tag)
end
end
context 'when user is a developer/guest/reporter' do
it 'disallows creation' do
expect(described_class.new(developer, project)).to be_disallowed(:admin_incident_management_timeline_event_tag)
expect(described_class.new(guest, project)).to be_disallowed(:admin_incident_management_timeline_event_tag)
expect(described_class.new(reporter, project)).to be_disallowed(:admin_incident_management_timeline_event_tag)
end
end
context 'when user is not a member of the project' do
let(:project) { private_project }
it 'disallows access to the timeline event tags' do
expect(described_class.new(non_member, project)).to be_disallowed(:read_incident_management_timeline_event_tag)
expect(described_class.new(non_member, project)).to be_disallowed(:admin_incident_management_timeline_event_tag)
end
end
end

View File

@ -0,0 +1,57 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe 'Creating a timeline event tag' do
include GraphqlHelpers
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project) }
let_it_be(:name) { 'Test tag 1' }
let(:input) { { project_path: project.full_path, name: name } }
let(:mutation) do
graphql_mutation(:timeline_event_tag_create, input) do
<<~QL
clientMutationId
errors
timelineEventTag {
id
name
}
QL
end
end
let(:mutation_response) { graphql_mutation_response(:timeline_event_tag_create) }
context 'when user has permissions to create timeline event tag' do
before do
project.add_maintainer(user)
end
it 'creates timeline event tag', :aggregate_failures do
post_graphql_mutation(mutation, current_user: user)
timeline_event_tag_response = mutation_response['timelineEventTag']
expect(response).to have_gitlab_http_status(:success)
expect(timeline_event_tag_response).to include(
'name' => name
)
end
end
context 'when user does not have permissions to create timeline event tag' do
before do
project.add_developer(user)
end
it 'raises error' do
post_graphql_mutation(mutation, current_user: user)
expect(mutation_response).to be_nil
expect_graphql_errors_to_include(Gitlab::Graphql::Authorize::AuthorizeResource::RESOURCE_ACCESS_ERROR)
end
end
end

View File

@ -0,0 +1,71 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe IncidentManagement::TimelineEventTags::CreateService do
let_it_be(:user_with_permissions) { create(:user) }
let_it_be(:user_without_permissions) { create(:user) }
let_it_be_with_reload(:project) { create(:project) }
let(:current_user) { user_with_permissions }
let(:args) { { 'name': 'Test tag 1', 'project_path': project.full_path } }
let(:service) { described_class.new(project, current_user, args) }
before do
project.add_maintainer(user_with_permissions)
project.add_developer(user_without_permissions)
end
describe '#execute' do
shared_examples 'error response' do |message|
it 'has an informative message' do
expect(execute).to be_error
expect(execute.message).to eq(message)
end
end
shared_examples 'success response' do
it 'has timeline event tag' do
expect(execute).to be_success
result = execute.payload[:timeline_event_tag]
expect(result).to be_a(::IncidentManagement::TimelineEventTag)
expect(result.name).to eq(args[:name])
expect(result.project).to eq(project)
end
end
subject(:execute) { service.execute }
context 'when current user is nil' do
let(:current_user) { nil }
it_behaves_like 'error response',
'You have insufficient permissions to manage timeline event tags for this project'
end
context 'when user does not have permissions to create tags' do
let(:current_user) { user_without_permissions }
it_behaves_like 'error response',
'You have insufficient permissions to manage timeline event tags for this project'
end
context 'when error occurs during creation' do
let(:args) { {} }
it_behaves_like 'error response', "Name can't be blank and Name is invalid"
end
context 'when user has permissions' do
it_behaves_like 'success response'
it 'creates database record' do
expect { execute }.to change {
::IncidentManagement::TimelineEventTag.where(project_id: project.id).count
}.by(1)
end
end
end
end