From 3ae1433a30e2940c4e467a1d18d084384748bb05 Mon Sep 17 00:00:00 2001 From: Bilka Date: Fri, 17 May 2024 18:28:13 +0200 Subject: [PATCH] AO3-6017 Add role of commenter to comment notification emails (#4683) * AO3-6017 Add username and role of commenter to comment notification emails * AO3-6017 Use same locale as guest comment name * AO3-6017 Fix that color was set twice on the pseud * AO3-6017 Add tests for guest and anon comment mails * AO3-6017 Change anon comment case to guard clause * AO3-6017 Rubocop * AO3-6017 Apply suggestions from code review Co-authored-by: Brian Austin <13002992+brianjaustin@users.noreply.github.com> * AO3-6017 Apply suggestions from code review everywhere Would have been nice if GitHub allowed me to do that in my browser * AO3-6017 Add tests for registered user with default pseud * AO3-6017 Add previews for comment reply sent and anon comment reply * AO3-6017 Rubocop * AO3-6017 Fix copy paste error * AO3-6017 Deduplicate comment notification tests in admin mailer spec * AO3-6017 Remove mistakenly added indentation In text mails the indentation ends up in the emails, which is not desired * AO3-6017 Improve locale keys * AO3-6017 Add comments to mailer previews * AO3-6017 Merge fix --------- Co-authored-by: Brian Austin <13002992+brianjaustin@users.noreply.github.com> --- app/helpers/mailer_helper.rb | 19 +- .../comment_notification.text.erb | 2 +- .../edited_comment_notification.text.erb | 2 +- config/locales/mailers/en.yml | 7 +- spec/mailers/admin_mailer_spec.rb | 294 ++++++++++++------ spec/mailers/comment_mailer_spec.rb | 236 ++++++++++++-- test/mailers/previews/admin_mailer_preview.rb | 29 ++ .../previews/comment_mailer_preview.rb | 55 ++++ 8 files changed, 526 insertions(+), 118 deletions(-) create mode 100644 test/mailers/previews/admin_mailer_preview.rb create mode 100644 test/mailers/previews/comment_mailer_preview.rb diff --git a/app/helpers/mailer_helper.rb b/app/helpers/mailer_helper.rb index c83af00bf0f..67af73b77ec 100644 --- a/app/helpers/mailer_helper.rb +++ b/app/helpers/mailer_helper.rb @@ -181,22 +181,25 @@ def style_work_tag_metadata(tags) end def commenter_pseud_or_name_link(comment) + return style_bold(t("roles.anonymous_creator")) if comment.by_anonymous_creator? + if comment.comment_owner.nil? - t("roles.guest_commenter_name_html", name: style_bold(comment.comment_owner_name), role: style_role(t("roles.guest_with_parens"))) - elsif comment.by_anonymous_creator? - style_bold(t("roles.anonymous_creator")) + t("roles.commenter_name.html", name: style_bold(comment.comment_owner_name), role_with_parens: style_role(t("roles.guest_with_parens"))) else - style_pseud_link(comment.pseud) + role = comment.user.official ? t("roles.official_with_parens") : t("roles.registered_with_parens") + pseud_link = style_link(comment.pseud.byline, user_pseud_url(comment.user, comment.pseud)) + t("roles.commenter_name.html", name: tag.strong(pseud_link), role_with_parens: style_role(role)) end end def commenter_pseud_or_name_text(comment) + return t("roles.anonymous_creator") if comment.by_anonymous_creator? + if comment.comment_owner.nil? - t("roles.guest_commenter_name_text", name: comment.comment_owner_name, role: t("roles.guest_with_parens")) - elsif comment.by_anonymous_creator? - t("roles.anonymous_creator") + t("roles.commenter_name.text", name: comment.comment_owner_name, role_with_parens: t("roles.guest_with_parens")) else - text_pseud(comment.pseud) + role = comment.user.official ? t("roles.official_with_parens") : t("roles.registered_with_parens") + t("roles.commenter_name.text", name: text_pseud(comment.pseud), role_with_parens: role) end end diff --git a/app/views/admin_mailer/comment_notification.text.erb b/app/views/admin_mailer/comment_notification.text.erb index c5ebdddad29..3da5b5b84d9 100644 --- a/app/views/admin_mailer/comment_notification.text.erb +++ b/app/views/admin_mailer/comment_notification.text.erb @@ -1,5 +1,5 @@ <% content_for :message do %> -<%= commenter_pseud_or_name_text(@comment) %> left the following comment on +<%= commenter_pseud_or_name_text(@comment) %> left the following comment on <% if @comment.ultimate_parent.is_a?(Tag) then %>the tag "<%= @comment.ultimate_parent.commentable_name %>" (<%= url_for(:controller => :tags, :action => :show, :id => @comment.ultimate_parent, :only_path => false) %>) <% else %>"<%= @comment.ultimate_parent.commentable_name.html_safe %>" (<%= polymorphic_url(@comment.ultimate_parent, :only_path => false) %>)<% end %>: <%= text_divider %> diff --git a/app/views/admin_mailer/edited_comment_notification.text.erb b/app/views/admin_mailer/edited_comment_notification.text.erb index 26cb244e166..12768817b05 100644 --- a/app/views/admin_mailer/edited_comment_notification.text.erb +++ b/app/views/admin_mailer/edited_comment_notification.text.erb @@ -1,5 +1,5 @@ <% content_for :message do %> -<%= commenter_pseud_or_name_text(@comment) %> edited the following comment on +<%= commenter_pseud_or_name_text(@comment) %> edited the following comment on <% if @comment.ultimate_parent.is_a?(Tag) then %>the tag "<%= @comment.ultimate_parent.commentable_name %>" (<%= url_for(:controller => :tags, :action => :show, :id => @comment.ultimate_parent, :only_path => false) %>) <% else %>"<%= @comment.ultimate_parent.commentable_name.html_safe %>" (<%= polymorphic_url(@comment.ultimate_parent, :only_path => false) %>)<% end %>: <%= text_divider %> diff --git a/config/locales/mailers/en.yml b/config/locales/mailers/en.yml index 59fa550d064..b612c6b6c4b 100644 --- a/config/locales/mailers/en.yml +++ b/config/locales/mailers/en.yml @@ -83,9 +83,12 @@ en: support: The AO3 Support team roles: anonymous_creator: Anonymous Creator - guest_commenter_name_html: "%{name} %{role}" - guest_commenter_name_text: "%{name} %{role}" + commenter_name: + html: "%{name} %{role_with_parens}" + text: "%{name} %{role_with_parens}" guest_with_parens: "(Guest)" + official_with_parens: "(Official)" + registered_with_parens: "(Registered User)" user_mailer: abuse_report: copy: diff --git a/spec/mailers/admin_mailer_spec.rb b/spec/mailers/admin_mailer_spec.rb index eb73425fd43..9977bd05699 100644 --- a/spec/mailers/admin_mailer_spec.rb +++ b/spec/mailers/admin_mailer_spec.rb @@ -3,93 +3,7 @@ require "spec_helper" describe AdminMailer do - describe "#comment_notification" do - let(:email) { described_class.comment_notification(comment.id) } - - context "when the comment is on an admin post" do - let(:comment) { create(:comment, :on_admin_post) } - - context "and the comment's contents contain an image" do - let(:image_url) { "an_image.png" } - let(:image_tag) { "" } - - before do - comment.comment_content += image_tag - comment.save! - end - - context "when image safety mode is enabled for admin post comments" do - before { allow(ArchiveConfig).to receive(:PARENTS_WITH_IMAGE_SAFETY_MODE).and_return(["AdminPost"]) } - - it "strips the image from the email message but leaves its URL" do - expect(email).not_to have_html_part_content(image_tag) - expect(email).not_to have_text_part_content(image_tag) - expect(email).to have_html_part_content(image_url) - expect(email).to have_text_part_content(image_url) - end - end - - context "when image safety mode is not enabled for admin post comments" do - it "embeds the image when image safety mode is completely disabled" do - allow(ArchiveConfig).to receive(:PARENTS_WITH_IMAGE_SAFETY_MODE).and_return([]) - expect(email).to have_html_part_content(image_tag) - expect(email).not_to have_text_part_content(image_url) - end - - it "embeds the image when image safety mode is enabled for other types of comments" do - allow(ArchiveConfig).to receive(:PARENTS_WITH_IMAGE_SAFETY_MODE).and_return(%w[Chapter Tag]) - expect(email).to have_html_part_content(image_tag) - expect(email).not_to have_text_part_content(image_url) - end - end - end - end - end - - describe "#edited_comment_notification" do - let(:email) { described_class.edited_comment_notification(comment.id) } - - context "when the comment is on an admin post" do - let(:comment) { create(:comment, :on_admin_post) } - - context "with an image in the comment content" do - let(:image_url) { "an_image.png" } - let(:image_tag) { "" } - - before do - comment.comment_content += image_tag - comment.save! - end - - context "when image safety mode is enabled for admin post comments" do - before { allow(ArchiveConfig).to receive(:PARENTS_WITH_IMAGE_SAFETY_MODE).and_return(["AdminPost"]) } - - it "strips the image from the email message but leaves its URL" do - expect(email).not_to have_html_part_content(image_tag) - expect(email).not_to have_text_part_content(image_tag) - expect(email).to have_html_part_content(image_url) - expect(email).to have_text_part_content(image_url) - end - end - - context "when image safety mode is not enabled for admin post comments" do - it "embeds the image in the HTML email when image safety mode is completely disabled" do - allow(ArchiveConfig).to receive(:PARENTS_WITH_IMAGE_SAFETY_MODE).and_return([]) - expect(email).to have_html_part_content(image_tag) - expect(email).not_to have_text_part_content(image_url) - end - - it "embeds the image in the HTML email when image safety mode is enabled for other types of comments" do - allow(ArchiveConfig).to receive(:PARENTS_WITH_IMAGE_SAFETY_MODE).and_return(%w[Chapter Tag]) - expect(email).to have_html_part_content(image_tag) - expect(email).not_to have_text_part_content(image_url) - end - end - end - end - end - - describe "send_spam_alert" do + describe "#send_spam_alert" do let(:spam_user) { create(:user) } let(:spam1) do @@ -216,7 +130,7 @@ end end - describe "set_password_notification" do + describe "#set_password_notification" do subject(:email) { AdminMailer.set_password_notification(admin, token) } let(:admin) { create(:admin) } @@ -258,4 +172,208 @@ end end end + + let(:commenter) { create(:user, login: "Accumulator") } + let(:commenter_pseud) { create(:pseud, user: commenter, name: "Blueprint") } + let(:comment) { create(:comment, :on_admin_post, pseud: commenter_pseud) } + + shared_examples "a notification email with the commenter's pseud and username" do + describe "HTML email" do + it "has the pseud and username of the commenter" do + expect(email).to have_html_part_content(">Blueprint (Accumulator) (Registered User)") + expect(subject.html_part).to have_xpath( + "//a[@href=\"#{user_pseud_url(commenter, commenter_pseud)}\"]", + text: "Blueprint (Accumulator)" + ) + end + end + + describe "text email" do + it "has the pseud and username of the commenter" do + expect(subject).to have_text_part_content( + "Blueprint (Accumulator) (#{user_pseud_url(commenter, commenter_pseud)}) (Registered User)" + ) + end + end + end + + shared_examples "a notification email that marks the commenter as official" do + describe "HTML email" do + it "has the username of the commenter and the official role" do + expect(email).to have_html_part_content(">Centrifuge (Official)") + expect(subject.html_part).to have_xpath( + "//a[@href=\"#{user_pseud_url(commenter, commenter.default_pseud)}\"]", + text: "Centrifuge" + ) + end + end + + describe "text email" do + it "has the username of the commenter and the official role" do + expect(subject).to have_text_part_content( + "Centrifuge (#{user_pseud_url(commenter, commenter.default_pseud)}) (Official)" + ) + end + end + end + + shared_examples "a notification email with only the commenter's username" do + describe "HTML email" do + it "has only the username of the commenter" do + expect(email).to have_html_part_content(">Exoskeleton (Registered User)") + expect(subject.html_part).to have_xpath( + "//a[@href=\"#{user_pseud_url(commenter, commenter.default_pseud)}\"]", + text: "Exoskeleton" + ) + expect(email).not_to have_html_part_content(">Exoskeleton (Exoskeleton)") + end + end + + describe "text email" do + it "has only the username of the commenter" do + expect(subject).to have_text_part_content( + "Exoskeleton (#{user_pseud_url(commenter, commenter.default_pseud)}) (Registered User)" + ) + expect(subject).not_to have_text_part_content("Exoskeleton (Exoskeleton)") + end + end + end + + describe "#comment_notification" do + subject(:email) { AdminMailer.comment_notification(comment.id) } + + it_behaves_like "an email with a valid sender" + it_behaves_like "a multipart email" + it_behaves_like "a notification email with the commenter's pseud and username" + + context "when the comment is on an admin post" do + let(:comment) { create(:comment, :on_admin_post) } + + context "and the comment's contents contain an image" do + let(:image_url) { "an_image.png" } + let(:image_tag) { "" } + + before do + comment.comment_content += image_tag + comment.save! + end + + context "when image safety mode is enabled for admin post comments" do + before { allow(ArchiveConfig).to receive(:PARENTS_WITH_IMAGE_SAFETY_MODE).and_return(["AdminPost"]) } + + it "strips the image from the email message but leaves its URL" do + expect(email).not_to have_html_part_content(image_tag) + expect(email).not_to have_text_part_content(image_tag) + expect(email).to have_html_part_content(image_url) + expect(email).to have_text_part_content(image_url) + end + end + + context "when image safety mode is not enabled for admin post comments" do + it "embeds the image when image safety mode is completely disabled" do + allow(ArchiveConfig).to receive(:PARENTS_WITH_IMAGE_SAFETY_MODE).and_return([]) + expect(email).to have_html_part_content(image_tag) + expect(email).not_to have_text_part_content(image_url) + end + + it "embeds the image when image safety mode is enabled for other types of comments" do + allow(ArchiveConfig).to receive(:PARENTS_WITH_IMAGE_SAFETY_MODE).and_return(%w[Chapter Tag]) + expect(email).to have_html_part_content(image_tag) + expect(email).not_to have_text_part_content(image_url) + end + end + end + end + + context "when the comment is by an official user using their default pseud" do + let(:commenter) { create(:official_user, login: "Centrifuge") } + let(:comment) { create(:comment, :on_admin_post, pseud: commenter.default_pseud) } + + it_behaves_like "a notification email that marks the commenter as official" + end + + context "when the commenter is a guest" do + let(:comment) { create(:comment, :on_admin_post, pseud: nil, name: "Defender", email: Faker::Internet.email) } + + describe "HTML email" do + it "has the name of the guest and the guest role" do + expect(email).to have_html_part_content(">Defender (Guest)") + end + end + + describe "text email" do + it "has the name of the guest and the guest role" do + expect(subject).to have_text_part_content("Defender (Guest)") + end + end + end + + context "when the comment is by a registered user using their default pseud" do + let(:commenter) { create(:user, login: "Exoskeleton") } + let(:comment) { create(:comment, pseud: commenter.default_pseud) } + + it_behaves_like "a notification email with only the commenter's username" + end + end + + describe "#comment_edited_notification" do + subject(:email) { AdminMailer.edited_comment_notification(comment.id) } + + it_behaves_like "an email with a valid sender" + it_behaves_like "a multipart email" + it_behaves_like "a notification email with the commenter's pseud and username" + + context "when the comment is on an admin post" do + let(:comment) { create(:comment, :on_admin_post) } + + context "with an image in the comment content" do + let(:image_url) { "an_image.png" } + let(:image_tag) { "" } + + before do + comment.comment_content += image_tag + comment.save! + end + + context "when image safety mode is enabled for admin post comments" do + before { allow(ArchiveConfig).to receive(:PARENTS_WITH_IMAGE_SAFETY_MODE).and_return(["AdminPost"]) } + + it "strips the image from the email message but leaves its URL" do + expect(email).not_to have_html_part_content(image_tag) + expect(email).not_to have_text_part_content(image_tag) + expect(email).to have_html_part_content(image_url) + expect(email).to have_text_part_content(image_url) + end + end + + context "when image safety mode is not enabled for admin post comments" do + it "embeds the image in the HTML email when image safety mode is completely disabled" do + allow(ArchiveConfig).to receive(:PARENTS_WITH_IMAGE_SAFETY_MODE).and_return([]) + expect(email).to have_html_part_content(image_tag) + expect(email).not_to have_text_part_content(image_url) + end + + it "embeds the image in the HTML email when image safety mode is enabled for other types of comments" do + allow(ArchiveConfig).to receive(:PARENTS_WITH_IMAGE_SAFETY_MODE).and_return(%w[Chapter Tag]) + expect(email).to have_html_part_content(image_tag) + expect(email).not_to have_text_part_content(image_url) + end + end + end + end + + context "when the comment is by an official user using their default pseud" do + let(:commenter) { create(:official_user, login: "Centrifuge") } + let(:comment) { create(:comment, :on_admin_post, pseud: commenter.default_pseud) } + + it_behaves_like "a notification email that marks the commenter as official" + end + + context "when the comment is by a registered user using their default pseud" do + let(:commenter) { create(:user, login: "Exoskeleton") } + let(:comment) { create(:comment, :on_admin_post, pseud: commenter.default_pseud) } + + it_behaves_like "a notification email with only the commenter's username" + end + end end diff --git a/spec/mailers/comment_mailer_spec.rb b/spec/mailers/comment_mailer_spec.rb index f248ed79c4c..7a2c2d7456e 100644 --- a/spec/mailers/comment_mailer_spec.rb +++ b/spec/mailers/comment_mailer_spec.rb @@ -1,8 +1,10 @@ require "spec_helper" describe CommentMailer do - let(:comment) { create(:comment) } let(:user) { create(:user) } + let(:commenter) { create(:user, login: "Accumulator") } + let(:commenter_pseud) { create(:pseud, user: commenter, name: "Blueprint") } + let(:comment) { create(:comment, pseud: commenter_pseud) } shared_examples "it retries when the comment doesn't exist" do it "tries to send the email 3 times, then fails silently" do @@ -71,6 +73,82 @@ end end + shared_examples "a notification email with the commenter's pseud and username" do + describe "HTML email" do + it "has the pseud and username of the commenter" do + expect(email).to have_html_part_content(">Blueprint (Accumulator) (Registered User)") + expect(subject.html_part).to have_xpath( + "//a[@href=\"#{user_pseud_url(commenter, commenter_pseud)}\"]", + text: "Blueprint (Accumulator)" + ) + end + end + + describe "text email" do + it "has the pseud and username of the commenter" do + expect(subject).to have_text_part_content( + "Blueprint (Accumulator) (#{user_pseud_url(commenter, commenter_pseud)}) (Registered User)" + ) + end + end + end + + shared_examples "a notification email that marks the commenter as official" do + describe "HTML email" do + it "has the username of the commenter and the official role" do + expect(email).to have_html_part_content(">Centrifuge (Official)") + expect(subject.html_part).to have_xpath( + "//a[@href=\"#{user_pseud_url(commenter, commenter.default_pseud)}\"]", + text: "Centrifuge" + ) + end + end + + describe "text email" do + it "has the username of the commenter and the official role" do + expect(subject).to have_text_part_content( + "Centrifuge (#{user_pseud_url(commenter, commenter.default_pseud)}) (Official)" + ) + end + end + end + + shared_examples "a notification email that marks the commenter as a guest" do + describe "HTML email" do + it "has the name of the guest and the guest role" do + expect(email).to have_html_part_content(">Defender (Guest)") + end + end + + describe "text email" do + it "has the name of the guest and the guest role" do + expect(subject).to have_text_part_content("Defender (Guest)") + end + end + end + + shared_examples "a notification email with only the commenter's username" do + describe "HTML email" do + it "has only the username of the commenter" do + expect(email).to have_html_part_content(">Exoskeleton (Registered User)") + expect(subject.html_part).to have_xpath( + "//a[@href=\"#{user_pseud_url(commenter, commenter.default_pseud)}\"]", + text: "Exoskeleton" + ) + expect(email).not_to have_html_part_content(">Exoskeleton (Exoskeleton)") + end + end + + describe "text email" do + it "has only the username of the commenter" do + expect(subject).to have_text_part_content( + "Exoskeleton (#{user_pseud_url(commenter, commenter.default_pseud)}) (Registered User)" + ) + expect(subject).not_to have_text_part_content("Exoskeleton (Exoskeleton)") + end + end + end + shared_examples "a comment subject to image safety mode settings" do let(:image_url) { "an_image.png" } let(:image_tag) { "" } @@ -112,11 +190,33 @@ subject(:email) { CommentMailer.comment_notification(user, comment) } it_behaves_like "an email with a valid sender" + it_behaves_like "a multipart email" it_behaves_like "it retries when the comment doesn't exist" it_behaves_like "a notification email with a link to the comment" it_behaves_like "a notification email with a link to reply to the comment" + it_behaves_like "a notification email with the commenter's pseud and username" it_behaves_like "a comment subject to image safety mode settings" + context "when the comment is by an official user using their default pseud" do + let(:commenter) { create(:official_user, login: "Centrifuge") } + let(:comment) { create(:comment, pseud: commenter.default_pseud) } + + it_behaves_like "a notification email that marks the commenter as official" + end + + context "when the comment is by a guest" do + let(:comment) { create(:comment, pseud: nil, name: "Defender", email: Faker::Internet.email) } + + it_behaves_like "a notification email that marks the commenter as a guest" + end + + context "when the comment is by a registered user using their default pseud" do + let(:commenter) { create(:user, login: "Exoskeleton") } + let(:comment) { create(:comment, pseud: commenter.default_pseud) } + + it_behaves_like "a notification email with only the commenter's username" + end + context "when the comment is on an admin post" do let(:comment) { create(:comment, :on_admin_post) } @@ -124,41 +224,60 @@ end context "when the comment is a reply to another comment" do - let(:comment) { create(:comment, commentable: create(:comment)) } + let(:comment) { create(:comment, commentable: create(:comment), pseud: commenter_pseud) } it_behaves_like "a notification email with a link to the comment" it_behaves_like "a notification email with a link to reply to the comment" it_behaves_like "a notification email with a link to the comment's thread" + it_behaves_like "a notification email with the commenter's pseud and username" it_behaves_like "a comment subject to image safety mode settings" end context "when the comment is on a tag" do - let(:comment) { create(:comment, :on_tag) } + let(:comment) { create(:comment, :on_tag, pseud: commenter_pseud) } it_behaves_like "a notification email with a link to the comment" it_behaves_like "a notification email with a link to reply to the comment" + it_behaves_like "a notification email with the commenter's pseud and username" it_behaves_like "a comment subject to image safety mode settings" context "when the comment is a reply to another comment" do - let(:comment) { create(:comment, commentable: create(:comment, :on_tag)) } + let(:comment) { create(:comment, commentable: create(:comment, :on_tag), pseud: commenter_pseud) } it_behaves_like "a notification email with a link to the comment" it_behaves_like "a notification email with a link to reply to the comment" it_behaves_like "a notification email with a link to the comment's thread" + it_behaves_like "a notification email with the commenter's pseud and username" it_behaves_like "a comment subject to image safety mode settings" end end end - describe "edited_comment_notification" do + describe "#edited_comment_notification" do subject(:email) { CommentMailer.edited_comment_notification(user, comment) } it_behaves_like "an email with a valid sender" + it_behaves_like "a multipart email" it_behaves_like "it retries when the comment doesn't exist" it_behaves_like "a notification email with a link to the comment" it_behaves_like "a notification email with a link to reply to the comment" + it_behaves_like "a notification email with the commenter's pseud and username" it_behaves_like "a comment subject to image safety mode settings" + context "when the comment is by an official user using their default pseud" do + let(:commenter) { create(:official_user, login: "Centrifuge") } + let(:comment) { create(:comment, pseud: commenter.default_pseud) } + + it_behaves_like "a notification email that marks the commenter as official" + end + + context "when the comment is by a registered user using their default pseud" do + let(:commenter) { create(:user, login: "Exoskeleton") } + let(:comment) { create(:comment, pseud: commenter.default_pseud) } + + it_behaves_like "a notification email with only the commenter's username" + end + context "when the comment is on an admin post" do let(:comment) { create(:comment, :on_admin_post) } @@ -166,45 +285,70 @@ end context "when the comment is a reply to another comment" do - let(:comment) { create(:comment, commentable: create(:comment)) } + let(:comment) { create(:comment, commentable: create(:comment), pseud: commenter_pseud) } it_behaves_like "a notification email with a link to the comment" it_behaves_like "a notification email with a link to reply to the comment" it_behaves_like "a notification email with a link to the comment's thread" + it_behaves_like "a notification email with the commenter's pseud and username" it_behaves_like "a comment subject to image safety mode settings" end context "when the comment is on a tag" do - let(:comment) { create(:comment, :on_tag) } + let(:comment) { create(:comment, :on_tag, pseud: commenter_pseud) } it_behaves_like "a notification email with a link to the comment" it_behaves_like "a notification email with a link to reply to the comment" + it_behaves_like "a notification email with the commenter's pseud and username" it_behaves_like "a comment subject to image safety mode settings" context "when the comment is a reply to another comment" do - let(:comment) { create(:comment, commentable: create(:comment, :on_tag)) } + let(:comment) { create(:comment, commentable: create(:comment, :on_tag), pseud: commenter_pseud) } it_behaves_like "a notification email with a link to the comment" it_behaves_like "a notification email with a link to reply to the comment" it_behaves_like "a notification email with a link to the comment's thread" + it_behaves_like "a notification email with the commenter's pseud and username" it_behaves_like "a comment subject to image safety mode settings" end end end - describe "comment_reply_notification" do + describe "#comment_reply_notification" do subject(:email) { CommentMailer.comment_reply_notification(parent_comment, comment) } let(:parent_comment) { create(:comment) } - let(:comment) { create(:comment, commentable: parent_comment) } + let(:comment) { create(:comment, commentable: parent_comment, pseud: commenter_pseud) } it_behaves_like "an email with a valid sender" + it_behaves_like "a multipart email" it_behaves_like "it retries when the comment doesn't exist" it_behaves_like "a notification email with a link to the comment" it_behaves_like "a notification email with a link to reply to the comment" it_behaves_like "a notification email with a link to the comment's thread" + it_behaves_like "a notification email with the commenter's pseud and username" it_behaves_like "a comment subject to image safety mode settings" + context "when the comment is by an official user using their default pseud" do + let(:commenter) { create(:official_user, login: "Centrifuge") } + let(:comment) { create(:comment, commentable: parent_comment, pseud: commenter.default_pseud) } + + it_behaves_like "a notification email that marks the commenter as official" + end + + context "when the comment is by a guest" do + let(:comment) { create(:comment, commentable: parent_comment, pseud: nil, name: "Defender", email: Faker::Internet.email) } + + it_behaves_like "a notification email that marks the commenter as a guest" + end + + context "when the comment is by a registered user using their default pseud" do + let(:commenter) { create(:user, login: "Exoskeleton") } + let(:comment) { create(:comment, commentable: parent_comment, pseud: commenter.default_pseud) } + + it_behaves_like "a notification email with only the commenter's username" + end + context "when the comment is on an admin post" do let(:comment) { create(:comment, :on_admin_post) } @@ -212,11 +356,12 @@ end context "when the comment is on a tag" do - let(:parent_comment) { create(:comment, :on_tag) } + let(:parent_comment) { create(:comment, :on_tag, pseud: commenter_pseud) } it_behaves_like "a notification email with a link to the comment" it_behaves_like "a notification email with a link to reply to the comment" it_behaves_like "a notification email with a link to the comment's thread" + it_behaves_like "a notification email with the commenter's pseud and username" it_behaves_like "a comment subject to image safety mode settings" end @@ -234,21 +379,57 @@ it_behaves_like "an unsent email" end + + context "when the comment is from the author of the anonymous work" do + let(:work) { create(:work, authors: [commenter_pseud], collections: [create(:anonymous_collection)]) } + let(:parent_comment) { create(:comment, commentable: work) } + let(:comment) { create(:comment, commentable: parent_comment, pseud: commenter_pseud) } + + describe "HTML email" do + it "does not reveal the pseud of the replier" do + expect(subject).to have_html_part_content(">Anonymous Creator") + expect(email).not_to have_html_part_content(">Blueprint (Accumulator)") + end + end + + describe "text email" do + it "does not reveal the pseud of the replier" do + expect(subject).to have_text_part_content("Anonymous Creator") + expect(subject).not_to have_text_part_content("Blueprint (Accumulator)") + end + end + end end - describe "edited_comment_reply_notification" do + describe "#edited_comment_reply_notification" do subject(:email) { CommentMailer.edited_comment_reply_notification(parent_comment, comment) } let(:parent_comment) { create(:comment) } - let(:comment) { create(:comment, commentable: parent_comment) } + let(:comment) { create(:comment, commentable: parent_comment, pseud: commenter_pseud) } it_behaves_like "an email with a valid sender" + it_behaves_like "a multipart email" it_behaves_like "it retries when the comment doesn't exist" it_behaves_like "a notification email with a link to the comment" it_behaves_like "a notification email with a link to reply to the comment" it_behaves_like "a notification email with a link to the comment's thread" + it_behaves_like "a notification email with the commenter's pseud and username" it_behaves_like "a comment subject to image safety mode settings" + context "when the comment is by an official user using their default pseud" do + let(:commenter) { create(:official_user, login: "Centrifuge") } + let(:comment) { create(:comment, commentable: parent_comment, pseud: commenter.default_pseud) } + + it_behaves_like "a notification email that marks the commenter as official" + end + + context "when the comment is by a registered user using their default pseud" do + let(:commenter) { create(:user, login: "Exoskeleton") } + let(:comment) { create(:comment, commentable: parent_comment, pseud: commenter.default_pseud) } + + it_behaves_like "a notification email with only the commenter's username" + end + context "when the comment is on an admin post" do let(:comment) { create(:comment, :on_admin_post) } @@ -256,11 +437,12 @@ end context "when the comment is on a tag" do - let(:parent_comment) { create(:comment, :on_tag) } + let(:parent_comment) { create(:comment, :on_tag, pseud: commenter_pseud) } it_behaves_like "a notification email with a link to the comment" it_behaves_like "a notification email with a link to reply to the comment" it_behaves_like "a notification email with a link to the comment's thread" + it_behaves_like "a notification email with the commenter's pseud and username" it_behaves_like "a comment subject to image safety mode settings" end @@ -280,10 +462,11 @@ end end - describe "comment_sent_notification" do + describe "#comment_sent_notification" do subject(:email) { CommentMailer.comment_sent_notification(comment) } it_behaves_like "an email with a valid sender" + it_behaves_like "a multipart email" it_behaves_like "it retries when the comment doesn't exist" it_behaves_like "a notification email with a link to the comment" it_behaves_like "a comment subject to image safety mode settings" @@ -302,16 +485,18 @@ end end - describe "comment_reply_sent_notification" do + describe "#comment_reply_sent_notification" do subject(:email) { CommentMailer.comment_reply_sent_notification(comment) } - let(:parent_comment) { create(:comment) } + let(:parent_comment) { create(:comment, pseud: commenter_pseud) } let(:comment) { create(:comment, commentable: parent_comment) } it_behaves_like "an email with a valid sender" + it_behaves_like "a multipart email" it_behaves_like "it retries when the comment doesn't exist" it_behaves_like "a notification email with a link to the comment" it_behaves_like "a notification email with a link to the comment's thread" + it_behaves_like "a notification email with the commenter's pseud and username" it_behaves_like "a comment subject to image safety mode settings" context "when the comment is on an admin post" do @@ -320,11 +505,26 @@ it_behaves_like "a comment subject to image safety mode settings" end + context "when the comment is by an official user using their default pseud" do + let(:commenter) { create(:official_user, login: "Centrifuge") } + let(:parent_comment) { create(:comment, pseud: commenter.default_pseud) } + + it_behaves_like "a notification email that marks the commenter as official" # for parent comment + end + + context "when the comment is by a registered user using their default pseud" do + let(:commenter) { create(:user, login: "Exoskeleton") } + let(:parent_comment) { create(:comment, pseud: commenter.default_pseud) } + + it_behaves_like "a notification email with only the commenter's username" # for parent comment + end + context "when the parent comment is on a tag" do - let(:parent_comment) { create(:comment, :on_tag) } + let(:parent_comment) { create(:comment, :on_tag, pseud: commenter_pseud) } it_behaves_like "a notification email with a link to the comment" it_behaves_like "a notification email with a link to the comment's thread" + it_behaves_like "a notification email with the commenter's pseud and username" # for parent comment it_behaves_like "a comment subject to image safety mode settings" end end diff --git a/test/mailers/previews/admin_mailer_preview.rb b/test/mailers/previews/admin_mailer_preview.rb new file mode 100644 index 00000000000..3d3da7ab8cc --- /dev/null +++ b/test/mailers/previews/admin_mailer_preview.rb @@ -0,0 +1,29 @@ +class AdminMailerPreview < ApplicationMailerPreview + # Sent to an admin when they get a comment on an admin post + def comment_notification + commenter = create(:user, login: "Accumulator") + commenter_pseud = create(:pseud, user: commenter, name: "Blueprint") + comment = create(:comment, pseud: commenter_pseud) + AdminMailer.comment_notification(comment.id) + end + + # Sent to an admin when they get a comment on an admin post by an official user + def comment_notification_official + commenter = create(:official_user, login: "Centrifuge") + comment = create(:comment, pseud: commenter.default_pseud) + AdminMailer.comment_notification(comment.id) + end + + # Sent to an admin when they get a comment on an admin post by a guest + def comment_notification_guest + comment = create(:comment, :by_guest) + AdminMailer.comment_notification(comment.id) + end + + # Sent to an admin when a comment on an admin post is edited + def edited_comment_notification + commenter = create(:user, login: "Defender") + comment = create(:comment, pseud: commenter.default_pseud) + AdminMailer.edited_comment_notification(comment.id) + end +end diff --git a/test/mailers/previews/comment_mailer_preview.rb b/test/mailers/previews/comment_mailer_preview.rb new file mode 100644 index 00000000000..167e75e8560 --- /dev/null +++ b/test/mailers/previews/comment_mailer_preview.rb @@ -0,0 +1,55 @@ +class CommentMailerPreview < ApplicationMailerPreview + # Sent to a user when they get a comment on a top-level creation + def comment_notification + user = create(:user) + + commenter = create(:user, login: "Accumulator") + commenter_pseud = create(:pseud, user: commenter, name: "Blueprint") + comment = create(:comment, pseud: commenter_pseud) + CommentMailer.comment_notification(user, comment) + end + + # Sent to a user when they get a comment on a top-level creation by an official user + def comment_notification_official + user = create(:user) + + commenter = create(:official_user, login: "Centrifuge") + comment = create(:comment, pseud: commenter.default_pseud) + CommentMailer.comment_notification(user, comment) + end + + # Sent to a user when they get a comment on a top-level creation by a guest + def comment_notification_guest + user = create(:user) + comment = create(:comment, :by_guest) + CommentMailer.comment_notification(user, comment) + end + + # Sent to a user when they get a comment reply to their comment + def comment_reply_notification + comment = create(:comment) + + replier = create(:user, login: "Defender") + reply = create(:comment, commentable: comment, pseud: replier.default_pseud) + CommentMailer.comment_reply_notification(comment, reply) + end + + # Sent to a user when they get a reply to their comment by an anonymous creator + def comment_reply_notification_anon + replier = create(:user) + work = create(:work, authors: [replier.default_pseud], collections: [create(:anonymous_collection)]) + + comment = create(:comment, commentable: work) + reply = create(:comment, commentable: comment, pseud: replier.default_pseud) + CommentMailer.comment_reply_notification(comment, reply) + end + + # Sent to a user when they make a reply to a comment and they want to be notified of their own comments + def comment_reply_sent_notification + commenter = create(:user, login: "Exoskeleton") + + comment = create(:comment, pseud: commenter.default_pseud) + reply = create(:comment, commentable: comment) + CommentMailer.comment_reply_sent_notification(reply) + end +end