Commit 9e616459e068f2ba65f90016a09387a192fe4cfc
1 parent
11d52a15
Exists in
master
and in
4 other branches
add watchers to email recipients list. Add emails for close/merge MR
Showing
5 changed files
with
196 additions
and
27 deletions
Show diff stats
app/observers/merge_request_observer.rb
| ... | ... | @@ -7,6 +7,12 @@ class MergeRequestObserver < BaseObserver |
| 7 | 7 | |
| 8 | 8 | def after_close(merge_request, transition) |
| 9 | 9 | Note.create_status_change_note(merge_request, current_user, merge_request.state) |
| 10 | + | |
| 11 | + notification.close_mr(merge_request, current_user) | |
| 12 | + end | |
| 13 | + | |
| 14 | + def after_merge(merge_request, transition) | |
| 15 | + notification.merge_mr(merge_request, current_user) | |
| 10 | 16 | end |
| 11 | 17 | |
| 12 | 18 | def after_reopen(merge_request, transition) | ... | ... |
app/services/notification_service.rb
| ... | ... | @@ -17,7 +17,21 @@ class NotificationService |
| 17 | 17 | end |
| 18 | 18 | end |
| 19 | 19 | |
| 20 | - # TODO: When we close an issue we should send next emails: | |
| 20 | + # When create an issue we should send next emails: | |
| 21 | + # | |
| 22 | + # * issue assignee if his notification level is not Disabled | |
| 23 | + # * project team members with notification level higher then Participating | |
| 24 | + # | |
| 25 | + def new_issue(issue, current_user) | |
| 26 | + recipients = reject_muted_users([issue.assignee]) | |
| 27 | + recipients = recipients.concat(project_watchers(issue.project)).uniq | |
| 28 | + | |
| 29 | + recipients.each do |recipient| | |
| 30 | + Notify.delay.new_issue_email(recipient.id, issue.id) | |
| 31 | + end | |
| 32 | + end | |
| 33 | + | |
| 34 | + # When we close an issue we should send next emails: | |
| 21 | 35 | # |
| 22 | 36 | # * issue author if his notification level is not Disabled |
| 23 | 37 | # * issue assignee if his notification level is not Disabled |
| ... | ... | @@ -26,6 +40,9 @@ class NotificationService |
| 26 | 40 | def close_issue(issue, current_user) |
| 27 | 41 | recipients = reject_muted_users([issue.author, issue.assignee]) |
| 28 | 42 | |
| 43 | + # Add watchers to email list | |
| 44 | + recipients = recipients.concat(project_watchers(issue.project)).uniq | |
| 45 | + | |
| 29 | 46 | # Dont send email to me when I close an issue |
| 30 | 47 | recipients.delete(current_user) |
| 31 | 48 | |
| ... | ... | @@ -43,30 +60,17 @@ class NotificationService |
| 43 | 60 | reassign_email(issue, current_user, 'reassigned_issue_email') |
| 44 | 61 | end |
| 45 | 62 | |
| 46 | - # When create an issue we should send next emails: | |
| 47 | - # | |
| 48 | - # * issue assignee if his notification level is not Disabled | |
| 49 | - # | |
| 50 | - def new_issue(issue, current_user) | |
| 51 | - | |
| 52 | - if issue.assignee && issue.assignee != current_user | |
| 53 | - # skip if assignee notification disabled | |
| 54 | - return true if issue.assignee.notification.disabled? | |
| 55 | - | |
| 56 | - Notify.delay.new_issue_email(issue.id) | |
| 57 | - end | |
| 58 | - end | |
| 59 | 63 | |
| 60 | 64 | # When create a merge request we should send next emails: |
| 61 | 65 | # |
| 62 | 66 | # * mr assignee if his notification level is not Disabled |
| 63 | 67 | # |
| 64 | 68 | def new_merge_request(merge_request, current_user) |
| 65 | - if merge_request.assignee && merge_request.assignee != current_user | |
| 66 | - # skip if assignee notification disabled | |
| 67 | - return true if merge_request.assignee.notification.disabled? | |
| 69 | + recipients = reject_muted_users([merge_request.assignee]) | |
| 70 | + recipients = recipients.concat(project_watchers(merge_request.project)).uniq | |
| 68 | 71 | |
| 69 | - Notify.delay.new_merge_request_email(merge_request.id) | |
| 72 | + recipients.each do |recipient| | |
| 73 | + Notify.delay.new_merge_request_email(recipient.id, merge_request.id) | |
| 70 | 74 | end |
| 71 | 75 | end |
| 72 | 76 | |
| ... | ... | @@ -79,6 +83,36 @@ class NotificationService |
| 79 | 83 | reassign_email(merge_request, current_user, 'reassigned_merge_request_email') |
| 80 | 84 | end |
| 81 | 85 | |
| 86 | + # When we close a merge request we should send next emails: | |
| 87 | + # | |
| 88 | + # * merge_request author if his notification level is not Disabled | |
| 89 | + # * merge_request assignee if his notification level is not Disabled | |
| 90 | + # * project team members with notification level higher then Participating | |
| 91 | + # | |
| 92 | + def close_mr(merge_request) | |
| 93 | + recipients = reject_muted_users([merge_request.author, merge_request.assignee]) | |
| 94 | + recipients = recipients.concat(project_watchers(merge_request.project)).uniq | |
| 95 | + | |
| 96 | + recipients.each do |recipient| | |
| 97 | + Notify.delay.closed_merge_request_email(recipient.id, merge_request.id) | |
| 98 | + end | |
| 99 | + end | |
| 100 | + | |
| 101 | + # When we merge a merge request we should send next emails: | |
| 102 | + # | |
| 103 | + # * merge_request author if his notification level is not Disabled | |
| 104 | + # * merge_request assignee if his notification level is not Disabled | |
| 105 | + # * project team members with notification level higher then Participating | |
| 106 | + # | |
| 107 | + def merge_mr(merge_request) | |
| 108 | + recipients = reject_muted_users([merge_request.author, merge_request.assignee]) | |
| 109 | + recipients = recipients.concat(project_watchers(merge_request.project)).uniq | |
| 110 | + | |
| 111 | + recipients.each do |recipient| | |
| 112 | + Notify.delay.merged_merge_request_email(recipient.id, merge_request.id) | |
| 113 | + end | |
| 114 | + end | |
| 115 | + | |
| 82 | 116 | # Notify new user with email after creation |
| 83 | 117 | def new_user(user) |
| 84 | 118 | # Dont email omniauth created users |
| ... | ... | @@ -119,6 +153,11 @@ class NotificationService |
| 119 | 153 | |
| 120 | 154 | protected |
| 121 | 155 | |
| 156 | + # Get project users with WATCH notification level | |
| 157 | + def project_watchers(project) | |
| 158 | + project.users.where(notification_level: Notification::N_WATCH) | |
| 159 | + end | |
| 160 | + | |
| 122 | 161 | # Remove users with disabled notifications from array |
| 123 | 162 | # Also remove duplications and nil recipients |
| 124 | 163 | def reject_muted_users(users) |
| ... | ... | @@ -130,6 +169,9 @@ class NotificationService |
| 130 | 169 | def reassign_email(target, current_user, method) |
| 131 | 170 | recipients = User.where(id: [target.assignee_id, target.assignee_id_was]) |
| 132 | 171 | |
| 172 | + # Add watchers to email list | |
| 173 | + recipients = recipients.concat(project_watchers(target.project)) | |
| 174 | + | |
| 133 | 175 | # reject users with disabled notifications |
| 134 | 176 | recipients = reject_muted_users(recipients) |
| 135 | 177 | ... | ... |
| ... | ... | @@ -0,0 +1,9 @@ |
| 1 | +%p | |
| 2 | + = "Merge Request #{@merge_request.id} was closed" | |
| 3 | +%p | |
| 4 | + = link_to_gfm truncate(@merge_request.title, length: 40), project_merge_request_url(@merge_request.project, @merge_request) | |
| 5 | +%p | |
| 6 | + Branches: #{@merge_request.source_branch} → #{@merge_request.target_branch} | |
| 7 | +%p | |
| 8 | + Assignee: #{@merge_request.author_name} → #{@merge_request.assignee_name} | |
| 9 | + | ... | ... |
| ... | ... | @@ -0,0 +1,9 @@ |
| 1 | +%p | |
| 2 | + = "Merge Request #{@merge_request.id} was merged" | |
| 3 | +%p | |
| 4 | + = link_to_gfm truncate(@merge_request.title, length: 40), project_merge_request_url(@merge_request.project, @merge_request) | |
| 5 | +%p | |
| 6 | + Branches: #{@merge_request.source_branch} → #{@merge_request.target_branch} | |
| 7 | +%p | |
| 8 | + Assignee: #{@merge_request.author_name} → #{@merge_request.assignee_name} | |
| 9 | + | ... | ... |
spec/services/notification_service_spec.rb
| ... | ... | @@ -23,6 +23,10 @@ describe NotificationService do |
| 23 | 23 | describe 'Issues' do |
| 24 | 24 | let(:issue) { create :issue, assignee: create(:user) } |
| 25 | 25 | |
| 26 | + before do | |
| 27 | + build_team(issue.project) | |
| 28 | + end | |
| 29 | + | |
| 26 | 30 | describe :new_issue do |
| 27 | 31 | it 'should sent email to issue assignee' do |
| 28 | 32 | Notify.should_receive(:new_issue_email).with(issue.id) |
| ... | ... | @@ -31,16 +35,41 @@ describe NotificationService do |
| 31 | 35 | end |
| 32 | 36 | |
| 33 | 37 | describe :reassigned_issue do |
| 34 | - it 'should sent email to issue old assignee and new issue assignee' do | |
| 35 | - Notify.should_receive(:reassigned_issue_email) | |
| 36 | - notification.reassigned_issue(issue, issue.author) | |
| 38 | + it 'should email new assignee' do | |
| 39 | + should_email(issue.assignee_id) | |
| 40 | + should_email(@u_watcher.id) | |
| 41 | + should_not_email(@u_participating.id) | |
| 42 | + should_not_email(@u_disabled.id) | |
| 43 | + | |
| 44 | + notification.reassigned_issue(issue, @u_disabled) | |
| 45 | + end | |
| 46 | + | |
| 47 | + def should_email(user_id) | |
| 48 | + Notify.should_receive(:reassigned_issue_email).with(user_id, issue.id, issue.assignee_id) | |
| 49 | + end | |
| 50 | + | |
| 51 | + def should_not_email(user_id) | |
| 52 | + Notify.should_not_receive(:reassigned_issue_email).with(user_id, issue.id, issue.assignee_id) | |
| 37 | 53 | end |
| 38 | 54 | end |
| 39 | 55 | |
| 40 | 56 | describe :close_issue do |
| 41 | 57 | it 'should sent email to issue assignee and issue author' do |
| 42 | - Notify.should_receive(:issue_status_changed_email) | |
| 43 | - notification.close_issue(issue, issue.author) | |
| 58 | + should_email(issue.assignee_id) | |
| 59 | + should_email(issue.author_id) | |
| 60 | + should_email(@u_watcher.id) | |
| 61 | + should_not_email(@u_participating.id) | |
| 62 | + should_not_email(@u_disabled.id) | |
| 63 | + | |
| 64 | + notification.close_issue(issue, @u_disabled) | |
| 65 | + end | |
| 66 | + | |
| 67 | + def should_email(user_id) | |
| 68 | + Notify.should_receive(:issue_status_changed_email).with(user_id, issue.id, issue.assignee_id) | |
| 69 | + end | |
| 70 | + | |
| 71 | + def should_not_email(user_id) | |
| 72 | + Notify.should_not_receive(:issue_status_changed_email).with(user_id, issue.id, issue.assignee_id) | |
| 44 | 73 | end |
| 45 | 74 | end |
| 46 | 75 | end |
| ... | ... | @@ -48,16 +77,90 @@ describe NotificationService do |
| 48 | 77 | describe 'Merge Requests' do |
| 49 | 78 | let(:merge_request) { create :merge_request, assignee: create(:user) } |
| 50 | 79 | |
| 80 | + before do | |
| 81 | + build_team(merge_request.project) | |
| 82 | + end | |
| 83 | + | |
| 51 | 84 | describe :new_merge_request do |
| 52 | - it 'should send email to merge_request assignee' do | |
| 85 | + it do | |
| 86 | + should_email(merge_request.assignee_id) | |
| 87 | + should_email(@u_watcher.id) | |
| 88 | + should_not_email(@u_participating.id) | |
| 89 | + should_not_email(@u_disabled.id) | |
| 90 | + notification.new_merge_request(merge_request, @u_disabled) | |
| 91 | + end | |
| 92 | + | |
| 93 | + def should_email(user_id) | |
| 53 | 94 | Notify.should_receive(:new_merge_request_email).with(merge_request.id) |
| 54 | - notification.new_merge_request(merge_request, merge_request.author) | |
| 55 | 95 | end |
| 56 | 96 | |
| 57 | - it 'should not send email to merge_request assignee if he is current_user' do | |
| 97 | + def should_not_email(user_id) | |
| 58 | 98 | Notify.should_not_receive(:new_merge_request_email).with(merge_request.id) |
| 59 | - notification.new_merge_request(merge_request, merge_request.assignee) | |
| 60 | 99 | end |
| 61 | 100 | end |
| 101 | + | |
| 102 | + describe :reassigned_merge_request do | |
| 103 | + it do | |
| 104 | + should_email(merge_request.assignee_id) | |
| 105 | + should_email(@u_watcher.id) | |
| 106 | + should_not_email(@u_participating.id) | |
| 107 | + should_not_email(@u_disabled.id) | |
| 108 | + notification.reassigned_merge_request(merge_request, merge_request.author) | |
| 109 | + end | |
| 110 | + | |
| 111 | + def should_email(user_id) | |
| 112 | + Notify.should_receive(:reassigned_merge_request_email).with(user_id, merge_request.id, merge_request.assignee_id) | |
| 113 | + end | |
| 114 | + | |
| 115 | + def should_not_email(user_id) | |
| 116 | + Notify.should_not_receive(:reassigned_merge_request_email).with(user_id, merge_request.id, merge_request.assignee_id) | |
| 117 | + end | |
| 118 | + end | |
| 119 | + | |
| 120 | + describe :closed_merge_request do | |
| 121 | + it do | |
| 122 | + should_email(merge_request.assignee_id) | |
| 123 | + should_email(@u_watcher.id) | |
| 124 | + should_not_email(@u_participating.id) | |
| 125 | + should_not_email(@u_disabled.id) | |
| 126 | + notification.close_mr(merge_request) | |
| 127 | + end | |
| 128 | + | |
| 129 | + def should_email(user_id) | |
| 130 | + Notify.should_receive(:closed_merge_request_email).with(user_id, merge_request.id) | |
| 131 | + end | |
| 132 | + | |
| 133 | + def should_not_email(user_id) | |
| 134 | + Notify.should_not_receive(:closed_merge_request_email).with(user_id, merge_request.id) | |
| 135 | + end | |
| 136 | + end | |
| 137 | + | |
| 138 | + describe :merged_merge_request do | |
| 139 | + it do | |
| 140 | + should_email(merge_request.assignee_id) | |
| 141 | + should_email(@u_watcher.id) | |
| 142 | + should_not_email(@u_participating.id) | |
| 143 | + should_not_email(@u_disabled.id) | |
| 144 | + notification.merge_mr(merge_request) | |
| 145 | + end | |
| 146 | + | |
| 147 | + def should_email(user_id) | |
| 148 | + Notify.should_receive(:merged_merge_request_email).with(user_id, merge_request.id) | |
| 149 | + end | |
| 150 | + | |
| 151 | + def should_not_email(user_id) | |
| 152 | + Notify.should_not_receive(:merged_merge_request_email).with(user_id, merge_request.id) | |
| 153 | + end | |
| 154 | + end | |
| 155 | + end | |
| 156 | + | |
| 157 | + def build_team(project) | |
| 158 | + @u_watcher = create(:user, notification_level: Notification::N_WATCH) | |
| 159 | + @u_participating = create(:user, notification_level: Notification::N_PARTICIPATING) | |
| 160 | + @u_disabled = create(:user, notification_level: Notification::N_DISABLED) | |
| 161 | + | |
| 162 | + project.team << [@u_watcher, :master] | |
| 163 | + project.team << [@u_participating, :master] | |
| 164 | + project.team << [@u_disabled, :master] | |
| 62 | 165 | end |
| 63 | 166 | end | ... | ... |