Skip to content
Snippets Groups Projects
Commit c01f611d authored by Luke Duncalfe's avatar Luke Duncalfe 🔴 Committed by Natalia Tepluhina
Browse files

GraphQL mutations for managing Notes

parent 08a48ab8
No related branches found
No related tags found
No related merge requests found
Showing
with 35 additions and 74 deletions
......@@ -23,6 +23,7 @@ def create_note_params(noteable, args)
def position(noteable, args)
position = args[:position].to_h
position[:position_type] = 'text'
position.merge!(position[:paths].to_h)
Gitlab::Diff::Position.new(position)
end
......
......@@ -23,6 +23,7 @@ def create_note_params(noteable, args)
def position(noteable, args)
position = args[:position].to_h
position[:position_type] = 'image'
position.merge!(position[:paths].to_h)
Gitlab::Diff::Position.new(position)
end
......
......@@ -5,35 +5,6 @@ module Notes
module Create
class Note < Base
graphql_name 'CreateNote'
argument :discussion_id,
GraphQL::ID_TYPE,
required: false,
description: 'The global id of the discussion this note is in reply to'
private
def create_note_params(noteable, args)
discussion_id = nil
if args[:discussion_id]
discussion = GitlabSchema.object_from_id(args[:discussion_id])
authorize_discussion!(discussion)
discussion_id = discussion.id
end
super(noteable, args).merge({
in_reply_to_discussion_id: discussion_id
})
end
def authorize_discussion!(discussion)
unless Ability.allowed?(current_user, :read_note, discussion.noteable, scope: :user)
raise Gitlab::Graphql::Errors::ResourceNotAvailable,
"The discussion does not exist or you don't have permission to perform this action"
end
end
end
end
end
......
......@@ -9,7 +9,7 @@ class MutationType < BaseObject
mount_mutation Mutations::AwardEmojis::Add
mount_mutation Mutations::AwardEmojis::Remove
mount_mutation Mutations::AwardEmojis::Toggle
mount_mutation Mutations::MergeRequests::SetWip
mount_mutation Mutations::MergeRequests::SetWip, calls_gitaly: true
mount_mutation Mutations::Notes::Create::Note
mount_mutation Mutations::Notes::Create::DiffNote
mount_mutation Mutations::Notes::Create::ImageDiffNote
......
......@@ -2,6 +2,7 @@
module Types
module Notes
# rubocop: disable Graphql/AuthorizeTypes
class DiffImagePositionInputType < DiffPositionBaseInputType
graphql_name 'DiffImagePositionInput'
......@@ -14,5 +15,6 @@ class DiffImagePositionInputType < DiffPositionBaseInputType
argument :height, GraphQL::INT_TYPE, required: true,
description: copy_field_description(Types::Notes::DiffPositionType, :height)
end
# rubocop: enable Graphql/AuthorizeTypes
end
end
......@@ -2,20 +2,21 @@
module Types
module Notes
# rubocop: disable Graphql/AuthorizeTypes
class DiffPositionBaseInputType < BaseInputObject
argument :head_sha, GraphQL::STRING_TYPE, required: true,
description: copy_field_description(Types::Notes::DiffPositionType, :head_sha)
argument :base_sha, GraphQL::STRING_TYPE, required: true,
argument :base_sha, GraphQL::STRING_TYPE, required: false,
description: copy_field_description(Types::Notes::DiffPositionType, :base_sha)
argument :start_sha, GraphQL::STRING_TYPE, required: true,
description: copy_field_description(Types::Notes::DiffPositionType, :start_sha)
argument :file_path, GraphQL::STRING_TYPE, required: false,
description: copy_field_description(Types::Notes::DiffPositionType, :file_path)
argument :old_path, GraphQL::STRING_TYPE, required: false,
description: copy_field_description(Types::Notes::DiffPositionType, :old_path)
argument :new_path, GraphQL::STRING_TYPE, required: false,
description: copy_field_description(Types::Notes::DiffPositionType, :new_path)
argument :paths,
Types::DiffPathsInputType,
required: true,
description: 'The paths of the file that was changed. ' \
'Both of the properties of this input are optional, but at least one of them is required'
end
# rubocop: enable Graphql/AuthorizeTypes
end
end
......@@ -2,6 +2,7 @@
module Types
module Notes
# rubocop: disable Graphql/AuthorizeTypes
class DiffPositionInputType < DiffPositionBaseInputType
graphql_name 'DiffPositionInput'
......@@ -10,5 +11,6 @@ class DiffPositionInputType < DiffPositionBaseInputType
argument :new_line, GraphQL::INT_TYPE, required: true,
description: copy_field_description(Types::Notes::DiffPositionType, :new_line)
end
# rubocop: enable Graphql/AuthorizeTypes
end
end
......@@ -14,8 +14,10 @@
noteable_id: GitlabSchema.id_from_object(noteable).to_s,
body: 'Body text',
position: {
old_path: 'files/ruby/popen.rb',
new_path: 'files/ruby/popen.rb',
paths: {
old_path: 'files/ruby/popen.rb',
new_path: 'files/ruby/popen2.rb'
},
new_line: 14,
base_sha: diff_refs.base_sha,
head_sha: diff_refs.head_sha,
......@@ -44,7 +46,7 @@ def mutation_response
context do
let(:diff_refs) { build(:merge_request).diff_refs } # Allow fake diff refs so arguments are valid
it_behaves_like 'a Note mutation when the given noteable is not a Noteable'
it_behaves_like 'a Note mutation when the given resource id is not for a Noteable'
end
it 'returns the note with the correct position' do
......@@ -53,9 +55,9 @@ def mutation_response
expect(mutation_response['note']['body']).to eq('Body text')
mutation_position_response = mutation_response['note']['position']
expect(mutation_position_response['positionType']).to eq('text')
expect(mutation_position_response['filePath']).to eq('files/ruby/popen.rb')
expect(mutation_position_response['filePath']).to eq('files/ruby/popen2.rb')
expect(mutation_position_response['oldPath']).to eq('files/ruby/popen.rb')
expect(mutation_position_response['newPath']).to eq('files/ruby/popen.rb')
expect(mutation_position_response['newPath']).to eq('files/ruby/popen2.rb')
expect(mutation_position_response['newLine']).to eq(14)
end
end
......
......@@ -14,8 +14,10 @@
noteable_id: GitlabSchema.id_from_object(noteable).to_s,
body: 'Body text',
position: {
old_path: 'files/images/any_image.png',
new_path: 'files/images/any_image.png',
paths: {
old_path: 'files/images/any_image.png',
new_path: 'files/images/any_image2.png'
},
width: 100,
height: 200,
x: 1,
......@@ -47,7 +49,7 @@ def mutation_response
context do
let(:diff_refs) { build(:merge_request).diff_refs } # Allow fake diff refs so arguments are valid
it_behaves_like 'a Note mutation when the given noteable is not a Noteable'
it_behaves_like 'a Note mutation when the given resource id is not for a Noteable'
end
it 'returns the note with the correct position' do
......@@ -55,9 +57,9 @@ def mutation_response
expect(mutation_response['note']['body']).to eq('Body text')
mutation_position_response = mutation_response['note']['position']
expect(mutation_position_response['filePath']).to eq('files/images/any_image.png')
expect(mutation_position_response['filePath']).to eq('files/images/any_image2.png')
expect(mutation_position_response['oldPath']).to eq('files/images/any_image.png')
expect(mutation_position_response['newPath']).to eq('files/images/any_image.png')
expect(mutation_position_response['newPath']).to eq('files/images/any_image2.png')
expect(mutation_position_response['positionType']).to eq('image')
expect(mutation_position_response['width']).to eq(100)
expect(mutation_position_response['height']).to eq(200)
......
......@@ -7,12 +7,10 @@
set(:current_user) { create(:user) }
let(:noteable) { create(:merge_request, source_project: project, target_project: project) }
let(:project) { create(:project) }
let(:discussion) { nil }
let(:project) { create(:project, :repository) }
let(:mutation) do
variables = {
noteable_id: GitlabSchema.id_from_object(noteable).to_s,
discussion_id: (GitlabSchema.id_from_object(discussion).to_s if discussion),
body: 'Body text'
}
......@@ -34,31 +32,12 @@ def mutation_response
it_behaves_like 'a Note mutation when there are active record validation errors'
it_behaves_like 'a Note mutation when the given noteable is not a Noteable'
it_behaves_like 'a Note mutation when the given resource id is not for a Noteable'
it 'returns the note' do
post_graphql_mutation(mutation, current_user: current_user)
expect(mutation_response['note']['body']).to eq('Body text')
end
describe 'creating Notes in reply to a discussion' do
context 'when the user does not have permission to create notes on the discussion' do
let(:discussion) { create(:discussion_note).to_discussion }
it_behaves_like 'a mutation that returns top-level errors',
errors: ["The discussion does not exist or you don't have permission to perform this action"]
end
context 'when the user has permission to create notes on the discussion' do
let(:discussion) { create(:discussion_note, project: project).to_discussion }
it 'creates a Note in a discussion' do
post_graphql_mutation(mutation, current_user: current_user)
expect(mutation_response['note']['discussion']['id']).to eq(discussion.to_global_id.to_s)
end
end
end
end
end
......@@ -34,7 +34,7 @@ def mutation_response
context 'when the user has permission' do
let(:current_user) { note.author }
it_behaves_like 'a Note mutation when the given note is not a Note'
it_behaves_like 'a Note mutation when the given resource id is not for a Note'
it 'destroys the Note' do
expect do
......
......@@ -37,7 +37,7 @@ def mutation_response
context 'when the user has permission' do
let(:current_user) { note.author }
it_behaves_like 'a Note mutation when the given note is not a Note'
it_behaves_like 'a Note mutation when the given resource id is not for a Note'
it 'updates the Note' do
post_graphql_mutation(mutation, current_user: current_user)
......
......@@ -46,7 +46,7 @@
end
end
RSpec.shared_examples 'a Note mutation when the given noteable is not a Noteable' do
RSpec.shared_examples 'a Note mutation when the given resource id is not for a Noteable' do
let(:noteable) { create(:label, project: project) }
it_behaves_like 'a Note mutation that does not create a Note'
......@@ -54,7 +54,7 @@
it_behaves_like 'a mutation that returns top-level errors', errors: ['Cannot add notes to this resource']
end
RSpec.shared_examples 'a Note mutation when the given note is not a Note' do
RSpec.shared_examples 'a Note mutation when the given resource id is not for a Note' do
let(:note) { create(:issue) }
it_behaves_like 'a mutation that returns top-level errors', errors: ['Resource is not a note']
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment