Class: NotificationService

Inherits:
Object
  • Object
show all
Defined in:
app/services/notification_service.rb

Overview

NotificationService class

Used for notifying users with emails about different events

Ex.

NotificationService.new.new_issue(issue, current_user)

When calculating the recipients of a notification is expensive (for instance, in the new issue case), ‘#async` will make that calculation happen in Sidekiq instead:

NotificationService.new.async.new_issue(issue, current_user)

Defined Under Namespace

Classes: Async

Constant Summary collapse

EXCLUDED_ACTIONS =

These should not be called by the MailScheduler::NotificationServiceWorker - what would it even mean?

%i[async].freeze
NEW_COMMIT_EMAIL_DISPLAY_LIMIT =
20

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.permitted_actionsObject



23
24
25
26
27
# File 'app/services/notification_service.rb', line 23

def self.permitted_actions
  @permitted_actions ||= gitlab_extensions.flat_map do |klass|
    klass.public_instance_methods(false) - EXCLUDED_ACTIONS
  end.to_set
end

Instance Method Details

#accept_group_invite(group_member) ⇒ Object



579
580
581
# File 'app/services/notification_service.rb', line 579

def accept_group_invite(group_member)
  mailer.member_invite_accepted_email(group_member.real_source_type, group_member.id).deliver_later
end

#accept_project_invite(project_member) ⇒ Object



546
547
548
549
550
# File 'app/services/notification_service.rb', line 546

def accept_project_invite(project_member)
  return true unless project_member.notifiable?(:subscription)

  mailer.member_invite_accepted_email(project_member.real_source_type, project_member.id).deliver_later
end

#access_token_about_to_expire(user, token_names) ⇒ Object

Notify the owner of the personal access token, when it is about to expire And mark the token with about_to_expire_delivered



114
115
116
117
118
# File 'app/services/notification_service.rb', line 114

def access_token_about_to_expire(user, token_names)
  return unless user.can?(:receive_notifications)

  mailer.access_token_about_to_expire_email(user, token_names).deliver_later
end

#access_token_created(user, token_name) ⇒ Object

Notify the owner of the account when a new personal access token is created



106
107
108
109
110
# File 'app/services/notification_service.rb', line 106

def access_token_created(user, token_name)
  return unless user.can?(:receive_notifications)

  mailer.access_token_created_email(user, token_name).deliver_later
end

#access_token_expired(user, token_names = []) ⇒ Object

Notify the user when at least one of their personal access tokens has expired today



121
122
123
124
125
# File 'app/services/notification_service.rb', line 121

def access_token_expired(user, token_names = [])
  return unless user.can?(:receive_notifications)

  mailer.access_token_expired_email(user, token_names).deliver_later
end

#access_token_revoked(user, token_name, source = nil) ⇒ Object

Notify the user when one of their personal access tokens is revoked



128
129
130
131
132
# File 'app/services/notification_service.rb', line 128

def access_token_revoked(user, token_name, source = nil)
  return unless user.can?(:receive_notifications)

  mailer.access_token_revoked_email(user, token_name, source).deliver_later
end

#application_authorized(user) ⇒ Object

Notify the owner of the account when an application is authorized



99
100
101
102
103
# File 'app/services/notification_service.rb', line 99

def application_authorized(user)
  return unless user.can?(:receive_notifications)

  mailer.application_authorized_email(user).deliver_now
end

#application_created(user) ⇒ Object

Notify the owner of the account when a new application is created



92
93
94
95
96
# File 'app/services/notification_service.rb', line 92

def application_created(user)
  return unless user.can?(:receive_notifications)

  mailer.application_created_email(user).deliver_now
end

#approve_mr(merge_request, current_user) ⇒ Object



786
787
788
# File 'app/services/notification_service.rb', line 786

def approve_mr(merge_request, current_user)
  approve_mr_email(merge_request, merge_request.target_project, current_user)
end

#asyncObject



45
46
47
# File 'app/services/notification_service.rb', line 45

def async
  @async ||= Async.new(self)
end

#autodevops_disabled(pipeline, recipients) ⇒ Object



669
670
671
672
673
674
675
# File 'app/services/notification_service.rb', line 669

def autodevops_disabled(pipeline, recipients)
  return if pipeline.project.emails_disabled?

  recipients.each do |recipient|
    mailer.autodevops_disabled_email(pipeline, recipient).deliver_later
  end
end

#change_in_merge_request_draft_status(merge_request, current_user) ⇒ Object



282
283
284
285
286
287
288
289
290
291
292
293
294
# File 'app/services/notification_service.rb', line 282

def change_in_merge_request_draft_status(merge_request, current_user)
  recipients = NotificationRecipients::BuildService.build_recipients(merge_request, current_user, action: "draft_status_change")

  recipients.each do |recipient|
    mailer.send(
      :change_in_merge_request_draft_status_email,
      recipient.user.id,
      merge_request.id,
      current_user.id,
      recipient.reason
    ).deliver_later
  end
end

#changed_milestone(target, milestone, current_user) ⇒ Object



819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
# File 'app/services/notification_service.rb', line 819

def changed_milestone(target, milestone, current_user)
  method = case target
           when Issue
             :changed_milestone_issue_email
           when MergeRequest
             :changed_milestone_merge_request_email
           end

  recipients = NotificationRecipients::BuildService.build_recipients(
    target,
    current_user,
    action: 'changed_milestone'
  )

  recipients.each do |recipient|
    mailer.send(method, recipient.user.id, target.id, milestone, current_user.id).deliver_later
  end
end

#changed_reviewer_of_merge_request(merge_request, current_user, previous_reviewers = []) ⇒ Object

When we change reviewer in a merge_request we should send an email to:

* merge_request old reviewers if their notification level is not Disabled
* merge_request new reviewers if their notification level is not Disabled
* users with custom level checked with "change reviewer merge request"


351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
# File 'app/services/notification_service.rb', line 351

def changed_reviewer_of_merge_request(merge_request, current_user, previous_reviewers = [])
  recipients = NotificationRecipients::BuildService.build_recipients(
    merge_request,
    current_user,
    action: "change_reviewer",
    previous_assignees: previous_reviewers
  )

  previous_reviewer_ids = previous_reviewers.map(&:id)

  recipients.each do |recipient|
    mailer.changed_reviewer_of_merge_request_email(
      recipient.user.id,
      merge_request.id,
      previous_reviewer_ids,
      current_user.id,
      recipient.reason
    ).deliver_later
  end
end

#close_issue(issue, current_user, params = {}) ⇒ Object

When we close an issue we should send an email to:

* issue author if their notification level is not Disabled
* issue assignee if their notification level is not Disabled
* project team members with notification level higher then Participating
* users with custom level checked with "close issue"


202
203
204
# File 'app/services/notification_service.rb', line 202

def close_issue(issue, current_user, params = {})
  close_resource_email(issue, current_user, :closed_issue_email, closed_via: params[:closed_via])
end

#close_mr(merge_request, current_user) ⇒ Object



392
393
394
# File 'app/services/notification_service.rb', line 392

def close_mr(merge_request, current_user)
  close_resource_email(merge_request, current_user, :closed_merge_request_email)
end

#decline_access_request(member) ⇒ Object



521
522
523
524
525
# File 'app/services/notification_service.rb', line 521

def decline_access_request(member)
  return true unless member.notifiable?(:subscription)

  mailer.member_access_denied_email(member.real_source_type, member.source_id, member.user_id).deliver_later
end

#decline_invite(member) ⇒ Object



527
528
529
530
531
532
533
534
535
536
537
# File 'app/services/notification_service.rb', line 527

def decline_invite(member)
  # Must always send, regardless of project/namespace configuration since it's a
  # response to the user's action.

  mailer.member_invite_declined_email(
    member.real_source_type,
    member.source.id,
    member.invite_email,
    member.created_by_id
  ).deliver_later
end

#disabled_two_factor(user) ⇒ Object



49
50
51
52
53
# File 'app/services/notification_service.rb', line 49

def disabled_two_factor(user)
  return unless user.can?(:receive_notifications)

  mailer.disabled_two_factor_email(user).deliver_later
end

#group_was_exported(group, current_user) ⇒ Object



749
750
751
752
753
# File 'app/services/notification_service.rb', line 749

def group_was_exported(group, current_user)
  return true unless notifiable?(current_user, :mention, group: group)

  mailer.group_was_exported_email(current_user, group).deliver_later
end

#group_was_not_exported(group, current_user, errors) ⇒ Object



755
756
757
758
759
# File 'app/services/notification_service.rb', line 755

def group_was_not_exported(group, current_user, errors)
  return true unless notifiable?(current_user, :mention, group: group)

  mailer.group_was_not_exported_email(current_user, group, errors).deliver_later
end

#inactive_project_deletion_warning(project, deletion_date) ⇒ Object



794
795
796
797
798
# File 'app/services/notification_service.rb', line 794

