Commit 0c350b79 authored by Jarka Kadlecova's avatar Jarka Kadlecova

address comments

parent bf708e55
...@@ -29,7 +29,7 @@ class Ability ...@@ -29,7 +29,7 @@ class Ability
when Snippet::INTERNAL, Snippet::PUBLIC when Snippet::INTERNAL, Snippet::PUBLIC
users users
when Snippet::PRIVATE when Snippet::PRIVATE
users.select { |user| snippet.author == user } users.include?(snippet.author) ? [snippet.author] : []
end end
end end
......
...@@ -51,6 +51,10 @@ module CacheMarkdownField ...@@ -51,6 +51,10 @@ module CacheMarkdownField
CACHING_CLASSES.map(&:constantize) CACHING_CLASSES.map(&:constantize)
end end
def skip_project_check?
false
end
extend ActiveSupport::Concern extend ActiveSupport::Concern
included do included do
...@@ -112,9 +116,7 @@ module CacheMarkdownField ...@@ -112,9 +116,7 @@ module CacheMarkdownField
invalidation_method = "#{html_field}_invalidated?".to_sym invalidation_method = "#{html_field}_invalidated?".to_sym
define_method(cache_method) do define_method(cache_method) do
options = { options = { skip_project_check: skip_project_check? }
skip_project_check: is_a?(Note) && for_personal_snippet?
}
html = Banzai::Renderer.cacheless_render_field(self, markdown_field, options) html = Banzai::Renderer.cacheless_render_field(self, markdown_field, options)
__send__("#{html_field}=", html) __send__("#{html_field}=", html)
true true
......
...@@ -52,7 +52,7 @@ module Mentionable ...@@ -52,7 +52,7 @@ module Mentionable
options = options.merge( options = options.merge(
cache_key: [self, attr], cache_key: [self, attr],
author: author, author: author,
skip_project_check: is_a?(Note) && for_personal_snippet? skip_project_check: skip_project_check?
) )
extractor.analyze(text, options) extractor.analyze(text, options)
...@@ -125,4 +125,8 @@ module Mentionable ...@@ -125,4 +125,8 @@ module Mentionable
def cross_reference_exists?(target) def cross_reference_exists?(target)
SystemNoteService.cross_reference_exists?(target, local_reference) SystemNoteService.cross_reference_exists?(target, local_reference)
end end
def skip_project_check?
false
end
end end
...@@ -96,7 +96,8 @@ module Participable ...@@ -96,7 +96,8 @@ module Participable
participants.merge(ext.users) participants.merge(ext.users)
if self.is_a?(PersonalSnippet) case self
when PersonalSnippet
Ability.users_that_can_read_personal_snippet(participants.to_a, self) Ability.users_that_can_read_personal_snippet(participants.to_a, self)
else else
Ability.users_that_can_read_project(participants.to_a, project) Ability.users_that_can_read_project(participants.to_a, project)
......
...@@ -167,7 +167,11 @@ class Note < ActiveRecord::Base ...@@ -167,7 +167,11 @@ class Note < ActiveRecord::Base
end end
def for_personal_snippet? def for_personal_snippet?
noteable_type == "Snippet" && noteable.type == 'PersonalSnippet' noteable.is_a?(PersonalSnippet)
end
def skip_project_check?
for_personal_snippet?
end end
# override to return commits, which are not active record # override to return commits, which are not active record
...@@ -225,6 +229,10 @@ class Note < ActiveRecord::Base ...@@ -225,6 +229,10 @@ class Note < ActiveRecord::Base
note.match(Banzai::Filter::EmojiFilter.emoji_pattern)[1] note.match(Banzai::Filter::EmojiFilter.emoji_pattern)[1]
end end
def to_ability_name
for_personal_snippet? ? 'personal_snippet' : noteable_type.underscore
end
private private
def keep_around_commit def keep_around_commit
......
...@@ -10,10 +10,11 @@ module Notes ...@@ -10,10 +10,11 @@ module Notes
# Skip system notes, like status changes and cross-references and awards # Skip system notes, like status changes and cross-references and awards
unless @note.system? unless @note.system?
EventCreateService.new.leave_note(@note, @note.author) EventCreateService.new.leave_note(@note, @note.author)
unless @note.for_personal_snippet?
@note.create_cross_references! return if @note.for_personal_snippet?
execute_note_hooks
end @note.create_cross_references!
execute_note_hooks
end end
end end
......
...@@ -12,7 +12,7 @@ module Notes ...@@ -12,7 +12,7 @@ module Notes
def self.supported?(note, current_user) def self.supported?(note, current_user)
noteable_update_service(note) && noteable_update_service(note) &&
current_user && current_user &&
current_user.can?(:"update_#{note.noteable_type.underscore}", note.noteable) current_user.can?(:"update_#{note.to_ability_name}", note.noteable)
end end
def supported?(note) def supported?(note)
......
...@@ -179,14 +179,14 @@ class NotificationService ...@@ -179,14 +179,14 @@ class NotificationService
mentioned_users = note.mentioned_users mentioned_users = note.mentioned_users
if note.for_personal_snippet? ability, subject = if note.for_personal_snippet?
mentioned_users.select! do |user| [:read_personal_snippet, note.noteable]
user.can?(:read_personal_snippet, note.noteable) else
end [:read_project, note.project]
else end
mentioned_users.select! do |user|
user.can?(:read_project, note.project) mentioned_users.select! do |user|
end user.can?(ability, subject)
end end
# Add all users participating in the thread (author, assignee, comment authors) # Add all users participating in the thread (author, assignee, comment authors)
...@@ -220,12 +220,7 @@ class NotificationService ...@@ -220,12 +220,7 @@ class NotificationService
recipients.delete(note.author) recipients.delete(note.author)
recipients = recipients.uniq recipients = recipients.uniq
# build notify method like 'note_commit_email' notify_method = "note_#{note.to_ability_name}_email".to_sym
if note.for_personal_snippet?
notify_method = "note_personal_snippet_email".to_sym
else
notify_method = "note_#{note.noteable_type.underscore}_email".to_sym
end
recipients.each do |recipient| recipients.each do |recipient|
mailer.send(notify_method, recipient.id, note.id).deliver_later mailer.send(notify_method, recipient.id, note.id).deliver_later
......
New comment for Snippet <%= @snippet.id %>
<%= url_for(snippet_url(@snippet, anchor: "note_#{@note.id}")) %>
Author: <%= @note.author_name %>
<%= @note.note %>
...@@ -28,6 +28,7 @@ module Banzai ...@@ -28,6 +28,7 @@ module Banzai
ref_pattern = User.reference_pattern ref_pattern = User.reference_pattern
ref_pattern_start = /\A#{ref_pattern}\z/ ref_pattern_start = /\A#{ref_pattern}\z/
nodes.each do |node| nodes.each do |node|
if text_node?(node) if text_node?(node)
replace_text_when_pattern_matches(node, ref_pattern) do |content| replace_text_when_pattern_matches(node, ref_pattern) do |content|
......
...@@ -157,17 +157,20 @@ describe Banzai::Filter::UserReferenceFilter, lib: true do ...@@ -157,17 +157,20 @@ describe Banzai::Filter::UserReferenceFilter, lib: true do
it 'does not link a User' do it 'does not link a User' do
doc = reference_filter("Hey #{reference}") doc = reference_filter("Hey #{reference}")
expect(doc).not_to include('a') expect(doc).not_to include('a')
end end
context 'when skip_project_check set to true' do context 'when skip_project_check set to true' do
it 'links to a User' do it 'links to a User' do
doc = reference_filter("Hey #{reference}", skip_project_check: true) doc = reference_filter("Hey #{reference}", skip_project_check: true)
expect(doc.css('a').first.attr('href')).to eq urls.user_url(user) expect(doc.css('a').first.attr('href')).to eq urls.user_url(user)
end end
it 'does not link users using @all reference' do it 'does not link users using @all reference' do
doc = reference_filter("Hey #{User.reference_prefix}all", skip_project_check: true) doc = reference_filter("Hey #{User.reference_prefix}all", skip_project_check: true)
expect(doc).not_to include('a') expect(doc).not_to include('a')
end end
end end
......
...@@ -172,32 +172,29 @@ describe Ability, lib: true do ...@@ -172,32 +172,29 @@ describe Ability, lib: true do
end end
describe '.users_that_can_read_personal_snippet' do describe '.users_that_can_read_personal_snippet' do
subject { Ability.users_that_can_read_personal_snippet(users, snippet) } def users_for_snippet(snippet)
described_class.users_that_can_read_personal_snippet(users, snippet)
end
let(:users) { create_list(:user, 3) } let(:users) { create_list(:user, 3) }
let(:author) { users[0] } let(:author) { users[0] }
context 'private snippet' do it 'private snippet is readable only by its author' do
let(:snippet) { create(:personal_snippet, :private, author: author) } snippet = create(:personal_snippet, :private, author: author)
it 'is readable only by its author' do expect(users_for_snippet(snippet)).to match_array([author])
expect(subject).to match_array([author])
end
end end
context 'internal snippet' do it 'internal snippet is readable by all registered users' do
let(:snippet) { create(:personal_snippet, :public, author: author) } snippet = create(:personal_snippet, :public, author: author)
it 'is readable by all registered users' do expect(users_for_snippet(snippet)).to match_array(users)
expect(subject).to match_array(users)
end
end end
context 'public snippet' do it 'public snippet is readable by all users' do
let(:snippet) { create(:personal_snippet, :public, author: author) } snippet = create(:personal_snippet, :public, author: author)
it 'is readable by all users' do expect(users_for_snippet(snippet)).to match_array(users)
expect(subject).to match_array(users)
end
end end
end end
......
...@@ -35,17 +35,14 @@ describe Issue, "Mentionable" do ...@@ -35,17 +35,14 @@ describe Issue, "Mentionable" do
subject { issue.mentioned_users } subject { issue.mentioned_users }
it { is_expected.to include(user) } it { expect(subject).to contain_exactly(user) }
it { is_expected.not_to include(user2) }
context 'when a note on personal snippet' do context 'when a note on personal snippet' do
let!(:note) { create(:note_on_personal_snippet, note: "#{user.to_reference} mentioned #{user3.to_reference}") } let!(:note) { create(:note_on_personal_snippet, note: "#{user.to_reference} mentioned #{user3.to_reference}") }
subject { note.mentioned_users } subject { note.mentioned_users }
it { is_expected.to include(user) } it { expect(subject).to contain_exactly(user, user3) }
it { is_expected.to include(user3) }
it { is_expected.not_to include(user2) }
end end
end end
......
...@@ -59,7 +59,7 @@ describe Note, models: true do ...@@ -59,7 +59,7 @@ describe Note, models: true do
end end
context 'when noteable is a personal snippet' do context 'when noteable is a personal snippet' do
subject { create(:note_on_personal_snippet) } subject { build(:note_on_personal_snippet) }
it 'is valid without project' do it 'is valid without project' do
is_expected.to be_valid is_expected.to be_valid
...@@ -321,4 +321,70 @@ describe Note, models: true do ...@@ -321,4 +321,70 @@ describe Note, models: true do
end end
end end
end end
describe '#for_personal_snippet?' do
it 'returns false for a project snippet note' do
expect(build(:note_on_project_snippet).for_personal_snippet?).to be_falsy
end
it 'returns true for a personal snippet note' do
expect(build(:note_on_personal_snippet).for_personal_snippet?).to be_truthy
end
end
describe '#to_ability_name' do
it 'returns snippet for a project snippet note' do
expect(build(:note_on_project_snippet).to_ability_name).to eq('snippet')
end
it 'returns personal_snippet for a personal snippet note' do
expect(build(:note_on_personal_snippet).to_ability_name).to eq('personal_snippet')
end
it 'returns merge_request for an MR note' do
expect(build(:note_on_merge_request).to_ability_name).to eq('merge_request')
end
it 'returns issue for an issue note' do
expect(build(:note_on_issue).to_ability_name).to eq('issue')
end
it 'returns issue for a commit note' do
expect(build(:note_on_commit).to_ability_name).to eq('commit')
end
end
describe '#cache_markdown_field' do
let(:html) { '<p>some html</p>'}
context 'note for a project snippet' do
let(:note) { build(:note_on_project_snippet) }
before do
expect(Banzai::Renderer).to receive(:cacheless_render_field).
with(note, :note, { skip_project_check: false }).and_return(html)
note.save
end
it 'creates a note' do
expect(note.note_html).to eq(html)
end
end
context 'note for a personal snippet' do
let(:note) { build(:note_on_personal_snippet) }
before do
expect(Banzai::Renderer).to receive(:cacheless_render_field).
with(note, :note, { skip_project_check: true }).and_return(html)
note.save
end
it 'creates a note' do
expect(note.note_html).to eq(html)
end
end
end
end end
...@@ -15,25 +15,25 @@ describe Notes::CreateService, services: true do ...@@ -15,25 +15,25 @@ describe Notes::CreateService, services: true do
context "valid params" do context "valid params" do
it 'returns a valid note' do it 'returns a valid note' do
note = Notes::CreateService.new(project, user, opts).execute note = described_class.new(project, user, opts).execute
expect(note).to be_valid expect(note).to be_valid
end end
it 'returns a persisted note' do it 'returns a persisted note' do
note = Notes::CreateService.new(project, user, opts).execute note = described_class.new(project, user, opts).execute
expect(note).to be_persisted expect(note).to be_persisted
end end
it 'note has valid content' do it 'note has valid content' do
note = Notes::CreateService.new(project, user, opts).execute note = described_class.new(project, user, opts).execute
expect(note.note).to eq(opts[:note]) expect(note.note).to eq(opts[:note])
end end
it 'note belongs to the correct project' do it 'note belongs to the correct project' do
note = Notes::CreateService.new(project, user, opts).execute note = described_class.new(project, user, opts).execute
expect(note.project).to eq(project) expect(note.project).to eq(project)
end end
...@@ -44,7 +44,7 @@ describe Notes::CreateService, services: true do ...@@ -44,7 +44,7 @@ describe Notes::CreateService, services: true do
expect_any_instance_of(TodoService).to receive(:new_note).with(note, user) expect_any_instance_of(TodoService).to receive(:new_note).with(note, user)
Notes::CreateService.new(project, user, opts).execute described_class.new(project, user, opts).execute
end end
it 'enqueues NewNoteWorker' do it 'enqueues NewNoteWorker' do
...@@ -53,7 +53,7 @@ describe Notes::CreateService, services: true do ...@@ -53,7 +53,7 @@ describe Notes::CreateService, services: true do
expect(NewNoteWorker).to receive(:perform_async).with(note.id) expect(NewNoteWorker).to receive(:perform_async).with(note.id)
Notes::CreateService.new(project, user, opts).execute described_class.new(project, user, opts).execute
end end
end end
...@@ -115,7 +115,7 @@ describe Notes::CreateService, services: true do ...@@ -115,7 +115,7 @@ describe Notes::CreateService, services: true do
noteable_type: 'Issue', noteable_type: 'Issue',
noteable_id: issue.id noteable_id: issue.id
} }
note = Notes::CreateService.new(project, user, opts).execute note = described_class.new(project, user, opts).execute
expect(note).to be_valid expect(note).to be_valid
expect(note.name).to eq('smile') expect(note.name).to eq('smile')
...@@ -127,7 +127,7 @@ describe Notes::CreateService, services: true do ...@@ -127,7 +127,7 @@ describe Notes::CreateService, services: true do
noteable_type: 'Issue', noteable_type: 'Issue',
noteable_id: issue.id noteable_id: issue.id
} }
note = Notes::CreateService.new(project, user, opts).execute note = described_class.new(project, user, opts).execute
expect(note).to be_valid expect(note).to be_valid
expect(note.note).to eq(opts[:note]) expect(note.note).to eq(opts[:note])
...@@ -142,7 +142,7 @@ describe Notes::CreateService, services: true do ...@@ -142,7 +142,7 @@ describe Notes::CreateService, services: true do
expect_any_instance_of(TodoService).to receive(:new_award_emoji).with(issue, user) expect_any_instance_of(TodoService).to receive(:new_award_emoji).with(issue, user)
Notes::CreateService.new(project, user, opts).execute described_class.new(project, user, opts).execute
end end
end 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