Commit d0b1993b authored by Dmitriy Zaporozhets's avatar Dmitriy Zaporozhets

Merge branch 'unauthorized-participants' into 'master'

Don't send notifications to mentioned users that don't have access to the project in question.

Fixes internal issue https://dev.gitlab.org/gitlab/gitlabhq/issues/2325.

See merge request !664
parents 390918b0 5210778d
...@@ -44,7 +44,7 @@ v 7.11.0 (unreleased) ...@@ -44,7 +44,7 @@ v 7.11.0 (unreleased)
- Fix bug where avatar filenames were not actually deleted from the database during removal (Stan Hu) - Fix bug where avatar filenames were not actually deleted from the database during removal (Stan Hu)
- Fix bug where Slack service channel was not saved in admin template settings. (Stan Hu) - Fix bug where Slack service channel was not saved in admin template settings. (Stan Hu)
- Protect OmniAuth request phase against CSRF. - Protect OmniAuth request phase against CSRF.
- - Don't send notifications to mentioned users that don't have access to the project in question.
- -
- Move snippets UI to fluid layout - Move snippets UI to fluid layout
- Improve UI for sidebar. Increase separation between navigation and content - Improve UI for sidebar. Increase separation between navigation and content
......
...@@ -35,8 +35,8 @@ module Participable ...@@ -35,8 +35,8 @@ module Participable
end end
end end
def participants(current_user = self.author) def participants(current_user = self.author, project = self.project)
self.class.participant_attrs.flat_map do |attr| participants = self.class.participant_attrs.flat_map do |attr|
meth = method(attr) meth = method(attr)
value = value =
...@@ -46,20 +46,28 @@ module Participable ...@@ -46,20 +46,28 @@ module Participable
meth.call meth.call
end end
participants_for(value, current_user) participants_for(value, current_user, project)
end.compact.uniq end.compact.uniq
if project
participants.select! do |user|
user.can?(:read_project, project)
end
end
participants
end end
private private
def participants_for(value, current_user = nil) def participants_for(value, current_user = nil, project = nil)
case value case value
when User when User
[value] [value]
when Enumerable, ActiveRecord::Relation when Enumerable, ActiveRecord::Relation
value.flat_map { |v| participants_for(v, current_user) } value.flat_map { |v| participants_for(v, current_user, project) }
when Participable when Participable
value.participants(current_user) value.participants(current_user, project)
end end
end end
end end
...@@ -91,10 +91,14 @@ class NotificationService ...@@ -91,10 +91,14 @@ class NotificationService
# * project team members with notification level higher then Participating # * project team members with notification level higher then Participating
# #
def merge_mr(merge_request, current_user) def merge_mr(merge_request, current_user)
recipients = reject_muted_users([merge_request.author, merge_request.assignee], merge_request.target_project) recipients = [merge_request.author, merge_request.assignee]
recipients = add_project_watchers(recipients, merge_request.target_project)
recipients = reject_muted_users(recipients, merge_request.target_project)
recipients = add_subscribed_users(recipients, merge_request) recipients = add_subscribed_users(recipients, merge_request)
recipients = reject_unsubscribed_users(recipients, merge_request) recipients = reject_unsubscribed_users(recipients, merge_request)
recipients = recipients.concat(project_watchers(merge_request.target_project)).uniq
recipients.delete(current_user) recipients.delete(current_user)
recipients.each do |recipient| recipients.each do |recipient|
...@@ -137,20 +141,17 @@ class NotificationService ...@@ -137,20 +141,17 @@ class NotificationService
recipients = recipients.concat(participants) recipients = recipients.concat(participants)
# Merge project watchers # Merge project watchers
recipients = recipients.concat(project_watchers(note.project)).compact.uniq recipients = add_project_watchers(recipients, note.project)
# Reject users with Mention notification level, except those mentioned in _this_ note. # Reject users with Mention notification level, except those mentioned in _this_ note.
recipients = reject_mention_users(recipients - note.mentioned_users, note.project) recipients = reject_mention_users(recipients - note.mentioned_users, note.project)
recipients = recipients + note.mentioned_users recipients = recipients + note.mentioned_users
# Reject mutes users
recipients = reject_muted_users(recipients, note.project) recipients = reject_muted_users(recipients, note.project)
recipients = add_subscribed_users(recipients, note.noteable) recipients = add_subscribed_users(recipients, note.noteable)
recipients = reject_unsubscribed_users(recipients, note.noteable) recipients = reject_unsubscribed_users(recipients, note.noteable)
# Reject author
recipients.delete(note.author) recipients.delete(note.author)
# build notify method like 'note_commit_email' # build notify method like 'note_commit_email'
...@@ -287,6 +288,10 @@ class NotificationService ...@@ -287,6 +288,10 @@ class NotificationService
users users
end end
def add_project_watchers(recipients, project)
recipients.concat(project_watchers(project)).compact.uniq
end
# Remove users with disabled notifications from array # Remove users with disabled notifications from array
# Also remove duplications and nil recipients # Also remove duplications and nil recipients
def reject_muted_users(users, project = nil) def reject_muted_users(users, project = nil)
...@@ -403,11 +408,13 @@ class NotificationService ...@@ -403,11 +408,13 @@ class NotificationService
[target.author, target.assignee] [target.author, target.assignee]
end end
recipients = reject_muted_users(recipients, project) recipients = add_project_watchers(recipients, project)
recipients = reject_mention_users(recipients, project) recipients = reject_mention_users(recipients, project)
recipients = reject_muted_users(recipients, project)
recipients = add_subscribed_users(recipients, target) recipients = add_subscribed_users(recipients, target)
recipients = recipients.concat(project_watchers(project)).uniq
recipients = reject_unsubscribed_users(recipients, target) recipients = reject_unsubscribed_users(recipients, target)
recipients recipients
end end
......
require 'spec_helper' require 'spec_helper'
describe Issues::CloseService do describe Issues::CloseService do
let(:project) { create(:empty_project) }
let(:user) { create(:user) } let(:user) { create(:user) }
let(:user2) { create(:user) } let(:user2) { create(:user) }
let(:issue) { create(:issue, assignee: user2) } let(:issue) { create(:issue, assignee: user2) }
let(:project) { issue.project }
before do before do
project.team << [user, :master] project.team << [user, :master]
......
require 'spec_helper' require 'spec_helper'
describe Issues::UpdateService do describe Issues::UpdateService do
let(:project) { create(:empty_project) }
let(:user) { create(:user) } let(:user) { create(:user) }
let(:user2) { create(:user) } let(:user2) { create(:user) }
let(:issue) { create(:issue) } let(:issue) { create(:issue) }
let(:label) { create(:label) } let(:label) { create(:label) }
let(:project) { issue.project }
before do before do
project.team << [user, :master] project.team << [user, :master]
......
...@@ -31,7 +31,8 @@ describe NotificationService do ...@@ -31,7 +31,8 @@ describe NotificationService do
describe 'Notes' do describe 'Notes' do
context 'issue note' do context 'issue note' do
let(:issue) { create(:issue, assignee: create(:user)) } let(:project) { create(:empty_project, :public) }
let(:issue) { create(:issue, project: project, assignee: create(:user)) }
let(:mentioned_issue) { create(:issue, assignee: issue.assignee) } let(:mentioned_issue) { create(:issue, assignee: issue.assignee) }
let(:note) { create(:note_on_issue, noteable: issue, project_id: issue.project_id, note: '@mention referenced') } let(:note) { create(:note_on_issue, noteable: issue, project_id: issue.project_id, note: '@mention referenced') }
...@@ -101,7 +102,8 @@ describe NotificationService do ...@@ -101,7 +102,8 @@ describe NotificationService do
end end
context 'issue note mention' do context 'issue note mention' do
let(:issue) { create(:issue, assignee: create(:user)) } let(:project) { create(:empty_project, :public) }
let(:issue) { create(:issue, project: project, assignee: create(:user)) }
let(:mentioned_issue) { create(:issue, assignee: issue.assignee) } let(:mentioned_issue) { create(:issue, assignee: issue.assignee) }
let(:note) { create(:note_on_issue, noteable: issue, project_id: issue.project_id, note: '@all mentioned') } let(:note) { create(:note_on_issue, noteable: issue, project_id: issue.project_id, note: '@all mentioned') }
...@@ -145,7 +147,8 @@ describe NotificationService do ...@@ -145,7 +147,8 @@ describe NotificationService do
end end
context 'commit note' do context 'commit note' do
let(:note) { create(:note_on_commit) } let(:project) { create(:project, :public) }
let(:note) { create(:note_on_commit, project: project) }
before do before do
build_team(note.project) build_team(note.project)
...@@ -192,7 +195,8 @@ describe NotificationService do ...@@ -192,7 +195,8 @@ describe NotificationService do
end end
describe 'Issues' do describe 'Issues' do
let(:issue) { create :issue, assignee: create(:user), description: 'cc @participant' } let(:project) { create(:empty_project, :public) }
let(:issue) { create :issue, project: project, assignee: create(:user), description: 'cc @participant' }
before do before do
build_team(issue.project) build_team(issue.project)
...@@ -295,7 +299,8 @@ describe NotificationService do ...@@ -295,7 +299,8 @@ describe NotificationService do
end end
describe 'Merge Requests' do describe 'Merge Requests' do
let(:merge_request) { create :merge_request, assignee: create(:user) } let(:project) { create(:project, :public) }
let(:merge_request) { create :merge_request, source_project: project, assignee: create(:user) }
before do before do
build_team(merge_request.target_project) build_team(merge_request.target_project)
......
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