def inactive_project_deletion_warning(project, deletion_date)
  owners_and_maintainers_without_invites(project).each do |recipient|
    mailer.inactive_project_deletion_warning_email(project, recipient.user, deletion_date).deliver_later
  end
end

#invite_group_member(group_member, token) ⇒ Object

Group invite



571
572
573
# File 'app/services/notification_service.rb', line 571

def invite_group_member(group_member, token)
  mailer.member_invited_email(group_member.real_source_type, group_member.id, token).deliver_later
end

#invite_member_reminder(group_member, token, reminder_index) ⇒ Object



575
576
577
# File 'app/services/notification_service.rb', line 575

def invite_member_reminder(group_member, token, reminder_index)
  mailer.member_invited_reminder_email(group_member.real_source_type, group_member.id, token, reminder_index).deliver_later
end

#invite_project_member(project_member, token) ⇒ Object

Project invite



540
541
542
543
544
# File 'app/services/notification_service.rb', line 540

def invite_project_member(project_member, token)
  return true unless project_member.notifiable?(:subscription)

  mailer.member_invited_email(project_member.real_source_type, project_member.id, token).deliver_later
end

#issue_cloned(issue, new_issue, current_user) ⇒ Object



624
625
626
627
628
629
630
631
632
# File 'app/services/notification_service.rb', line 624

def issue_cloned(issue, new_issue, current_user)
  recipients = NotificationRecipients::BuildService.build_recipients(issue, current_user, action: 'cloned')

  recipients.map do |recipient|
    email = mailer.issue_cloned_email(recipient.user, issue, new_issue, current_user, recipient.reason)
    email.deliver_later
    email
  end
end

#issue_due(issue) ⇒ Object



707
708
709
710
711
712
713
714
715
716
717
718
719
# File 'app/services/notification_service.rb', line 707

def issue_due(issue)
  recipients = NotificationRecipients::BuildService.build_recipients(
    issue,
    issue.author,
    action: 'due',
    custom_action: :issue_due,
    skip_current_user: false
  )

  recipients.each do |recipient|
    mailer.send(:issue_due_email, recipient.user.id, issue.id, recipient.reason).deliver_later
  end
end

#issue_moved(issue, new_issue, current_user) ⇒ Object



614
615
616
617
618
619
620
621
622
# File 'app/services/notification_service.rb', line 614

def issue_moved(issue, new_issue, current_user)
  recipients = NotificationRecipients::BuildService.build_recipients(issue, current_user, action: 'moved')

  recipients.map do |recipient|
    email = mailer.issue_moved_email(recipient.user, issue, new_issue, current_user, recipient.reason)
    email.deliver_later
    email
  end
end

#member_about_to_expire(member) ⇒ Object



564
565
566
567
568
# File 'app/services/notification_service.rb', line 564

def member_about_to_expire(member)
  return true unless member.notifiable?(:mention)

  mailer.member_about_to_expire_email(member.real_source_type, member.id).deliver_later
end

#merge_mr(merge_request, current_user) ⇒ Object



400
401
402
403
404
405
406
407
# File 'app/services/notification_service.rb', line 400

def merge_mr(merge_request, current_user)
  close_resource_email(
    merge_request,
    current_user,
    :merged_merge_request_email,
    skip_current_user: !merge_request.auto_merge_enabled?
  )
end

#merge_request_unmergeable(merge_request) ⇒ Object

When a merge request is found to be unmergeable, we should send an email to:

* mr author
* mr merge user if set


301
302
303
# File 'app/services/notification_service.rb', line 301

def merge_request_unmergeable(merge_request)
  merge_request_unmergeable_email(merge_request)
end

#merge_when_pipeline_succeeds(merge_request, current_user) ⇒ Object



773
774
775
776
777
778
779
780
781
782
783
784
# File 'app/services/notification_service.rb', line 773

def merge_when_pipeline_succeeds(merge_request, current_user)
  recipients = ::NotificationRecipients::BuildService.build_recipients(
    merge_request,
    current_user,
    action: 'merge_when_pipeline_succeeds',
    custom_action: :merge_when_pipeline_succeeds
  )

  recipients.each do |recipient|
    mailer.merge_when_pipeline_succeeds_email(recipient.user.id, merge_request.id, current_user.id).deliver_later
  end
end

#new_access_request(member) ⇒ Object

Members



511
512
513
514
515
516
517
518
519
# File 'app/services/notification_service.rb', line 511

