From decd147a7c8199370a93a097d4758bc88063dc70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marius=20B=C4=82LTEANU?= Date: Wed, 20 Mar 2024 00:53:04 +0200 Subject: [PATCH] WIP --- app/models/mailer.rb | 18 ++-- .../notification_recipients/build_service.rb | 30 +++++++ .../notification_recipients/builder/base.rb | 82 +++++++++++++++++++ .../notification_recipients/builder/issue.rb | 55 +++++++++++++ .../builder/journal.rb | 33 ++++++++ .../notification_recipients/notified_user.rb | 53 ++++++++++++ 6 files changed, 262 insertions(+), 9 deletions(-) create mode 100644 app/services/notification_recipients/build_service.rb create mode 100644 app/services/notification_recipients/builder/base.rb create mode 100644 app/services/notification_recipients/builder/issue.rb create mode 100644 app/services/notification_recipients/builder/journal.rb create mode 100644 app/services/notification_recipients/notified_user.rb diff --git a/app/models/mailer.rb b/app/models/mailer.rb index 716482ec3..8b481817d 100644 --- a/app/models/mailer.rb +++ b/app/models/mailer.rb @@ -103,9 +103,11 @@ class Mailer < ActionMailer::Base # Example: # Mailer.deliver_issue_add(issue) def self.deliver_issue_add(issue) - users = issue.notified_users | issue.notified_watchers | issue.notified_mentions - users.each do |user| - issue_add(user, issue).deliver_later + # users = issue.notified_users | issue.notified_watchers | issue.notified_mentions + recipients = ::NotificationRecipients::BuildService::issue_add(issue) + + recipients.each do |r| + issue_add(r.user, issue).deliver_later end end @@ -139,12 +141,10 @@ class Mailer < ActionMailer::Base # Example: # Mailer.deliver_issue_edit(journal) def self.deliver_issue_edit(journal) - users = journal.notified_users | journal.notified_watchers | journal.notified_mentions | journal.journalized.notified_mentions - users.select! do |user| - journal.notes? || journal.visible_details(user).any? - end - users.each do |user| - issue_edit(user, journal).deliver_later + recipients = ::NotificationRecipients::BuildService::issue_edit(journal) + + recipients.each do |r| + issue_edit(r.user, journal).deliver_later end end diff --git a/app/services/notification_recipients/build_service.rb b/app/services/notification_recipients/build_service.rb new file mode 100644 index 000000000..1baaeac9b --- /dev/null +++ b/app/services/notification_recipients/build_service.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true + +# Redmine - project management software +# Copyright (C) 2006- Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module NotificationRecipients + class BuildService + def self.issue_add(issue) + NotificationRecipients::Builder::Issue.new(issue).notified_recipients + end + + def self.issue_edit(journal) + NotificationRecipients::Builder::Journal.new(journal).notified_recipients + end + end +end diff --git a/app/services/notification_recipients/builder/base.rb b/app/services/notification_recipients/builder/base.rb new file mode 100644 index 000000000..95d8475cb --- /dev/null +++ b/app/services/notification_recipients/builder/base.rb @@ -0,0 +1,82 @@ +module NotificationRecipients + module Builder + class Base + attr_reader :target + + def initialize(target) + @target = target + end + + def notified_recipients + build_notified_recipients + filter! + reorder! + + self.recipients.freeze + end + + def notified_users + build_notified_users + filter! + reorder! + + self.recipients.freeze + end + + def notified_mentions + build_notified_mentions + filter! + + self.recipients.freeze + end + + def notified_watchers + add_watchers(target) + + self.recipients.freeze + end + + private + + def recipients + @recipients ||= [] + end + + def build_notified_watchers + add_watchers(target) + end + + def build_notified_mentions + add_mentions(target) + end + + def add_mentions(target) + users = target.notified_mentions + + users.each do |user| + add_recipient(user, NotifiedUser::MENTIONED) + end + end + + def add_watchers(target) + users = target.notified_watchers + + users.each do |user| + add_recipient(user, NotifiedUser::WATCHER) + end + end + + def add_recipient(user, reason) + recipients.push(NotifiedUser.new(user, reason)) + end + + def filter! + end + + def reorder! + self.recipients.sort_by! { |r| NotifiedUser::priority(r.reason) } + self.recipients.uniq!(&:user) + end + end + end +end diff --git a/app/services/notification_recipients/builder/issue.rb b/app/services/notification_recipients/builder/issue.rb new file mode 100644 index 000000000..da8fef373 --- /dev/null +++ b/app/services/notification_recipients/builder/issue.rb @@ -0,0 +1,55 @@ +module NotificationRecipients + module Builder + class Issue < Base + + private + + def build_notified_recipients + build_notified_users + build_notified_mentions + build_notified_watchers + end + + def build_notified_users + add_involved_users + add_subscribed_users + add_high_priority_users + end + + def add_involved_users + notified = [target.author, target.assigned_to, target.previous_assignee].compact.uniq + notified = notified.map {|n| n.is_a?(Group) ? n.users : n}.flatten + notified.uniq! + notified = notified.select {|u| u.active? && u.notify_about?(target)} + + # Remove users that can not view the issue + notified.reject! {|user| !target.visible?(user)} + + notified.each do |user| + add_recipient(user, NotifiedUser::INVOLVED) + end + end + + def add_subscribed_users + notified = target.project.notified_users.to_a + + # Remove users that can not view the issue + notified.reject! {|user| !target.visible?(user)} + + notified.each do |user| + add_recipient(user, NotifiedUser::SUBSCRIBED) + end + end + + def add_high_priority_users + if target.priority.high? + project.users.preload(:preference).select(&:notify_about_high_priority_issues?).each do |user| + next unless target.visible?(user) + + add_recipient(user, NotifiedUser::HIGH_PRIORITY) + end + end + end + end + end +end diff --git a/app/services/notification_recipients/builder/journal.rb b/app/services/notification_recipients/builder/journal.rb new file mode 100644 index 000000000..0664c8c8d --- /dev/null +++ b/app/services/notification_recipients/builder/journal.rb @@ -0,0 +1,33 @@ +module NotificationRecipients + module Builder + class Journal < Base + private + + def build_notified_users + recipients.concat(::NotificationRecipients::Builder::Issue.new(target.journalized).notified_users) + end + + def build_notified_recipients + build_notified_users + build_notified_watchers + build_notified_mentions + end + + def build_notified_watchers + add_watchers(target.journalized) + end + + def build_notified_mentions + add_mentions(target) + add_mentions(target.journalized) + end + + def filter! + if target.private_notes? + self.recipients.select! {|r | r.user.allowed_to?(:view_private_notes, target.journalized.project)} + self.recipients.select! {|r | target.notes? || target.visible_details(r.user).any? } + end + end + end + end +end diff --git a/app/services/notification_recipients/notified_user.rb b/app/services/notification_recipients/notified_user.rb new file mode 100644 index 000000000..d1706f9d9 --- /dev/null +++ b/app/services/notification_recipients/notified_user.rb @@ -0,0 +1,53 @@ +# frozen_string_literal: true + +# Redmine - project management software +# Copyright (C) 2006-2023 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module NotificationRecipients + class NotifiedUser + INVOLVED = 'involved' + MENTIONED = 'mentioned' + WATCHER = 'watcher' + SUBSCRIBED = 'subscribed' + ADMIN = 'admin' + + REASON_PRIORITY = [ + INVOLVED, + MENTIONED, + WATCHER, + SUBSCRIBED, + ADMIN + ].freeze + + attr_reader :user, :reason + + def initialize(user, reason) + @user = user + @reason = reason + end + + def self.reorder_by_priority(users) + users = users.sort_by { |r| priority(r.notification_reason) } + users.uniq! + users + end + + def self.priority(reason) + REASON_PRIORITY.index(reason) || REASON_PRIORITY.length + 1 + end + end +end -- 2.39.3 (Apple Git-145)