Commit 1d00e3b1 authored by Jarka Košanová's avatar Jarka Košanová

Add updating notes confidentiality to Service

- update specs so the notes are completely reloaded
  because of discussion memoization
parent 6f1b899d
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
# A note of this type is never resolvable. # A note of this type is never resolvable.
class Note < ApplicationRecord class Note < ApplicationRecord
extend ActiveModel::Naming extend ActiveModel::Naming
include Gitlab::Utils::StrongMemoize
include Participable include Participable
include Mentionable include Mentionable
include Awardable include Awardable
...@@ -446,9 +447,11 @@ class Note < ApplicationRecord ...@@ -446,9 +447,11 @@ class Note < ApplicationRecord
# Consider using `#to_discussion` if we do not need to render the discussion # Consider using `#to_discussion` if we do not need to render the discussion
# and all its notes and if we don't care about the discussion's resolvability status. # and all its notes and if we don't care about the discussion's resolvability status.
def discussion def discussion
strong_memoize(:discussion) do
full_discussion = self.noteable.notes.find_discussion(self.discussion_id) if part_of_discussion? full_discussion = self.noteable.notes.find_discussion(self.discussion_id) if part_of_discussion?
full_discussion || to_discussion full_discussion || to_discussion
end end
end
def start_of_discussion? def start_of_discussion?
discussion.first_note == self discussion.first_note == self
......
...@@ -10,6 +10,7 @@ module Notes ...@@ -10,6 +10,7 @@ module Notes
note.assign_attributes(params.merge(updated_by: current_user)) note.assign_attributes(params.merge(updated_by: current_user))
note.with_transaction_returning_status do note.with_transaction_returning_status do
update_confidentiality(note)
note.save note.save
end end
...@@ -79,6 +80,15 @@ module Notes ...@@ -79,6 +80,15 @@ module Notes
TodoService.new.update_note(note, current_user, old_mentioned_users) TodoService.new.update_note(note, current_user, old_mentioned_users)
end end
# This method updates confidentiality of all discussion notes at once
def update_confidentiality(note)
return unless params.key?(:confidential)
return unless note.is_a?(DiscussionNote) # we don't need to do bulk update for single notes
return unless note.start_of_discussion? # don't update all notes if a response is being updated
Note.id_in(note.discussion.notes.map(&:id)).update_all(confidential: params[:confidential])
end
end end
end end
......
...@@ -182,7 +182,8 @@ RSpec.describe Projects::DiscussionsController do ...@@ -182,7 +182,8 @@ RSpec.describe Projects::DiscussionsController do
it "unresolves the discussion" do it "unresolves the discussion" do
delete :unresolve, params: request_params delete :unresolve, params: request_params
expect(note.reload.discussion.resolved?).to be false # discussion is memoized and reload doesn't clear the memoization
expect(Note.find(note.id).discussion.resolved?).to be false
end end
it "returns status 200" do it "returns status 200" do
......
...@@ -331,8 +331,10 @@ RSpec.describe Projects::MergeRequests::DraftsController do ...@@ -331,8 +331,10 @@ RSpec.describe Projects::MergeRequests::DraftsController do
notes = merge_request.notes.reload notes = merge_request.notes.reload
expect(notes.pluck(:note)).to include(*drafts.map(&:note)) expect(notes.pluck(:note)).to include(*drafts.map(&:note))
expect(note.discussion.notes.last.note).to eq(draft_reply.note)
expect(diff_note.discussion.notes.last.note).to eq(diff_draft_reply.note) # discussion is memoized and reload doesn't clear the memoization
expect(Note.find(note.id).discussion.notes.last.note).to eq(draft_reply.note)
expect(Note.find(diff_note.id).discussion.notes.last.note).to eq(diff_draft_reply.note)
end end
it 'can publish just a single draft note' do it 'can publish just a single draft note' do
...@@ -376,7 +378,8 @@ RSpec.describe Projects::MergeRequests::DraftsController do ...@@ -376,7 +378,8 @@ RSpec.describe Projects::MergeRequests::DraftsController do
post :publish, params: params post :publish, params: params
discussion = note.discussion # discussion is memoized and reload doesn't clear the memoization
discussion = Note.find(note.id).discussion
expect(discussion.notes.last.note).to eq(draft_reply.note) expect(discussion.notes.last.note).to eq(draft_reply.note)
expect(discussion.resolved?).to eq(false) expect(discussion.resolved?).to eq(false)
......
...@@ -1180,9 +1180,7 @@ RSpec.describe Notify do ...@@ -1180,9 +1180,7 @@ RSpec.describe Notify do
context 'when note is not on text' do context 'when note is not on text' do
before do before do
allow_next_instance_of(DiffDiscussion) do |instance| allow(note.discussion).to receive(:on_text?).and_return(false)
allow(instance).to receive(:on_text?).and_return(false)
end
end end
it 'does not include diffs with character-level highlighting' do it 'does not include diffs with character-level highlighting' do
......
...@@ -237,7 +237,8 @@ RSpec.describe DraftNotes::PublishService do ...@@ -237,7 +237,8 @@ RSpec.describe DraftNotes::PublishService do
it 'resolves the thread' do it 'resolves the thread' do
publish(draft: draft_note) publish(draft: draft_note)
expect(note.discussion.resolved?).to be true # discussion is memoized and reload doesn't clear the memoization
expect(Note.find(note.id).discussion.resolved?).to be true
end end
it 'sends notifications if all threads are resolved' do it 'sends notifications if all threads are resolved' do
......
...@@ -59,6 +59,45 @@ RSpec.describe Notes::UpdateService do ...@@ -59,6 +59,45 @@ RSpec.describe Notes::UpdateService do
end end
end end
context 'setting confidentiality' do
let(:opts) { { confidential: true } }
context 'simple note' do
it 'updates the confidentiality' do
expect { update_note(opts) }.to change { note.reload.confidential }.from(nil).to(true)
end
end
context 'discussion notes' do
let(:note) { create(:discussion_note, project: project, noteable: issue, author: user, note: "Old note #{user2.to_reference}") }
let!(:response_note_1) { create(:discussion_note, project: project, noteable: issue, in_reply_to: note) }
let!(:response_note_2) { create(:discussion_note, project: project, noteable: issue, in_reply_to: note, confidential: false) }
let!(:other_note) { create(:note, project: project, noteable: issue) }
context 'when updating the root note' do
it 'updates the confidentiality of the root note and all the responses' do
update_note(opts)
expect(note.reload.confidential).to be_truthy
expect(response_note_1.reload.confidential).to be_truthy
expect(response_note_2.reload.confidential).to be_truthy
expect(other_note.reload.confidential).to be_falsey
end
end
context 'when updating one of the response notes' do
it 'updates only the confidentiality of the note that is being updated' do
Notes::UpdateService.new(project, user, opts).execute(response_note_1)
expect(note.reload.confidential).to be_falsey
expect(response_note_1.reload.confidential).to be_truthy
expect(response_note_2.reload.confidential).to be_falsey
expect(other_note.reload.confidential).to be_falsey
end
end
end
end
context 'todos' do context 'todos' do
shared_examples 'does not update todos' do shared_examples 'does not update todos' do
it 'keep todos' do it 'keep todos' do
......
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