def new_access_request(member)
  return true unless member.notifiable?(:subscription)

  recipients = member.source.access_request_approvers_to_be_notified

  return true if recipients.empty?

  recipients.each { |recipient| deliver_access_request_email(recipient, member) }
end

#new_achievement_email(user, achievement) ⇒ Object



838
839
840
# File 'app/services/notification_service.rb', line 838

def new_achievement_email(user, achievement)
  mailer.new_achievement_email(user, achievement)
end

#new_email_address_added(user, email) ⇒ Object

Notify a user when a new email address is added to the their account



165
166
167
168
169
# File 'app/services/notification_service.rb', line 165

def new_email_address_added(user, email)
  return unless user.can?(:receive_notifications)

  mailer.new_email_address_added_email(user, email).deliver_later
end

#new_gpg_key(gpg_key) ⇒ Object

Always notify the user about gpg key added

This is a security email so it will be sent even if the user disabled notifications



72
73
74
75
76
# File 'app/services/notification_service.rb', line 72

def new_gpg_key(gpg_key)
  if gpg_key.user&.can?(:receive_notifications)
    mailer.new_gpg_key_email(gpg_key.id).deliver_later
  end
end

#new_group_member(group_member) ⇒ Object



583
584
585
586
587
# File 'app/services/notification_service.rb', line 583

def new_group_member(group_member)
  return true unless group_member.notifiable?(:mention)

  mailer.member_access_granted_email(group_member.real_source_type, group_member.id).deliver_later
end

#new_instance_access_request(user) ⇒ Object



492
493
494
495
496
497
498
499
500
# File 'app/services/notification_service.rb', line 492

def new_instance_access_request(user)
  recipients = User.instance_access_request_approvers_to_be_notified # https://gitlab.com/gitlab-org/gitlab/-/issues/277016 will change this

  return true if recipients.empty?

  recipients.each do |recipient|
    mailer.instance_access_request_email(user, recipient).deliver_later
  end
end

#new_issue(issue, current_user) ⇒ Object

When create an issue we should send an email to:

* issue assignee if their notification level is not Disabled
* project team members with notification level higher then Participating
* watchers of the issue's labels
* users with custom level checked with "new issue"


178
179
180
# File 'app/services/notification_service.rb', line 178

def new_issue(issue, current_user)
  new_resource_email(issue, current_user, :new_issue_email)
end

#new_key(key) ⇒ Object

Always notify user about ssh key added only if ssh key is not deploy key

This is security email so it will be sent even if user disabled notifications. However, it won’t be sent to internal users like the ghost user or the EE support bot.



62
63
64
65
66
# File 'app/services/notification_service.rb', line 62

def new_key(key)
  if key.user&.can?(:receive_notifications)
    mailer.new_ssh_key_email(key.id).deliver_later
  end
end

#new_mentions_in_issue(issue, new_mentioned_users, current_user) ⇒ Object

When issue text is updated, we should send an email to:

* newly mentioned project team members with notification level higher than Participating


186
187
188
189
190
191
192
193
# File 'app/services/notification_service.rb', line 186

def new_mentions_in_issue(issue, new_mentioned_users, current_user)
  new_mentions_in_resource_email(
    issue,
    new_mentioned_users,
    current_user,
    :new_mention_in_issue_email
  )
end

#new_mentions_in_merge_request(merge_request, new_mentioned_users, current_user) ⇒ Object

When merge request text is updated, we should send an email to:

* newly mentioned project team members with notification level higher than Participating


309
310
311
312
313
314
315
316
# File 'app/services/notification_service.rb', line 309

def new_mentions_in_merge_request(merge_request, new_mentioned_users, current_user)
  new_mentions_in_resource_email(
    merge_request,
    new_mentioned_users,
    current_user,
    :new_mention_in_merge_request_email
  )
end

#new_merge_request(merge_request, current_user) ⇒ Object

When create a merge request we should send an email to:

* mr author
* mr assignees if their notification level is not Disabled
* project team members with notification level higher then Participating
* watchers of the mr's labels
* users with custom level checked with "new merge request"

In EE, approvers of the merge request are also included



251
252
253
# File 'app/services/notification_service.rb', line 251

def new_merge_request(merge_request, current_user)
  new_resource_email(merge_request, current_user, :new_merge_request_email)
end

#new_note(note) ⇒ Object

Notify users on new note in system



438
439
440
441
442
443
444
445
446
# File 'app/services/notification_service.rb', line 438

def new_note(note)
  return true unless note.noteable_type.present?

  # ignore gitlab service messages
  return true if note.system_note_with_references?

  send_new_note_notifications(note)
  send_service_desk_notification(note)
