diff --git a/app/helpers/events_helper.rb b/app/helpers/events_helper.rb index 992463740..94e6990d2 100644 --- a/app/helpers/events_helper.rb +++ b/app/helpers/events_helper.rb @@ -55,70 +55,6 @@ 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 - end - - def comment_event_action_sentence(event) - "#{event_creator_name(event)} commented on #{event_card_title(event.eventable.card)}".html_safe - end - - def event_creator_name(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 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 - 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" 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..87a5ec6d0 --- /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 + to_sentence(creator_tag, card_title_tag).html_safe + end + + def to_plain_text + to_sentence(creator_text, card.title) + end + + private + 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 + tag.span data: { creator_id: event.creator.id } do + tag.span("You", data: { only_visible_to_you: true }) + + tag.span(event.creator.name, data: { only_visible_to_others: true }) + end + end + + def card_title_tag + tag.span card.title, class: "txt-underline" + 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) + "#{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 0fc767862..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(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 91500a17b..f2920e8d0 100644 --- a/app/views/webhooks/event.html.erb +++ b/app/views/webhooks/event.html.erb @@ -1,4 +1,4 @@ -<%= event_action_sentence(@event) %> +<%= @event.description_for(Current.user).to_plain_text %> <% if @event.eventable %> <%= link_to "↗︎", polymorphic_url(@event.eventable) %> <% end %> 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 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