Commit 7b64b205 authored by Valery Sizov's avatar Valery Sizov

[Multiple issue assignees] Fixes for notification, todos, system notes[ci skip]

parent 3f98525f
...@@ -11,10 +11,12 @@ module Emails ...@@ -11,10 +11,12 @@ module Emails
mail_answer_thread(@issue, issue_thread_options(updated_by_user_id, recipient_id)) mail_answer_thread(@issue, issue_thread_options(updated_by_user_id, recipient_id))
end end
def reassigned_issue_email(recipient_id, issue_id, previous_assignee_id, updated_by_user_id) def reassigned_issue_email(recipient_id, issue_id, previous_assignee_ids, updated_by_user_id)
setup_issue_mail(issue_id, recipient_id) setup_issue_mail(issue_id, recipient_id)
@previous_assignee = User.find_by(id: previous_assignee_id) if previous_assignee_id @previous_assignees = []
@previous_assignees = User.where(id: previous_assignee_ids) if previous_assignee_ids.any?
mail_answer_thread(@issue, issue_thread_options(updated_by_user_id, recipient_id)) mail_answer_thread(@issue, issue_thread_options(updated_by_user_id, recipient_id))
end end
......
...@@ -140,11 +140,17 @@ class Issue < ActiveRecord::Base ...@@ -140,11 +140,17 @@ class Issue < ActiveRecord::Base
end end
def assignee_or_author?(user) def assignee_or_author?(user)
author_id == user.id || assignees.exists?(user) author_id == user.id || assignees.exists?(user.id)
end end
def assignee_list def assignee_list
assignees.pluck(:name).join(', ') assignees.map(&:to_reference).to_sentence
end
# TODO: This method will help us to find some silent failures.
# We should remove it before merging to master
def assignee_id
raise "assignee_id is deprecated"
end end
# `from` argument can be a Namespace or Project. # `from` argument can be a Namespace or Project.
......
...@@ -193,6 +193,11 @@ class MergeRequest < ActiveRecord::Base ...@@ -193,6 +193,11 @@ class MergeRequest < ActiveRecord::Base
} }
end end
# This method is needed for compatibility with issues
def assignees
[assignee]
end
def assignee_or_author?(user) def assignee_or_author?(user)
author_id == user.id || assignee_id == user.id author_id == user.id || assignee_id == user.id
end end
......
class IssuableBaseService < BaseService class IssuableBaseService < BaseService
private private
def create_assignee_note(issuable)
SystemNoteService.change_assignee(
issuable, issuable.project, current_user, issuable.assignee)
end
def create_milestone_note(issuable) def create_milestone_note(issuable)
SystemNoteService.change_milestone( SystemNoteService.change_milestone(
issuable, issuable.project, current_user, issuable.milestone) issuable, issuable.project, current_user, issuable.milestone)
...@@ -77,7 +72,7 @@ class IssuableBaseService < BaseService ...@@ -77,7 +72,7 @@ class IssuableBaseService < BaseService
def assignee_can_read?(issuable, assignee_id) def assignee_can_read?(issuable, assignee_id)
new_assignee = User.find_by_id(assignee_id) new_assignee = User.find_by_id(assignee_id)
return false unless new_assignee.present? return false unless new_assignee
ability_name = :"read_#{issuable.to_ability_name}" ability_name = :"read_#{issuable.to_ability_name}"
resource = issuable.persisted? ? issuable : project resource = issuable.persisted? ? issuable : project
...@@ -207,6 +202,7 @@ class IssuableBaseService < BaseService ...@@ -207,6 +202,7 @@ class IssuableBaseService < BaseService
filter_params(issuable) filter_params(issuable)
old_labels = issuable.labels.to_a old_labels = issuable.labels.to_a
old_mentioned_users = issuable.mentioned_users.to_a old_mentioned_users = issuable.mentioned_users.to_a
old_assignees = issuable.assignees.to_a
label_ids = process_label_ids(params, existing_label_ids: issuable.label_ids) label_ids = process_label_ids(params, existing_label_ids: issuable.label_ids)
params[:label_ids] = label_ids if labels_changing?(issuable.label_ids, label_ids) params[:label_ids] = label_ids if labels_changing?(issuable.label_ids, label_ids)
...@@ -222,7 +218,13 @@ class IssuableBaseService < BaseService ...@@ -222,7 +218,13 @@ class IssuableBaseService < BaseService
handle_common_system_notes(issuable, old_labels: old_labels) handle_common_system_notes(issuable, old_labels: old_labels)
end end
handle_changes(issuable, old_labels: old_labels, old_mentioned_users: old_mentioned_users) handle_changes(
issuable,
old_labels: old_labels,
old_mentioned_users: old_mentioned_users,
old_assignees: old_assignees
)
after_update(issuable) after_update(issuable)
issuable.create_new_cross_references!(current_user) issuable.create_new_cross_references!(current_user)
execute_hooks(issuable, 'update') execute_hooks(issuable, 'update')
......
...@@ -9,11 +9,28 @@ module Issues ...@@ -9,11 +9,28 @@ module Issues
private private
def create_assignee_note(issue)
SystemNoteService.change_issue_assignees(
issue, issue.project, current_user, issue.assignees)
end
def execute_hooks(issue, action = 'open') def execute_hooks(issue, action = 'open')
issue_data = hook_data(issue, action) issue_data = hook_data(issue, action)
hooks_scope = issue.confidential? ? :confidential_issue_hooks : :issue_hooks hooks_scope = issue.confidential? ? :confidential_issue_hooks : :issue_hooks
issue.project.execute_hooks(issue_data, hooks_scope) issue.project.execute_hooks(issue_data, hooks_scope)
issue.project.execute_services(issue_data, hooks_scope) issue.project.execute_services(issue_data, hooks_scope)
end end
def filter_assignee(issuable)
return if params[:assignee_ids].blank?
assignee_ids = params[:assignee_ids].split(',').map(&:strip)
if assignee_ids == [ IssuableFinder::NONE ]
params[:assignee_ids] = ""
else
params.delete(:assignee_ids) unless assignee_ids.all?{ |assignee_id| assignee_can_read?(issuable, assignee_id)}
end
end
end end
end end
...@@ -12,7 +12,7 @@ module Issues ...@@ -12,7 +12,7 @@ module Issues
spam_check(issue, current_user) spam_check(issue, current_user)
end end
def handle_changes(issue, old_labels: [], old_mentioned_users: []) def handle_changes(issue, old_labels: [], old_mentioned_users: [], old_assignees: [])
if has_changes?(issue, old_labels: old_labels) if has_changes?(issue, old_labels: old_labels)
todo_service.mark_pending_todos_as_done(issue, current_user) todo_service.mark_pending_todos_as_done(issue, current_user)
end end
...@@ -26,9 +26,9 @@ module Issues ...@@ -26,9 +26,9 @@ module Issues
create_milestone_note(issue) create_milestone_note(issue)
end end
if issue.previous_changes.include?('assignee_id') if issue.previous_changes.include?('assignee_ids')
create_assignee_note(issue) create_assignee_note(issue)
notification_service.reassigned_issue(issue, current_user) notification_service.reassigned_issue(issue, current_user, old_assignees)
todo_service.reassigned_issue(issue, current_user) todo_service.reassigned_issue(issue, current_user)
end end
......
...@@ -4,7 +4,7 @@ module MergeRequests ...@@ -4,7 +4,7 @@ module MergeRequests
@assignable_issues ||= begin @assignable_issues ||= begin
if current_user == merge_request.author if current_user == merge_request.author
closes_issues.select do |issue| closes_issues.select do |issue|
!issue.is_a?(ExternalIssue) && !issue.assignee_id? && can?(current_user, :admin_issue, issue) !issue.is_a?(ExternalIssue) && !issue.assignees.any? && can?(current_user, :admin_issue, issue)
end end
else else
[] []
...@@ -14,7 +14,7 @@ module MergeRequests ...@@ -14,7 +14,7 @@ module MergeRequests
def execute def execute
assignable_issues.each do |issue| assignable_issues.each do |issue|
Issues::UpdateService.new(issue.project, current_user, assignee_id: current_user.id).execute(issue) Issues::UpdateService.new(issue.project, current_user, assignee_ids: [current_user.id]).execute(issue)
end end
{ {
......
...@@ -38,6 +38,11 @@ module MergeRequests ...@@ -38,6 +38,11 @@ module MergeRequests
private private
def create_assignee_note(merge_request)
SystemNoteService.change_assignee(
merge_request, merge_request.project, current_user, merge_request.assignee)
end
# Returns all origin and fork merge requests from `@project` satisfying passed arguments. # Returns all origin and fork merge requests from `@project` satisfying passed arguments.
def merge_requests_for(source_branch, mr_states: [:opened]) def merge_requests_for(source_branch, mr_states: [:opened])
MergeRequest MergeRequest
......
...@@ -8,6 +8,7 @@ class NotificationRecipientService ...@@ -8,6 +8,7 @@ class NotificationRecipientService
@project = project @project = project
end end
# TODO: refactor this: previous_assignee argument can be a user object or an array which is not really nice
def build_recipients(target, current_user, action: nil, previous_assignee: nil, skip_current_user: true) def build_recipients(target, current_user, action: nil, previous_assignee: nil, skip_current_user: true)
custom_action = build_custom_key(action, target) custom_action = build_custom_key(action, target)
...@@ -23,9 +24,13 @@ class NotificationRecipientService ...@@ -23,9 +24,13 @@ class NotificationRecipientService
# Re-assign is considered as a mention of the new assignee so we add the # Re-assign is considered as a mention of the new assignee so we add the
# new assignee to the list of recipients after we rejected users with # new assignee to the list of recipients after we rejected users with
# the "on mention" notification level # the "on mention" notification level
if [:reassign_merge_request, :reassign_issue].include?(custom_action) case custom_action
when :reassign_merge_request
recipients << previous_assignee if previous_assignee recipients << previous_assignee if previous_assignee
recipients << target.assignee recipients << target.assignee
when :reassign_issue
recipients.concat(previous_assignee) if previous_assignee.any?
recipients.concat(target.assignees)
end end
recipients = reject_muted_users(recipients) recipients = reject_muted_users(recipients)
......
...@@ -66,8 +66,23 @@ class NotificationService ...@@ -66,8 +66,23 @@ class NotificationService
# * issue new assignee if their notification level is not Disabled # * issue new assignee if their notification level is not Disabled
# * users with custom level checked with "reassign issue" # * users with custom level checked with "reassign issue"
# #
def reassigned_issue(issue, current_user) def reassigned_issue(issue, current_user, previous_assignees = [])
reassign_resource_email(issue, issue.project, current_user, :reassigned_issue_email) recipients = NotificationRecipientService.new(issue.project).build_recipients(
issue,
current_user,
action: "reassign",
previous_assignee: previous_assignees
)
recipients.each do |recipient|
mailer.send(
:reassigned_issue_email,
recipient.id,
issue.id,
previous_assignees.map(&:id),
current_user.id
).deliver_later
end
end end
# When we add labels to an issue we should send an email to: # When we add labels to an issue we should send an email to:
...@@ -407,10 +422,10 @@ class NotificationService ...@@ -407,10 +422,10 @@ class NotificationService
end end
def previous_record(object, attribute) def previous_record(object, attribute)
if object && attribute return unless object && attribute
if object.previous_changes.include?(attribute) if object.previous_changes.include?(attribute)
object.previous_changes[attribute].first object.previous_changes[attribute].first
end end
end end
end
end end
...@@ -49,6 +49,42 @@ module SystemNoteService ...@@ -49,6 +49,42 @@ module SystemNoteService
create_note(noteable: noteable, project: project, author: author, note: body) create_note(noteable: noteable, project: project, author: author, note: body)
end end
# Called when the assignees of an Issue is changed or removed
#
# issue - Issue object
# project - Project owning noteable
# author - User performing the change
# assignees - User being assigned, or nil
#
# Example Note text:
#
# "removed all assignees"
#
# "assigned to @user1 additionally to @user2"
#
# "assigned to @user1, @user2 and @user3 and unassigned from @user4 and @user5"
#
# "assigned to @user1 and @user2"
#
# Returns the created Note object
def change_issue_assignees(issue, project, author, assignees)
# TODO: basic implementation, should be improved before merging the MR
body =
if issue.assignees.any? && assignees.any?
unassigned_users = issue.assignees - assignees
added_users = assignees - issue.assignees
"assigned to #{added_users.map(&:to_reference).to_sentence} and unassigned #{unassigned_users.map(&:to_reference).to_sentence}"
elsif issue.assignees.any?
"removed all assignees"
elsif assignees.any?
"assigned to #{assignees.map(&:to_reference).to_sentence}"
end
create_note(noteable: issue, project: project, author: author, note: body)
end
# Called when one or more labels on a Noteable are added and/or removed # Called when one or more labels on a Noteable are added and/or removed
# #
# noteable - Noteable object # noteable - Noteable object
......
...@@ -264,9 +264,9 @@ class TodoService ...@@ -264,9 +264,9 @@ class TodoService
end end
def create_assignment_todo(issuable, author) def create_assignment_todo(issuable, author)
if issuable.assignee if issuable.assignees.any?
attributes = attributes_for_todo(issuable.project, issuable, author, Todo::ASSIGNED) attributes = attributes_for_todo(issuable.project, issuable, author, Todo::ASSIGNED)
create_todos(issuable.assignee, attributes) create_todos(issuable.assignees, attributes)
end end
end end
......
Reassigned <%= issuable.class.model_name.human.titleize %> <%= issuable.iid %> Reassigned Issue <%= @issue.iid %>
<%= url_for([issuable.project.namespace.becomes(Namespace), issuable.project, issuable, { only_path: false }]) %> <%= url_for([@issue.project.namespace.becomes(Namespace), @issue.project, @issue, { only_path: false }]) %>
Assignee changed <%= "from #{@previous_assignee.name}" if @previous_assignee -%> Assignee changed <%= "from #{@previous_assignees.map(&:name)}" if @previous_assignees.any? -%>
to <%= "#{issuable.assignee_id ? issuable.assignee_name : 'Unassigned'}" %> to <%= "#{@issue.assignees.any? ? @issue.assignees.map(&:name) : 'Unassigned'}" %>
...@@ -4,6 +4,6 @@ ...@@ -4,6 +4,6 @@
- if @issue.description - if @issue.description
= markdown(@issue.description, pipeline: :email, author: @issue.author) = markdown(@issue.description, pipeline: :email, author: @issue.author)
- if @issue.assignee_id.present? - if @issue.assignees.any?
%p %p
Assignee: #{@issue.assignee_name} Assignee: #{@issue.assignee_list}
...@@ -2,6 +2,6 @@ New Issue was created. ...@@ -2,6 +2,6 @@ New Issue was created.
Issue <%= @issue.iid %>: <%= url_for(namespace_project_issue_url(@issue.project.namespace, @issue.project, @issue)) %> Issue <%= @issue.iid %>: <%= url_for(namespace_project_issue_url(@issue.project.namespace, @issue.project, @issue)) %>
Author: <%= @issue.author_name %> Author: <%= @issue.author_name %>
Assignee: <%= @issue.assignee_name %> Assignee: <%= @issue.assignee_list %>
<%= @issue.description %> <%= @issue.description %>
...@@ -7,6 +7,6 @@ ...@@ -7,6 +7,6 @@
- if @issue.description - if @issue.description
= markdown(@issue.description, pipeline: :email, author: @issue.author) = markdown(@issue.description, pipeline: :email, author: @issue.author)
- if @issue.assignee_id.present? - if @issue.assignees.any?
%p %p
Assignee: #{@issue.assignee_name} Assignee: #{@issue.assignee_list}
...@@ -2,6 +2,6 @@ You have been mentioned in an issue. ...@@ -2,6 +2,6 @@ You have been mentioned in an issue.
Issue <%= @issue.iid %>: <%= url_for(namespace_project_issue_url(@issue.project.namespace, @issue.project, @issue)) %> Issue <%= @issue.iid %>: <%= url_for(namespace_project_issue_url(@issue.project.namespace, @issue.project, @issue)) %>
Author: <%= @issue.author_name %> Author: <%= @issue.author_name %>
Assignee: <%= @issue.assignee_name %> Assignee: <%= @issue.assignee_list %>
<%= @issue.description %> <%= @issue.description %>
= render 'reassigned_issuable_email', issuable: @issue %p
Assignee changed
- if @previous_assignees.any?
from
%strong= @previous_assignees.map(&:to_reference).to_sentence
to
- if @issue.assignees.any?
%strong= @issue.assignee_list
- else
%strong Unassigned
<%= render 'reassigned_issuable_email', issuable: @merge_request %> Reassigned Merge Request <%= @merge_request.iid %>
<%= url_for([@merge_request.project.namespace.becomes(Namespace), @merge_request.project, @merge_request, { only_path: false }]) %>
Assignee changed <%= "from #{@previous_assignee.name}" if @previous_assignee -%>
to <%= "#{@merge_request.assignee_id ? @merge_request.assignee_name : 'Unassigned'}" %>
...@@ -25,8 +25,10 @@ class CreateIssueAssigneesTable < ActiveRecord::Migration ...@@ -25,8 +25,10 @@ class CreateIssueAssigneesTable < ActiveRecord::Migration
def change def change
create_table :issue_assignees do |t| create_table :issue_assignees do |t|
t.references :user, foreign_key: true, index: true t.references :user, foreign_key: { on_delete: :cascade }, index: true, null: false
t.references :issue, foreign_key: true, index: true t.references :issue, foreign_key: { on_delete: :cascade }, null: false
end end
add_index :issue_assignees, [:issue_id, :user_id], unique: true
end end
end end
...@@ -1444,7 +1444,6 @@ ActiveRecord::Schema.define(version: 20170320173259) do ...@@ -1444,7 +1444,6 @@ ActiveRecord::Schema.define(version: 20170320173259) do
t.boolean "authorized_projects_populated" t.boolean "authorized_projects_populated"
t.boolean "auditor", default: false, null: false t.boolean "auditor", default: false, null: false
t.boolean "ghost" t.boolean "ghost"
t.boolean "notified_of_own_activity", default: false, null: false
end end
add_index "users", ["admin"], name: "index_users_on_admin", using: :btree add_index "users", ["admin"], name: "index_users_on_admin", using: :btree
......
...@@ -16,7 +16,7 @@ describe Dashboard::TodosController do ...@@ -16,7 +16,7 @@ describe Dashboard::TodosController do
describe 'GET #index' do describe 'GET #index' do
context 'when using pagination' do context 'when using pagination' do
let(:last_page) { user.todos.page.total_pages } let(:last_page) { user.todos.page.total_pages }
let!(:issues) { create_list(:issue, 2, project: project, assignee: user) } let!(:issues) { create_list(:issue, 2, project: project, assignees: [user]) }
before do before do
issues.each { |issue| todo_service.new_issue(issue, user) } issues.each { |issue| todo_service.new_issue(issue, user) }
......
...@@ -4,6 +4,7 @@ describe NotificationService, services: true do ...@@ -4,6 +4,7 @@ describe NotificationService, services: true do
include EmailHelpers include EmailHelpers
let(:notification) { NotificationService.new } let(:notification) { NotificationService.new }
let(:assignee) { create(:user) }
around(:each) do |example| around(:each) do |example|
perform_enqueued_jobs do perform_enqueued_jobs do
...@@ -52,7 +53,11 @@ describe NotificationService, services: true do ...@@ -52,7 +53,11 @@ describe NotificationService, services: true do
shared_examples 'participating by assignee notification' do shared_examples 'participating by assignee notification' do
it 'emails the participant' do it 'emails the participant' do
if issuable.is_a?(Issue)
issuable.assignees << participant
else
issuable.update_attribute(:assignee, participant) issuable.update_attribute(:assignee, participant)
end
notification_trigger notification_trigger
...@@ -103,14 +108,14 @@ describe NotificationService, services: true do ...@@ -103,14 +108,14 @@ describe NotificationService, services: true do
describe 'Notes' do describe 'Notes' do
context 'issue note' do context 'issue note' do
let(:project) { create(:empty_project, :private) } let(:project) { create(:empty_project, :private) }
let(:issue) { create(:issue, project: project, assignee: create(:user)) } let(:issue) { create(:issue, project: project, assignees: [assignee]) }
let(:mentioned_issue) { create(:issue, assignee: issue.assignee) } let(:mentioned_issue) { create(:issue, assignees: issue.assignees) }
let(:note) { create(:note_on_issue, noteable: issue, project_id: issue.project_id, note: '@mention referenced, @outsider also') } let(:note) { create(:note_on_issue, noteable: issue, project_id: issue.project_id, note: '@mention referenced, @outsider also') }
before do before do
build_team(note.project) build_team(note.project)
project.add_master(issue.author) project.add_master(issue.author)
project.add_master(issue.assignee) project.add_master(assignee)
project.add_master(note.author) project.add_master(note.author)
create(:note_on_issue, noteable: issue, project_id: issue.project_id, note: '@subscribed_participant cc this guy') create(:note_on_issue, noteable: issue, project_id: issue.project_id, note: '@subscribed_participant cc this guy')
update_custom_notification(:new_note, @u_guest_custom, project) update_custom_notification(:new_note, @u_guest_custom, project)
...@@ -130,7 +135,7 @@ describe NotificationService, services: true do ...@@ -130,7 +135,7 @@ describe NotificationService, services: true do
should_email(@u_watcher) should_email(@u_watcher)
should_email(note.noteable.author) should_email(note.noteable.author)
should_email(note.noteable.assignee) should_email(note.noteable.assignees.first)
should_email(@u_custom_global) should_email(@u_custom_global)
should_email(@u_mentioned) should_email(@u_mentioned)
should_email(@subscriber) should_email(@subscriber)
...@@ -186,7 +191,7 @@ describe NotificationService, services: true do ...@@ -186,7 +191,7 @@ describe NotificationService, services: true do
notification.new_note(note) notification.new_note(note)
should_email(note.noteable.author) should_email(note.noteable.author)
should_email(note.noteable.assignee) should_email(note.noteable.assignees.first)
should_email(@u_mentioned) should_email(@u_mentioned)
should_email(@u_custom_global) should_email(@u_custom_global)
should_not_email(@u_guest_custom) should_not_email(@u_guest_custom)
...@@ -208,7 +213,7 @@ describe NotificationService, services: true do ...@@ -208,7 +213,7 @@ describe NotificationService, services: true do
let(:member) { create(:user) } let(:member) { create(:user) }
let(:guest) { create(:user) } let(:guest) { create(:user) }
let(:admin) { create(:admin) } let(:admin) { create(:admin) }
let(:confidential_issue) { create(:issue, :confidential, project: project, author: author, assignee: assignee) } let(:confidential_issue) { create(:issue, :confidential, project: project, author: author, assignees: [assignee]) }
let(:note) { create(:note_on_issue, noteable: confidential_issue, project: project, note: "#{author.to_reference} #{assignee.to_reference} #{non_member.to_reference} #{member.to_reference} #{admin.to_reference}") } let(:note) { create(:note_on_issue, noteable: confidential_issue, project: project, note: "#{author.to_reference} #{assignee.to_reference} #{non_member.to_reference} #{member.to_reference} #{admin.to_reference}") }
let(:guest_watcher) { create_user_with_notification(:watch, "guest-watcher-confidential") } let(:guest_watcher) { create_user_with_notification(:watch, "guest-watcher-confidential") }
...@@ -234,8 +239,8 @@ describe NotificationService, services: true do ...@@ -234,8 +239,8 @@ describe NotificationService, services: true do
context 'issue note mention' do context 'issue note mention' do
let(:project) { create(:empty_project, :public) } let(:project) { create(:empty_project, :public) }
let(:issue) { create(:issue, project: project, assignee: create(:user)) } let(:issue) { create(:issue, project: project, assignees: [assignee]) }
let(:mentioned_issue) { create(:issue, assignee: issue.assignee) } let(:mentioned_issue) { create(:issue, assignees: issue.assignees) }
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') }
before do before do
...@@ -259,7 +264,7 @@ describe NotificationService, services: true do ...@@ -259,7 +264,7 @@ describe NotificationService, services: true do
should_email(@u_guest_watcher) should_email(@u_guest_watcher)
should_email(note.noteable.author) should_email(note.noteable.author)
should_email(note.noteable.assignee) should_email(note.noteable.assignees.first)
should_not_email(note.author) should_not_email(note.author)
should_email(@u_mentioned) should_email(@u_mentioned)
should_not_email(@u_disabled) should_not_email(@u_disabled)
...@@ -439,7 +444,7 @@ describe NotificationService, services: true do ...@@ -439,7 +444,7 @@ describe NotificationService, services: true do
let(:group) { create(:group) } let(:group) { create(:group) }
let(:project) { create(:empty_project, :public, namespace: group) } let(:project) { create(:empty_project, :public, namespace: group) }
let(:another_project) { create(:empty_project, :public, namespace: group) } let(:another_project) { create(:empty_project, :public, namespace: group) }
let(:issue) { create :issue, project: project, assignee: create(:user), description: 'cc @participant' } let(:issue) { create :issue, project: project, assignees: [assignee], description: 'cc @participant' }
before do before do
build_team(issue.project) build_team(issue.project)
...@@ -455,7 +460,7 @@ describe NotificationService, services: true do ...@@ -455,7 +460,7 @@ describe NotificationService, services: true do
it do it do
notification.new_issue(issue, @u_disabled) notification.new_issue(issue, @u_disabled)
should_email(issue.assignee) should_email(issue.assignees.first)
should_email(@u_watcher) should_email(@u_watcher)
should_email(@u_guest_watcher) should_email(@u_guest_watcher)
should_email(@u_guest_custom) should_email(@u_guest_custom)
...@@ -470,10 +475,10 @@ describe NotificationService, services: true do ...@@ -470,10 +475,10 @@ describe NotificationService, services: true do
end end
it do it do
create_global_setting_for(issue.assignee, :mention) create_global_setting_for(issue.assignees.first, :mention)
notification.new_issue(issue, @u_disabled) notification.new_issue(issue, @u_disabled)
should_not_email(issue.assignee) should_not_email(issue.assignees.first)
end end
it "emails subscribers of the issue's labels" do it "emails subscribers of the issue's labels" do
...@@ -504,7 +509,7 @@ describe NotificationService, services: true do ...@@ -504,7 +509,7 @@ describe NotificationService, services: true do
let(:member) { create(:user) } let(:member) { create(:user) }
let(:guest) { create(:user) } let(:guest) { create(:user) }
let(:admin) { create(:admin) } let(:admin) { create(:admin) }
let(:confidential_issue) { create(:issue, :confidential, project: project, title: 'Confidential issue', author: author, assignee: assignee) } let(:confidential_issue) { create(:issue, :confidential, project: project, title: 'Confidential issue', author: author, assignees: [assignee]) }
it "emails subscribers of the issue's labels that can read the issue" do it "emails subscribers of the issue's labels that can read the issue" do
project.add_developer(member) project.add_developer(member)
...@@ -548,9 +553,9 @@ describe NotificationService, services: true do ...@@ -548,9 +553,9 @@ describe NotificationService, services: true do
end end
it 'emails new assignee' do it 'emails new assignee' do
notification.reassigned_issue(issue, @u_disabled) notification.reassigned_issue(issue, @u_disabled, [assignee])
should_email(issue.assignee) should_email(issue.assignees.first)
should_email(@u_watcher) should_email(@u_watcher)
should_email(@u_guest_watcher) should_email(@u_guest_watcher)
should_email(@u_guest_custom) should_email(@u_guest_custom)
...@@ -564,9 +569,8 @@ describe NotificationService, services: true do ...@@ -564,9 +569,8 @@ describe NotificationService, services: true do
end end
it 'emails previous assignee even if he has the "on mention" notif level' do it 'emails previous assignee even if he has the "on mention" notif level' do
issue.update_attribute(:assignee, @u_mentioned) issue.assignees = [@u_mentioned]
issue.update_attributes(assignee: @u_watcher) notification.reassigned_issue(issue, @u_disabled, [@u_watcher])
notification.reassigned_issue(issue, @u_disabled)
should_email(@u_mentioned) should_email(@u_mentioned)
should_email(@u_watcher) should_email(@u_watcher)
...@@ -582,11 +586,11 @@ describe NotificationService, services: true do ...@@ -582,11 +586,11 @@ describe NotificationService, services: true do
end end
it 'emails new assignee even if he has the "on mention" notif level' do it 'emails new assignee even if he has the "on mention" notif level' do
issue.update_attributes(assignee: @u_mentioned) issue.assignees = [@u_mentioned]
notification.reassigned_issue(issue, @u_disabled) notification.reassigned_issue(issue, @u_disabled, [@u_mentioned])
expect(issue.assignee).to be @u_mentioned expect(issue.assignees.first).to be @u_mentioned
should_email(issue.assignee) should_email(issue.assignees.first)
should_email(@u_watcher) should_email(@u_watcher)
should_email(@u_guest_watcher) should_email(@u_guest_watcher)
should_email(@u_guest_custom) should_email(@u_guest_custom)
...@@ -600,11 +604,11 @@ describe NotificationService, services: true do ...@@ -600,11 +604,11 @@ describe NotificationService, services: true do
end end
it 'emails new assignee' do it 'emails new assignee' do
issue.update_attribute(:assignee, @u_mentioned) issue.assignees = [@u_mentioned]
notification.reassigned_issue(issue, @u_disabled) notification.reassigned_issue(issue, @u_disabled, [@u_mentioned])
expect(issue.assignee).to be @u_mentioned expect(issue.assignees.first).to be @u_mentioned
should_email(issue.assignee) should_email(issue.assignees.first)
should_email(@u_watcher) should_email(@u_watcher)
should_email(@u_guest_watcher) should_email(@u_guest_watcher)
should_email(@u_guest_custom) should_email(@u_guest_custom)
...@@ -618,17 +622,17 @@ describe NotificationService, services: true do ...@@ -618,17 +622,17 @@ describe NotificationService, services: true do
end end
it 'does not email new assignee if they are the current user' do it 'does not email new assignee if they are the current user' do
issue.update_attribute(:assignee, @u_mentioned) issue.assignees = [@u_mentioned]
notification.reassigned_issue(issue, @u_mentioned) notification.reassigned_issue(issue, @u_mentioned, [@u_mentioned])
expect(issue.assignee).to be @u_mentioned expect(issue.assignees.first).to be @u_mentioned
should_email(@u_watcher) should_email(@u_watcher)
should_email(@u_guest_watcher) should_email(@u_guest_watcher)
should_email(@u_guest_custom) should_email(@u_guest_custom)
should_email(@u_participant_mentioned) should_email(@u_participant_mentioned)
should_email(@subscriber) should_email(@subscriber)
should_email(@u_custom_global) should_email(@u_custom_global)
should_not_email(issue.assignee) should_not_email(issue.assignees.first)
should_not_email(@unsubscriber) should_not_email(@unsubscriber)
should_not_email(@u_participating) should_not_email(@u_participating)
should_not_email(@u_disabled) should_not_email(@u_disabled)
...@@ -638,7 +642,7 @@ describe NotificationService, services: true do ...@@ -638,7 +642,7 @@ describe NotificationService, services: true do
it_behaves_like 'participating notifications' do it_behaves_like 'participating notifications' do
let(:participant) { create(:user, username: 'user-participant') } let(:participant) { create(:user, username: 'user-participant') }
let(:issuable) { issue } let(:issuable) { issue }
let(:notification_trigger) { notification.reassigned_issue(issue, @u_disabled) } let(:notification_trigger) { notification.reassigned_issue(issue, @u_disabled, [assignee]) }
end end
end end
...@@ -668,7 +672,7 @@ describe NotificationService, services: true do ...@@ -668,7 +672,7 @@ describe NotificationService, services: true do
it "doesn't send email to anyone but subscribers of the given labels" do it "doesn't send email to anyone but subscribers of the given labels" do
notification.relabeled_issue(issue, [group_label_2, label_2], @u_disabled) notification.relabeled_issue(issue, [group_label_2, label_2], @u_disabled)
should_not_email(issue.assignee) should_not_email(issue.assignees.first)
should_not_email(issue.author) should_not_email(issue.author)
should_not_email(@u_watcher) should_not_email(@u_watcher)
should_not_email(@u_guest_watcher) should_not_email(@u_guest_watcher)
...@@ -692,7 +696,7 @@ describe NotificationService, services: true do ...@@ -692,7 +696,7 @@ describe NotificationService, services: true do
let(:member) { create(:user) } let(:member) { create(:user) }
let(:guest) { create(:user) } let(:guest) { create(:user) }
let(:admin) { create(:admin) } let(:admin) { create(:admin) }
let(:confidential_issue) { create(:issue, :confidential, project: project, title: 'Confidential issue', author: author, assignee: assignee) } let(:confidential_issue) { create(:issue, :confidential, project: project, title: 'Confidential issue', author: author, assignees: [assignee]) }
let!(:label_1) { create(:label, project: project, issues: [confidential_issue]) } let!(:label_1) { create(:label, project: project, issues: [confidential_issue]) }
let!(:label_2) { create(:label, project: project) } let!(:label_2) { create(:label, project: project) }
...@@ -730,7 +734,7 @@ describe NotificationService, services: true do ...@@ -730,7 +734,7 @@ describe NotificationService, services: true do
it 'sends email to issue assignee and issue author' do it 'sends email to issue assignee and issue author' do
notification.close_issue(issue, @u_disabled) notification.close_issue(issue, @u_disabled)
should_email(issue.assignee) should_email(issue.assignees.first)
should_email(issue.author) should_email(issue.author)
should_email(@u_watcher) should_email(@u_watcher)
should_email(@u_guest_watcher) should_email(@u_guest_watcher)
...@@ -761,7 +765,7 @@ describe NotificationService, services: true do ...@@ -761,7 +765,7 @@ describe NotificationService, services: true do
it 'sends email to issue notification recipients' do it 'sends email to issue notification recipients' do
notification.reopen_issue(issue, @u_disabled) notification.reopen_issue(issue, @u_disabled)
should_email(issue.assignee) should_email(issue.assignees.first)
should_email(issue.author) should_email(issue.author)
should_email(@u_watcher) should_email(@u_watcher)
should_email(@u_guest_watcher) should_email(@u_guest_watcher)
...@@ -789,7 +793,7 @@ describe NotificationService, services: true do ...@@ -789,7 +793,7 @@ describe NotificationService, services: true do
it 'sends email to issue notification recipients' do it 'sends email to issue notification recipients' do
notification.issue_moved(issue, new_issue, @u_disabled) notification.issue_moved(issue, new_issue, @u_disabled)
should_email(issue.assignee) should_email(issue.assignees.first)
should_email(issue.author) should_email(issue.author)
should_email(@u_watcher) should_email(@u_watcher)
should_email(@u_guest_watcher) should_email(@u_guest_watcher)
......
...@@ -54,7 +54,7 @@ describe Users::DestroyService, services: true do ...@@ -54,7 +54,7 @@ describe Users::DestroyService, services: true do
end end
context "for an issue the user was assigned to" do context "for an issue the user was assigned to" do
let!(:issue) { create(:issue, project: project, assignee: user) } let!(:issue) { create(:issue, project: project, assignees: [user]) }
before do before do
service.execute(user) service.execute(user)
...@@ -67,7 +67,7 @@ describe Users::DestroyService, services: true do ...@@ -67,7 +67,7 @@ describe Users::DestroyService, services: true do
it 'migrates the issue so that it is "Unassigned"' do it 'migrates the issue so that it is "Unassigned"' do
migrated_issue = Issue.find_by_id(issue.id) migrated_issue = Issue.find_by_id(issue.id)
expect(migrated_issue.assignee).to be_nil expect(migrated_issue.assignees).to be_empty
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