end

#new_project_member(project_member) ⇒ Object



552
553
554
555
556
# File 'app/services/notification_service.rb', line 552

def new_project_member(project_member)
  return true unless project_member.notifiable?(:mention, skip_read_ability: true)

  mailer.member_access_granted_email(project_member.real_source_type, project_member.id).deliver_later
end

#new_review(review) ⇒ Object

Notify users on new review in system



762
763
764
765
766
767
768
769
770
771
# File 'app/services/notification_service.rb', line 762

def new_review(review)
  recipients = NotificationRecipients::BuildService.build_new_review_recipients(review)
  deliver_options = new_review_deliver_options(review)

  recipients.each do |recipient|
    mailer
      .new_review_email(recipient.user.id, review.id)
      .deliver_later(deliver_options)
  end
end

#new_user(user, token = nil) ⇒ Object

Notify new user with email after creation



430
431
432
433
434
435
# File 'app/services/notification_service.rb', line 430

def new_user(user, token = nil)
  return true unless notifiable?(user, :mention)

  # Don't email omniauth created users
  mailer.new_user_email(user.id, token).deliver_later unless user.identities.any?
end

#pages_domain_auto_ssl_failed(domain) ⇒ Object



701
702
703
704
705
# File 'app/services/notification_service.rb', line 701

def pages_domain_auto_ssl_failed(domain)
  project_maintainers_recipients(domain, action: 'disabled').each do |recipient|
    mailer.pages_domain_auto_ssl_failed_email(domain, recipient.user).deliver_later
  end
end

#pages_domain_disabled(domain) ⇒ Object



695
696
697
698
699
# File 'app/services/notification_service.rb', line 695

def pages_domain_disabled(domain)
  project_maintainers_recipients(domain, action: 'disabled').each do |recipient|
    mailer.pages_domain_disabled_email(domain, recipient.user).deliver_later
  end
end

#pages_domain_enabled(domain) ⇒ Object



689
690
691
692
693
# File 'app/services/notification_service.rb', line 689

def pages_domain_enabled(domain)
  project_maintainers_recipients(domain, action: 'enabled').each do |recipient|
    mailer.pages_domain_enabled_email(domain, recipient.user).deliver_later
  end
end

#pages_domain_verification_failed(domain) ⇒ Object



683
684
685
686
687
# File 'app/services/notification_service.rb', line 683

def pages_domain_verification_failed(domain)
  project_maintainers_recipients(domain, action: 'failed').each do |recipient|
    mailer.pages_domain_verification_failed_email(domain, recipient.user).deliver_later
  end
end

#pages_domain_verification_succeeded(domain) ⇒ Object



677
678
679
680
681
# File 'app/services/notification_service.rb', line 677

def pages_domain_verification_succeeded(domain)
  project_maintainers_recipients(domain, action: 'succeeded').each do |recipient|
    mailer.pages_domain_verification_succeeded_email(domain, recipient.user).deliver_later
  end
end

#pipeline_finished(pipeline, ref_status: nil, recipients: nil) ⇒ Object



646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
# File 'app/services/notification_service.rb', line 646

def pipeline_finished(pipeline, ref_status: nil, recipients: nil)
  # Must always check project configuration since recipients could be a list of emails
  # from the PipelinesEmailService integration.
  return if pipeline.project.emails_disabled?

  status = pipeline_notification_status(ref_status, pipeline)
  email_template = "pipeline_#{status}_email"

  return unless mailer.respond_to?(email_template)

  recipients ||= notifiable_users(
    [pipeline.user], :watch,
    custom_action: :"#{status}_pipeline",
    target: pipeline
  ).map do |user|
    user.notification_email_for(pipeline.project.group)
  end

  recipients.each do |recipient|
    mailer.public_send(email_template, pipeline, recipient).deliver_later
  end
end

#project_exported(project, current_user) ⇒ Object



634
635
636
637
638
# File 'app/services/notification_service.rb', line 634

def project_exported(project, current_user)
  return true unless notifiable?(current_user, :mention, project: project)

  mailer.project_was_exported_email(current_user, project).deliver_later
end

#project_not_exported(project, current_user, errors) ⇒ Object



640
641
642
643
644
# File 'app/services/notification_service.rb', line 640

def project_not_exported(project, current_user, errors)
  return true unless notifiable?(current_user, :mention, project: project)

  mailer.project_was_not_exported_email(current_user, project, errors).deliver_later
end

#project_was_moved(project, old_path_with_namespace) ⇒ Object



