From 1d2ed91e89478f65ccbc9eecdfbed382fce46132 Mon Sep 17 00:00:00 2001 From: Rosa Gutierrez Date: Wed, 21 Jan 2026 19:07:04 +0100 Subject: [PATCH] Extract payload building into dedicated classes Separates notification payload construction from push delivery by introducing DefaultPayload, EventPayload, and MentionPayload classes that encapsulate the title, body, and URL generation for each notification type. Co-Authored-By: Claude Opus 4.5 --- app/models/notification/default_payload.rb | 41 ++++++++++ app/models/notification/event_payload.rb | 55 +++++++++++++ app/models/notification/mention_payload.rb | 20 +++++ app/models/notification/push.rb | 95 +--------------------- 4 files changed, 119 insertions(+), 92 deletions(-) create mode 100644 app/models/notification/default_payload.rb create mode 100644 app/models/notification/event_payload.rb create mode 100644 app/models/notification/mention_payload.rb diff --git a/app/models/notification/default_payload.rb b/app/models/notification/default_payload.rb new file mode 100644 index 000000000..acffb1365 --- /dev/null +++ b/app/models/notification/default_payload.rb @@ -0,0 +1,41 @@ +class Notification::DefaultPayload + attr_reader :notification + + delegate :card, to: :notification + + def initialize(notification) + @notification = notification + end + + def to_h + { title: title, body: body, url: url } + end + + private + def title + "New notification" + end + + def body + "You have a new notification" + end + + def url + notifications_url + end + + def card_url(card) + Rails.application.routes.url_helpers.card_url(card, **url_options) + end + + def notifications_url + Rails.application.routes.url_helpers.notifications_url(**url_options) + end + + def url_options + base_options = Rails.application.routes.default_url_options.presence || + Rails.application.config.action_mailer.default_url_options || + {} + base_options.merge(script_name: notification.account.slug) + end +end diff --git a/app/models/notification/event_payload.rb b/app/models/notification/event_payload.rb new file mode 100644 index 000000000..3cc02dc34 --- /dev/null +++ b/app/models/notification/event_payload.rb @@ -0,0 +1,55 @@ +class Notification::EventPayload < Notification::DefaultPayload + include ExcerptHelper + + private + def title + case event.action + when "comment_created" + "RE: #{card_title}" + else + card_title + end + end + + def body + case event.action + when "comment_created" + format_excerpt(event.eventable.body, length: 200) + when "card_assigned" + "Assigned to you by #{event.creator.name}" + when "card_published" + "Added by #{event.creator.name}" + when "card_closed" + card.closure ? "Moved to Done by #{event.creator.name}" : "Closed by #{event.creator.name}" + when "card_reopened" + "Reopened by #{event.creator.name}" + else + event.creator.name + end + end + + def url + case event.action + when "comment_created" + card_url_with_comment_anchor(event.eventable) + else + card_url(card) + end + end + + def event + notification.source + end + + def card_title + card.title.presence || "Card #{card.number}" + end + + def card_url_with_comment_anchor(comment) + Rails.application.routes.url_helpers.card_url( + comment.card, + anchor: ActionView::RecordIdentifier.dom_id(comment), + **url_options + ) + end +end diff --git a/app/models/notification/mention_payload.rb b/app/models/notification/mention_payload.rb new file mode 100644 index 000000000..4649f38f3 --- /dev/null +++ b/app/models/notification/mention_payload.rb @@ -0,0 +1,20 @@ +class Notification::MentionPayload < Notification::DefaultPayload + include ExcerptHelper + + private + def title + "#{mention.mentioner.first_name} mentioned you" + end + + def body + format_excerpt(mention.source.mentionable_content, length: 200) + end + + def url + card_url(card) + end + + def mention + notification.source + end +end diff --git a/app/models/notification/push.rb b/app/models/notification/push.rb index c94f121f1..cf2adce44 100644 --- a/app/models/notification/push.rb +++ b/app/models/notification/push.rb @@ -1,6 +1,4 @@ class Notification::Push - include ExcerptHelper - attr_reader :notification delegate :card, to: :notification @@ -27,98 +25,11 @@ class Notification::Push def build_payload case notification.source_type when "Event" - build_event_payload + Notification::EventPayload.new(notification).to_h when "Mention" - build_mention_payload + Notification::MentionPayload.new(notification).to_h else - build_default_payload + Notification::DefaultPayload.new(notification).to_h end end - - def build_event_payload - event = notification.source - - base_payload = { - title: card_notification_title(card), - url: card_url(card) - } - - case event.action - when "comment_created" - base_payload.merge( - title: "RE: #{base_payload[:title]}", - body: comment_notification_body(event), - url: card_url_with_comment_anchor(event.eventable) - ) - when "card_assigned" - base_payload.merge( - body: "Assigned to you by #{event.creator.name}" - ) - when "card_published" - base_payload.merge( - body: "Added by #{event.creator.name}" - ) - when "card_closed" - base_payload.merge( - body: card.closure ? "Moved to Done by #{event.creator.name}" : "Closed by #{event.creator.name}" - ) - when "card_reopened" - base_payload.merge( - body: "Reopened by #{event.creator.name}" - ) - else - base_payload.merge( - body: event.creator.name - ) - end - end - - def build_mention_payload - mention = notification.source - - { - title: "#{mention.mentioner.first_name} mentioned you", - body: format_excerpt(mention.source.mentionable_content, length: 200), - url: card_url(card) - } - end - - def build_default_payload - { - title: "New notification", - body: "You have a new notification", - url: notifications_url - } - end - - def card_notification_title(card) - card.title.presence || "Card #{card.number}" - end - - def comment_notification_body(event) - format_excerpt(event.eventable.body, length: 200) - end - - def card_url(card) - Rails.application.routes.url_helpers.card_url(card, **url_options) - end - - def notifications_url - Rails.application.routes.url_helpers.notifications_url(**url_options) - end - - def card_url_with_comment_anchor(comment) - Rails.application.routes.url_helpers.card_url( - comment.card, - anchor: ActionView::RecordIdentifier.dom_id(comment), - **url_options - ) - end - - def url_options - base_options = Rails.application.routes.default_url_options.presence || - Rails.application.config.action_mailer.default_url_options || - {} - base_options.merge(script_name: notification.account.slug) - end end