From 637621518a254ff1434f301d5a460d4391471a30 Mon Sep 17 00:00:00 2001 From: Fernando Olivares Date: Wed, 5 Nov 2025 19:57:33 -0600 Subject: [PATCH 01/10] Split event_action_sentence into *_tag and *_text --- app/helpers/events_helper.rb | 142 +++++++++++++++++++---------------- 1 file changed, 79 insertions(+), 63 deletions(-) diff --git a/app/helpers/events_helper.rb b/app/helpers/events_helper.rb index 992463740..d9ad27613 100644 --- a/app/helpers/events_helper.rb +++ b/app/helpers/events_helper.rb @@ -55,19 +55,21 @@ module EventsHelper tag.div class: "events__time-block", style: "grid-area: #{row}/#{col}", & end - def event_action_sentence(event) - if event.action.comment_created? - comment_event_action_sentence(event) - else - card_event_action_sentence(event) - end + def event_action_sentence_tag(event) + creator = event_creator_name_tag(event) + card = event.action.comment_created? ? event.eventable.card : event.eventable + card_title = event_card_title(card) + event_action_sentence(creator, card_title, event).html_safe end - def comment_event_action_sentence(event) - "#{event_creator_name(event)} commented on #{event_card_title(event.eventable.card)}".html_safe + def event_action_sentence_text(event) + creator = event_creator_name_text(event) + card = event.action.comment_created? ? event.eventable.card : event.eventable + card_title = card.title + event_action_sentence(creator, card_title, event) end - def event_creator_name(event) + def event_creator_name_tag(event) tag.span data: { creator_id: event.creator.id } do safe_join([ tag.span("You", data: { only_visible_to_you: true }), @@ -76,63 +78,77 @@ module EventsHelper end end - def card_event_action_sentence(event) - card = event.eventable - - case event.action - when "card_assigned" - if event.assignees.include?(Current.user) - "#{event_creator_name(event)} will handle #{event_card_title(card)}" - else - "#{event_creator_name(event)} assigned #{h event.assignees.pluck(:name).to_sentence} to #{event_card_title(card)}" - end - when "card_unassigned" - "#{event_creator_name(event)} unassigned #{h(event.assignees.include?(Current.user) ? "yourself" : event.assignees.pluck(:name).to_sentence)} from #{event_card_title(card)}" - when "card_published" - "#{event_creator_name(event)} added #{event_card_title(card)}" - when "card_closed" - "#{event_creator_name(event)} moved #{event_card_title(card)} to “Done”" - when "card_reopened" - "#{event_creator_name(event)} reopened #{event_card_title(card)}" - when "card_postponed" - "#{event_creator_name(event)} moved #{event_card_title(card)} to “Not Now”" - when "card_auto_postponed" - "#{event_card_title(card)} was closed as “Not Now” due to inactivity" - when "card_resumed" - "#{event_creator_name(event)} resumed #{event_card_title(card)}" - when "card_title_changed" - "#{event_creator_name(event)} renamed #{event_card_title(card)} (was: “#{h event.particulars.dig('particulars', 'old_title')}”)" - when "card_board_changed", "card_collection_changed" - "#{event_creator_name(event)} moved #{event_card_title(card)} to “#{h (event.particulars.dig('particulars', 'new_board') || event.particulars.dig('particulars', 'new_collection'))}”" - when "card_triaged" - "#{event_creator_name(event)} moved #{event_card_title(card)} to “#{h event.particulars.dig('particulars', 'column')}”" - when "card_sent_back_to_triage" - "#{event_creator_name(event)} moved #{event_card_title(card)} back to “Maybe?”" - end&.html_safe + def event_creator_name_text(event) + event.creator == Current.user ? "You" : h(event.creator.name) end - def event_card_title(card) - tag.span card.title, class: "txt-underline" - end - - def event_due_date(event) - event.particulars.dig("particulars", "due_date").to_date.strftime("%B %-d") - end - - def event_action_icon(event) - case event.action - when "card_assigned" - "assigned" - when "card_unassigned" - "minus" - when "comment_created" - "comment" - when "card_title_changed" - "rename" - when "card_board_changed" - "move" + def event_action_sentence(event_creator, event_card_title, event) + if event.action.comment_created? + comment_event_action_sentence(event_creator, event_card_title, event) else - "person" + card_event_action_sentence(event_creator, event_card_title, event) end end + + def comment_event_action_sentence(event_creator, event_card_title, event) + "#{event_creator} commented on #{event_card_title}" + end + + def card_event_action_sentence(event_creator, event_card_title, event) + case event.action + when "card_assigned" + if event.assignees.include?(Current.user) + "#{event_creator} will handle #{event_card_title}" + else + "#{event_creator} assigned #{h event.assignees.pluck(:name).to_sentence} to #{event_card_title}" + end + when "card_unassigned" + "#{event_creator} unassigned #{h(event.assignees.include?(Current.user) ? "yourself" : event.assignees.pluck(:name).to_sentence)} from #{event_card_title}" + when "card_published" + "#{event_creator} added #{event_card_title}" + when "card_closed" + "#{event_creator} moved #{event_card_title} to “Done”" + when "card_reopened" + "#{event_creator} reopened #{event_card_title}" + when "card_postponed" + "#{event_creator} moved #{event_card_title} to “Not Now”" + when "card_auto_postponed" + "#{event_card_title} was closed as “Not Now” due to inactivity" + when "card_resumed" + "#{event_creator} resumed #{event_card_title}" + when "card_title_changed" + "#{event_creator} renamed #{event_card_title} (was: “#{h event.particulars.dig('particulars', 'old_title')}”)" + when "card_board_changed", "card_collection_changed" + "#{event_creator} moved #{event_card_title} to “#{h (event.particulars.dig('particulars', 'new_board') || event.particulars.dig('particulars', 'new_collection'))}”" + when "card_triaged" + "#{event_creator} moved #{event_card_title} to “#{h event.particulars.dig('particulars', 'column')}”" + when "card_sent_back_to_triage" + "#{event_creator} moved #{event_card_title} back to “Maybe?”" + end + end + + def event_card_title(card) + tag.span card.title, class: "txt-underline" + end + + def event_due_date(event) + event.particulars.dig("particulars", "due_date").to_date.strftime("%B %-d") + end + + def event_action_icon(event) + case event.action + when "card_assigned" + "assigned" + when "card_unassigned" + "minus" + when "comment_created" + "comment" + when "card_title_changed" + "rename" + when "card_board_changed" + "move" + else + "person" + end + end end From de0ae43dcdf5309b3d4de255aded3096af087288 Mon Sep 17 00:00:00 2001 From: Fernando Olivares Date: Wed, 5 Nov 2025 19:58:35 -0600 Subject: [PATCH 02/10] Use event action sentence text in webhook --- app/views/webhooks/event.html.erb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/webhooks/event.html.erb b/app/views/webhooks/event.html.erb index 91500a17b..a9835c21e 100644 --- a/app/views/webhooks/event.html.erb +++ b/app/views/webhooks/event.html.erb @@ -1,4 +1,4 @@ -<%= event_action_sentence(@event) %> +<%= event_action_sentence_text(@event) %> <% if @event.eventable %> <%= link_to "↗︎", polymorphic_url(@event.eventable) %> <% end %> From 6aefab2396a74adabaf3f62372fe3309915ca891 Mon Sep 17 00:00:00 2001 From: Fernando Olivares Date: Wed, 5 Nov 2025 19:58:42 -0600 Subject: [PATCH 03/10] Use event action sentence tag in layout --- app/views/events/event/_layout.html.erb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/events/event/_layout.html.erb b/app/views/events/event/_layout.html.erb index 0fc767862..1cd1e6831 100644 --- a/app/views/events/event/_layout.html.erb +++ b/app/views/events/event/_layout.html.erb @@ -32,7 +32,7 @@
- <%= event_action_sentence(event) %> + <%= event_action_sentence_tag(event) %> <%= yield %> From c926d7ad6c145974c4a95e7715663d7bd2f2ca87 Mon Sep 17 00:00:00 2001 From: Jorge Manrubia Date: Thu, 6 Nov 2025 10:56:07 +0100 Subject: [PATCH 04/10] Extract description object to remove the helper salad Lots of repetition with the helpers and params --- app/helpers/events_helper.rb | 106 +++-------------------- app/models/event.rb | 4 + app/models/event/description.rb | 108 ++++++++++++++++++++++++ app/views/events/event/_layout.html.erb | 2 +- app/views/webhooks/event.html.erb | 2 +- 5 files changed, 127 insertions(+), 95 deletions(-) create mode 100644 app/models/event/description.rb diff --git a/app/helpers/events_helper.rb b/app/helpers/events_helper.rb index d9ad27613..94e6990d2 100644 --- a/app/helpers/events_helper.rb +++ b/app/helpers/events_helper.rb @@ -55,100 +55,20 @@ module EventsHelper tag.div class: "events__time-block", style: "grid-area: #{row}/#{col}", & end - def event_action_sentence_tag(event) - creator = event_creator_name_tag(event) - card = event.action.comment_created? ? event.eventable.card : event.eventable - card_title = event_card_title(card) - event_action_sentence(creator, card_title, event).html_safe - end - - def event_action_sentence_text(event) - creator = event_creator_name_text(event) - card = event.action.comment_created? ? event.eventable.card : event.eventable - card_title = card.title - event_action_sentence(creator, card_title, event) - end - - def event_creator_name_tag(event) - tag.span data: { creator_id: event.creator.id } do - safe_join([ - tag.span("You", data: { only_visible_to_you: true }), - tag.span(h(event.creator.name), data: { only_visible_to_others: true }) - ]) - end - end - - def event_creator_name_text(event) - event.creator == Current.user ? "You" : h(event.creator.name) - end - - def event_action_sentence(event_creator, event_card_title, event) - if event.action.comment_created? - comment_event_action_sentence(event_creator, event_card_title, event) + def event_action_icon(event) + case event.action + when "card_assigned" + "assigned" + when "card_unassigned" + "minus" + when "comment_created" + "comment" + when "card_title_changed" + "rename" + when "card_board_changed" + "move" else - card_event_action_sentence(event_creator, event_card_title, event) + "person" end end - - def comment_event_action_sentence(event_creator, event_card_title, event) - "#{event_creator} commented on #{event_card_title}" - end - - def card_event_action_sentence(event_creator, event_card_title, event) - case event.action - when "card_assigned" - if event.assignees.include?(Current.user) - "#{event_creator} will handle #{event_card_title}" - else - "#{event_creator} assigned #{h event.assignees.pluck(:name).to_sentence} to #{event_card_title}" - end - when "card_unassigned" - "#{event_creator} unassigned #{h(event.assignees.include?(Current.user) ? "yourself" : event.assignees.pluck(:name).to_sentence)} from #{event_card_title}" - when "card_published" - "#{event_creator} added #{event_card_title}" - when "card_closed" - "#{event_creator} moved #{event_card_title} to “Done”" - when "card_reopened" - "#{event_creator} reopened #{event_card_title}" - when "card_postponed" - "#{event_creator} moved #{event_card_title} to “Not Now”" - when "card_auto_postponed" - "#{event_card_title} was closed as “Not Now” due to inactivity" - when "card_resumed" - "#{event_creator} resumed #{event_card_title}" - when "card_title_changed" - "#{event_creator} renamed #{event_card_title} (was: “#{h event.particulars.dig('particulars', 'old_title')}”)" - when "card_board_changed", "card_collection_changed" - "#{event_creator} moved #{event_card_title} to “#{h (event.particulars.dig('particulars', 'new_board') || event.particulars.dig('particulars', 'new_collection'))}”" - when "card_triaged" - "#{event_creator} moved #{event_card_title} to “#{h event.particulars.dig('particulars', 'column')}”" - when "card_sent_back_to_triage" - "#{event_creator} moved #{event_card_title} back to “Maybe?”" - end - end - - def event_card_title(card) - tag.span card.title, class: "txt-underline" - end - - def event_due_date(event) - event.particulars.dig("particulars", "due_date").to_date.strftime("%B %-d") - end - - def event_action_icon(event) - case event.action - when "card_assigned" - "assigned" - when "card_unassigned" - "minus" - when "comment_created" - "comment" - when "card_title_changed" - "rename" - when "card_board_changed" - "move" - else - "person" - end - end end diff --git a/app/models/event.rb b/app/models/event.rb index ad77d3492..74a3bb20f 100644 --- a/app/models/event.rb +++ b/app/models/event.rb @@ -22,6 +22,10 @@ class Event < ApplicationRecord eventable end + def description_for(user) + Event::Description.new(self, user) + end + private def dispatch_webhooks Event::WebhookDispatchJob.perform_later(self) diff --git a/app/models/event/description.rb b/app/models/event/description.rb new file mode 100644 index 000000000..f743ce0e2 --- /dev/null +++ b/app/models/event/description.rb @@ -0,0 +1,108 @@ +class Event::Description + include ActionView::Helpers::TagHelper + include ERB::Util + + attr_reader :event, :user + + def initialize(event, user) + @event = event + @user = user + end + + def to_html + sentence(creator_tag, card_title_tag).html_safe + end + + def to_plain_text + sentence(creator_text, card.title) + end + + private + def card + @card ||= event.action.comment_created? ? event.eventable.card : event.eventable + end + + def creator_tag + tag.span data: { creator_id: event.creator.id } do + tag.span("You", data: { only_visible_to_you: true }) + + tag.span(h(event.creator.name), data: { only_visible_to_others: true }) + end + end + + def creator_text + event.creator == user ? "You" : h(event.creator.name) + end + + def card_title_tag + tag.span card.title, class: "txt-underline" + end + + def sentence(creator, card_title) + if event.action.comment_created? + comment_sentence(creator, card_title) + else + action_sentence(creator, card_title) + end + end + + def comment_sentence(creator, card_title) + "#{creator} commented on #{card_title}" + end + + def action_sentence(creator, card_title) + case event.action + when "card_assigned" + assigned_sentence(creator, card_title) + when "card_unassigned" + unassigned_sentence(creator, card_title) + when "card_published" + "#{creator} added #{card_title}" + when "card_closed" + %(#{creator} moved #{card_title} to "Done") + when "card_reopened" + "#{creator} reopened #{card_title}" + when "card_postponed" + %(#{creator} moved #{card_title} to "Not Now") + when "card_auto_postponed" + %(#{card_title} was closed as "Not Now" due to inactivity) + when "card_resumed" + "#{creator} resumed #{card_title}" + when "card_title_changed" + renamed_sentence(creator, card_title) + when "card_board_changed", "card_collection_changed" + moved_sentence(creator, card_title) + when "card_triaged" + triaged_sentence(creator, card_title) + when "card_sent_back_to_triage" + %(#{creator} moved #{card_title} back to "Maybe?") + end + end + + def assigned_sentence(creator, card_title) + if event.assignees.include?(user) + "#{creator} will handle #{card_title}" + else + "#{creator} assigned #{h event.assignees.pluck(:name).to_sentence} to #{card_title}" + end + end + + def unassigned_sentence(creator, card_title) + assignees_text = event.assignees.include?(user) ? "yourself" : event.assignees.pluck(:name).to_sentence + "#{creator} unassigned #{h(assignees_text)} from #{card_title}" + end + + def renamed_sentence(creator, card_title) + old_title = event.particulars.dig("particulars", "old_title") + %(#{creator} renamed #{card_title} (was: "#{h old_title}")) + end + + def moved_sentence(creator, card_title) + new_location = event.particulars.dig("particulars", "new_board") || event.particulars.dig("particulars", "new_collection") + %(#{creator} moved #{card_title} to "#{h new_location}") + end + + def triaged_sentence(creator, card_title) + column = event.particulars.dig("particulars", "column") + %(#{creator} moved #{card_title} to "#{h column}") + end +end diff --git a/app/views/events/event/_layout.html.erb b/app/views/events/event/_layout.html.erb index 1cd1e6831..0cd0fee07 100644 --- a/app/views/events/event/_layout.html.erb +++ b/app/views/events/event/_layout.html.erb @@ -32,7 +32,7 @@
- <%= event_action_sentence_tag(event) %> + <%= event.description_for(Current.user).to_html %> <%= yield %> diff --git a/app/views/webhooks/event.html.erb b/app/views/webhooks/event.html.erb index a9835c21e..f2920e8d0 100644 --- a/app/views/webhooks/event.html.erb +++ b/app/views/webhooks/event.html.erb @@ -1,4 +1,4 @@ -<%= event_action_sentence_text(@event) %> +<%= @event.description_for(Current.user).to_plain_text %> <% if @event.eventable %> <%= link_to "↗︎", polymorphic_url(@event.eventable) %> <% end %> From f5dfcd461c538bf66838e7bc63180e28808b3261 Mon Sep 17 00:00:00 2001 From: Jorge Manrubia Date: Thu, 6 Nov 2025 11:01:21 +0100 Subject: [PATCH 05/10] Rename method --- app/models/event/description.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/models/event/description.rb b/app/models/event/description.rb index f743ce0e2..d474b5e73 100644 --- a/app/models/event/description.rb +++ b/app/models/event/description.rb @@ -10,11 +10,11 @@ class Event::Description end def to_html - sentence(creator_tag, card_title_tag).html_safe + to_sentence(creator_tag, card_title_tag).html_safe end def to_plain_text - sentence(creator_text, card.title) + to_sentence(creator_text, card.title) end private @@ -37,7 +37,7 @@ class Event::Description tag.span card.title, class: "txt-underline" end - def sentence(creator, card_title) + def to_sentence(creator, card_title) if event.action.comment_created? comment_sentence(creator, card_title) else From e4cb5579f05c6b4b55d9a0fa30894ae139be37c4 Mon Sep 17 00:00:00 2001 From: Jorge Manrubia Date: Thu, 6 Nov 2025 11:02:20 +0100 Subject: [PATCH 06/10] Order methods --- app/models/event/description.rb | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/app/models/event/description.rb b/app/models/event/description.rb index d474b5e73..ab0305d96 100644 --- a/app/models/event/description.rb +++ b/app/models/event/description.rb @@ -18,8 +18,12 @@ class Event::Description end private - def card - @card ||= event.action.comment_created? ? event.eventable.card : event.eventable + def to_sentence(creator, card_title) + if event.action.comment_created? + comment_sentence(creator, card_title) + else + action_sentence(creator, card_title) + end end def creator_tag @@ -29,20 +33,16 @@ class Event::Description end end - def creator_text - event.creator == user ? "You" : h(event.creator.name) - end - def card_title_tag tag.span card.title, class: "txt-underline" end - def to_sentence(creator, card_title) - if event.action.comment_created? - comment_sentence(creator, card_title) - else - action_sentence(creator, card_title) - end + def creator_text + event.creator == user ? "You" : h(event.creator.name) + end + + def card + @card ||= event.action.comment_created? ? event.eventable.card : event.eventable end def comment_sentence(creator, card_title) From 82adcecfb15ac998defb19283b03bc5b898b04c1 Mon Sep 17 00:00:00 2001 From: Jorge Manrubia Date: Thu, 6 Nov 2025 11:05:42 +0100 Subject: [PATCH 07/10] Add some sanity tests for event descriptions --- test/models/event/description_test.rb | 35 +++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 test/models/event/description_test.rb diff --git a/test/models/event/description_test.rb b/test/models/event/description_test.rb new file mode 100644 index 000000000..6fa8d20d2 --- /dev/null +++ b/test/models/event/description_test.rb @@ -0,0 +1,35 @@ +require "test_helper" + +class Event::DescriptionTest < ActiveSupport::TestCase + test "generates html description for card published event" do + description = events(:logo_published).description_for(users(:david)) + + assert_includes description.to_html, "added" + assert_includes description.to_html, "logo" + end + + test "generates plain text description for card published event" do + description = events(:logo_published).description_for(users(:david)) + + assert_includes description.to_plain_text, "You added" + assert_includes description.to_plain_text, "logo" + end + + test "generates description for comment event" do + description = events(:layout_commented).description_for(users(:jz)) + + assert_includes description.to_plain_text, "David commented on" + end + + test "uses 'You' when event creator is the current user" do + description = events(:logo_published).description_for(users(:david)) + + assert_includes description.to_plain_text, "You added" + end + + test "uses creator name when event creator is not the current user" do + description = events(:logo_published).description_for(users(:jz)) + + assert_includes description.to_plain_text, "David added" + end +end From 9291e64deb2faefa80bbd60473fa8b7cfb9cef0a Mon Sep 17 00:00:00 2001 From: Jorge Manrubia Date: Thu, 6 Nov 2025 11:21:22 +0100 Subject: [PATCH 08/10] Add test for weebhook delivery test --- test/models/webhook/delivery_test.rb | 40 ++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/test/models/webhook/delivery_test.rb b/test/models/webhook/delivery_test.rb index 244a9a2cc..8deab09ae 100644 --- a/test/models/webhook/delivery_test.rb +++ b/test/models/webhook/delivery_test.rb @@ -218,4 +218,44 @@ class Webhook::DeliveryTest < ActiveSupport::TestCase assert Webhook::Delivery.exists?(fresh_delivery.id) assert_not Webhook::Delivery.exists?(stale_delivery.id) end + + test "renders 'You' when event creator is current user" do + webhook = Webhook.create!( + board: boards(:writebook), + name: "Basecamp", + url: "https://3.basecamp.com/123/integrations/webhook/buckets/456/chats/789/lines" + ) + event = events(:logo_published) + delivery = Webhook::Delivery.create!(webhook: webhook, event: event) + + Current.session = sessions(:david) + + request_stub = stub_request(:post, webhook.url) + .with { |request| CGI.parse(request.body)["content"].first.include?("You added") } + .to_return(status: 200) + + delivery.deliver + + assert_requested request_stub + end + + test "renders creator name when event creator is not current user" do + webhook = Webhook.create!( + board: boards(:writebook), + name: "Basecamp", + url: "https://3.basecamp.com/123/integrations/webhook/buckets/456/chats/789/lines" + ) + event = events(:logo_published) + delivery = Webhook::Delivery.create!(webhook: webhook, event: event) + + Current.session = sessions(:kevin) + + request_stub = stub_request(:post, webhook.url) + .with { |request| CGI.parse(request.body)["content"].first.include?("David added") } + .to_return(status: 200) + + delivery.deliver + + assert_requested request_stub + end end From 0c48e5f30a962885623f32f0a73b9f7b61c0f074 Mon Sep 17 00:00:00 2001 From: Jorge Manrubia Date: Thu, 6 Nov 2025 11:43:22 +0100 Subject: [PATCH 09/10] No need to escape here --- app/models/event/description.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/event/description.rb b/app/models/event/description.rb index ab0305d96..3c6d2200d 100644 --- a/app/models/event/description.rb +++ b/app/models/event/description.rb @@ -29,7 +29,7 @@ class Event::Description def creator_tag tag.span data: { creator_id: event.creator.id } do tag.span("You", data: { only_visible_to_you: true }) + - tag.span(h(event.creator.name), data: { only_visible_to_others: true }) + tag.span(event.creator.name, data: { only_visible_to_others: true }) end end From 6fcb51703d5790eb3313601148ffdfbcb4657c3d Mon Sep 17 00:00:00 2001 From: Jorge Manrubia Date: Thu, 6 Nov 2025 11:44:03 +0100 Subject: [PATCH 10/10] Format --- app/models/event/description.rb | 48 ++++++++++++++++----------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/app/models/event/description.rb b/app/models/event/description.rb index 3c6d2200d..87a5ec6d0 100644 --- a/app/models/event/description.rb +++ b/app/models/event/description.rb @@ -51,30 +51,30 @@ class Event::Description def action_sentence(creator, card_title) case event.action - when "card_assigned" - assigned_sentence(creator, card_title) - when "card_unassigned" - unassigned_sentence(creator, card_title) - when "card_published" - "#{creator} added #{card_title}" - when "card_closed" - %(#{creator} moved #{card_title} to "Done") - when "card_reopened" - "#{creator} reopened #{card_title}" - when "card_postponed" - %(#{creator} moved #{card_title} to "Not Now") - when "card_auto_postponed" - %(#{card_title} was closed as "Not Now" due to inactivity) - when "card_resumed" - "#{creator} resumed #{card_title}" - when "card_title_changed" - renamed_sentence(creator, card_title) - when "card_board_changed", "card_collection_changed" - moved_sentence(creator, card_title) - when "card_triaged" - triaged_sentence(creator, card_title) - when "card_sent_back_to_triage" - %(#{creator} moved #{card_title} back to "Maybe?") + when "card_assigned" + assigned_sentence(creator, card_title) + when "card_unassigned" + unassigned_sentence(creator, card_title) + when "card_published" + "#{creator} added #{card_title}" + when "card_closed" + %(#{creator} moved #{card_title} to "Done") + when "card_reopened" + "#{creator} reopened #{card_title}" + when "card_postponed" + %(#{creator} moved #{card_title} to "Not Now") + when "card_auto_postponed" + %(#{card_title} was closed as "Not Now" due to inactivity) + when "card_resumed" + "#{creator} resumed #{card_title}" + when "card_title_changed" + renamed_sentence(creator, card_title) + when "card_board_changed", "card_collection_changed" + moved_sentence(creator, card_title) + when "card_triaged" + triaged_sentence(creator, card_title) + when "card_sent_back_to_triage" + %(#{creator} moved #{card_title} back to "Maybe?") end end