601
602
603
604
605
606
607
608
609
610
611
612
# File 'app/services/notification_service.rb', line 601

def project_was_moved(project, old_path_with_namespace)
  recipients = project_moved_recipients(project)
  recipients = notifiable_users(recipients, :custom, custom_action: :moved_project, project: project)

  recipients.each do |recipient|
    mailer.project_was_moved_email(
      project.id,
      recipient.id,
      old_path_with_namespace
    ).deliver_later
  end
end

#prometheus_alerts_fired(project, alerts) ⇒ Object



741
742
743
744
745
746
747
# File 'app/services/notification_service.rb', line 741

def prometheus_alerts_fired(project, alerts)
  return if project.emails_disabled?

  owners_and_maintainers_without_invites(project).to_a.product(alerts).each do |recipient, alert|
    mailer.prometheus_alert_fired_email(project, recipient.user, alert).deliver_later
  end
end

#push_to_merge_request(merge_request, current_user, new_commits: [], existing_commits: []) ⇒ Object



256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
# File 'app/services/notification_service.rb', line 256

def push_to_merge_request(merge_request, current_user, new_commits: [], existing_commits: [])
  total_new_commits_count = new_commits.count
  truncated_new_commits = new_commits.first(NEW_COMMIT_EMAIL_DISPLAY_LIMIT).map do |commit|
    { short_id: commit.short_id, title: commit.title }
  end

  # We don't need the list of all existing commits. We need the first, the
  # last, and the total number of existing commits only.
  total_existing_commits_count = existing_commits.count
  existing_commits = [existing_commits.first, existing_commits.last] if total_existing_commits_count > 2
  existing_commits = existing_commits.map do |commit|
    { short_id: commit.short_id, title: commit.title }
  end

  recipients = NotificationRecipients::BuildService.build_recipients(merge_request, current_user, action: "push_to")

  recipients.each do |recipient|
    mailer.send(
      :push_to_merge_request_email,
      recipient.user.id, merge_request.id, current_user.id, recipient.reason,
      new_commits: truncated_new_commits, total_new_commits_count: total_new_commits_count,
      existing_commits: existing_commits, total_existing_commits_count: total_existing_commits_count
    ).deliver_later
  end
end

#reassigned_issue(issue, current_user, previous_assignees = []) ⇒ Object

When we reassign an issue we should send an email to:

* issue old assignees if their notification level is not Disabled
* issue new assignees if their notification level is not Disabled
* users with custom level checked with "reassign issue"


212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
# File 'app/services/notification_service.rb', line 212

def reassigned_issue(issue, current_user, previous_assignees = [])
  recipients = NotificationRecipients::BuildService.build_recipients(
    issue,
    current_user,
    action: "reassign",
    previous_assignees: previous_assignees
  )

  previous_assignee_ids = previous_assignees.map(&:id)

  recipients.each do |recipient|
    mailer.send(
      :reassigned_issue_email,
      recipient.user.id,
      issue.id,
      previous_assignee_ids,
      current_user.id,
      recipient.reason
    ).deliver_later
  end
end

#reassigned_merge_request(merge_request, current_user, previous_assignees = []) ⇒ Object

When we reassign a merge_request we should send an email to:

* merge_request old assignees if their notification level is not Disabled
* merge_request new assignees if their notification level is not Disabled
* users with custom level checked with "reassign merge request"


324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
# File 'app/services/notification_service.rb', line 324

def reassigned_merge_request(merge_request, current_user, previous_assignees = [])
  recipients = NotificationRecipients::BuildService.build_recipients(
    merge_request,
    current_user,
    action: "reassign",
    previous_assignees: previous_assignees
  )

  previous_assignee_ids = previous_assignees.map(&:id)

  recipients.each do |recipient|
    mailer.reassigned_merge_request_email(
      recipient.user.id,
      merge_request.id,
      previous_assignee_ids,
      current_user.id,
      recipient.reason
    ).deliver_later
  end
end

#relabeled_issue(issue, added_labels, current_user) ⇒ Object

When we add labels to an issue we should send an email to:

* watchers of the issue's labels


238
239
240
# File 'app/services/notification_service.rb', line 238

def relabeled_issue(issue, added_labels, current_user)
  relabeled_resource_email(issue, added_labels, current_user, :relabeled_issue_email)
end

#relabeled_merge_request(merge_request, added_labels, current_user) ⇒ Object

When we add labels to a merge request we should send an email to:

* watchers of the mr's labels


388
389
390
# File 'app/services/notification_service.rb', line 388

def relabeled_merge_request(merge_request, added_labels, current_user)
  relabeled_resource_email(merge_request, added_labels, current_user, :relabeled_merge_request_email)
end

#remote_mirror_update_failed(remote_mirror) ⇒ Object



733
734
735
736
737
738
739
# File 'app/services/notification_service.rb', line 733

def remote_mirror_update_failed(remote_mirror)
  recipients = project_maintainers_recipients(remote_mirror, action: 'update_failed')

  recipients.each do |recipient|
    mailer.remote_mirror_update_failed_email(remote_mirror.id, recipient.user.id).deliver_later
  end
end

#removed_milestone(target, current_user) ⇒ Object



800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
# File 'app/services/notification_service.rb', line 800

def removed_milestone(target, current_user)
  method = case target
           when Issue
             :removed_milestone_issue_email
           when MergeRequest
             :removed_milestone_merge_request_email
           end

  recipients = NotificationRecipients::BuildService.build_recipients(
    target,
    current_user,
    action: 'removed_milestone'
  )

  recipients.each do |recipient|
    mailer.send(method, recipient.user.id, target.id, current_user.id).deliver_later
  end
end

#reopen_issue(issue, current_user) ⇒ Object



396
397
398
# File 'app/services/notification_service.rb', line 396

def reopen_issue(issue, current_user)
  reopen_resource_email(issue, current_user, :issue_status_changed_email, 'reopened')
end

#reopen_mr(merge_request, current_user) ⇒ Object



409
410
411
412
413
414
415
416
# File 'app/services/notification_service.rb', line 409

def reopen_mr(merge_request, current_user)
  reopen_resource_email(
    merge_request,
    current_user,
    :merge_request_status_email,
    'reopened'
  )
end

#repository_cleanup_failure(project, user, error) ⇒ Object



727
728
729
730
731
# File 'app/services/notification_service.rb', line 727

def repository_cleanup_failure(project, user, error)
  return if project.emails_disabled?

  mailer.send(:repository_cleanup_failure_email, project, user, error).deliver_later
end

#repository_cleanup_success(project, user) ⇒ Object



721
722
723
724
725
# File 'app/services/notification_service.rb', line 721

def repository_cleanup_success(project, user)
  return if project.emails_disabled?

  mailer.send(:repository_cleanup_success_email, project, user).deliver_later
end

#resolve_all_discussions(merge_request, current_user) ⇒ Object



418
419
420
421
422
423
424
425
426
427
# File 'app/services/notification_service.rb', line 418

def resolve_all_discussions(merge_request, current_user)
  recipients = NotificationRecipients::BuildService.build_recipients(
    merge_request,
    current_user,
    action: "resolve_all_discussions")

  recipients.each do |recipient|
    mailer.resolved_all_discussions_email(recipient.user.id, merge_request.id, current_user.id, recipient.reason).deliver_later
  end
end

#resource_access_tokens_about_to_expire(bot_user, token_names) ⇒ Object



78
79
80
81
82
83
84
85
86
87
88
89
# File 'app/services/notification_service.rb', line 78

def resource_access_tokens_about_to_expire(bot_user, token_names)
  recipients = bot_user.resource_bot_owners.select { |owner| owner.can?(:receive_notifications) }
  resource = bot_user.resource_bot_resource

  recipients.each do |recipient|
    mailer.resource_access_tokens_about_to_expire_email(
      recipient,
      resource,
      token_names
    ).deliver_later
  end
end

#review_requested_of_merge_request(merge_request, current_user, reviewer) ⇒ Object



372
373
374
375
376
377
378
379
380
381
382
# File 'app/services/notification_service.rb', line 372

def review_requested_of_merge_request(merge_request, current_user, reviewer)
  recipients = NotificationRecipients::BuildService.build_requested_review_recipients(merge_request, current_user, reviewer)

  deliver_option = review_request_deliver_options(merge_request.project, reviewer)

  recipients.each do |recipient|
    mailer
      .request_review_merge_request_email(recipient.user.id, merge_request.id, current_user.id, recipient.reason)
      .deliver_later(deliver_option)
  end
end

#send_new_note_notifications(note) ⇒ Object



448
449
450
451
452
453
454
455
# File 'app/services/notification_service.rb', line 448

def send_new_note_notifications(note)
  notify_method = "note_#{note.noteable_ability_name}_email".to_sym

  recipients = NotificationRecipients::BuildService.build_new_note_recipients(note)
  recipients.each do |recipient|
    mailer.send(notify_method, recipient.user.id, note.id, recipient.reason).deliver_later
  end
end

#send_new_release_notifications(release) ⇒ Object

Notify users when a new release is created



477
478
479
480
481
482
483
484
485
486
487
488
489
490
# File 'app/services/notification_service.rb', line 477

def send_new_release_notifications(release)
  unless release.author&.can_trigger_notifications?
    warn_skipping_notifications(release.author, release)
    return false
  end

  recipients = NotificationRecipients::BuildService.build_recipients(release,
    release.author,
    action: "new")

  recipients.each do |recipient|
    mailer.new_release_email(recipient.user.id, release, recipient.reason).deliver_later
  end
end

#send_service_desk_notification(note) ⇒ Object



457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
# File 'app/services/notification_service.rb', line 457

def send_service_desk_notification(note)
  return unless note.noteable_type == 'Issue'
  return if note.confidential
  return unless note.project.service_desk_enabled?

  issue = note.noteable
  recipients = issue.email_participants_emails

  return unless recipients.any?

  support_bot = Users::Internal.support_bot
  recipients.delete(issue.external_author) if note.author == support_bot

  recipients.each do |recipient|
    mailer.service_desk_new_note_email(issue.id, note.id, recipient).deliver_later
    Gitlab::Metrics::BackgroundTransaction.current&.add_event(:service_desk_new_note_email)
  end
end

#ssh_key_expired(user, fingerprints) ⇒ Object

Notify the user when at least one of their ssh key has expired today



135
136
137
138
139
# File 'app/services/notification_service.rb', line 135

def ssh_key_expired(user, fingerprints)
  return unless user.can?(:receive_notifications)

  mailer.ssh_key_expired_email(user, fingerprints).deliver_later
end

#ssh_key_expiring_soon(user, fingerprints) ⇒ Object

Notify the user when at least one of their ssh key is expiring soon



142
143
144
145
146
# File 'app/services/notification_service.rb', line 142

def ssh_key_expiring_soon(user, fingerprints)
  return unless user.can?(:receive_notifications)

  mailer.ssh_key_expiring_soon_email(user, fingerprints).deliver_later
end

#two_factor_otp_attempt_failed(user, ip) ⇒ Object

Notify a user when a wrong 2FA OTP has been entered to try to sign in to their account



158
159
160
161
162
# File 'app/services/notification_service.rb', line 158

def two_factor_otp_attempt_failed(user, ip)
  return unless user.can?(:receive_notifications)

  mailer.two_factor_otp_attempt_failed_email(user, ip).deliver_later
end

#unapprove_mr(merge_request, current_user) ⇒ Object



790
791
792
# File 'app/services/notification_service.rb', line 790

def unapprove_mr(merge_request, current_user)
  unapprove_mr_email(merge_request, merge_request.target_project, current_user)
end

#unknown_sign_in(user, ip, time) ⇒ Object

Notify a user when a previously unknown IP or device is used to sign in to their account



150
151
152
153
154
# File 'app/services/notification_service.rb', line 150

def (user, ip, time)
  return unless user.can?(:receive_notifications)

  mailer.(user, ip, time).deliver_later
end

#update_group_member(group_member) ⇒ Object



589
590
591
592
593
# File 'app/services/notification_service.rb', line 589

def update_group_member(group_member)
  return true unless group_member.notifiable?(:mention)

  mailer.member_access_granted_email(group_member.real_source_type, group_member.id).deliver_later
end

#update_project_member(project_member) ⇒ Object



558
559
560
561
562
# File 'app/services/notification_service.rb', line 558

def update_project_member(project_member)
  return true unless project_member.notifiable?(:mention)

  mailer.member_access_granted_email(project_member.real_source_type, project_member.id).deliver_later
end

#updated_group_member_expiration(group_member) ⇒ Object



595
596
597
598
599
# File 'app/services/notification_service.rb', line 595

def updated_group_member_expiration(group_member)
  return true unless group_member.notifiable?(:mention)

  mailer.member_expiration_date_updated_email(group_member.real_source_type, group_member.id).deliver_later
end

#user_admin_rejection(name, email) ⇒ Object



502
503
504
# File 'app/services/notification_service.rb', line 502

def user_admin_rejection(name, email)
  mailer.user_admin_rejection_email(name, email).deliver_later
end

#user_deactivated(name, email) ⇒ Object



506
507
508
# File 'app/services/notification_service.rb', line 506

def user_deactivated(name, email)
  mailer.user_deactivated_email(name, email).deliver_later
end