Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AO3-5763 AO3-5348 Add more info to gift notification email and internationalize it #4137

Merged
merged 13 commits into from Apr 24, 2022
Merged
52 changes: 52 additions & 0 deletions app/helpers/mailer_helper.rb
Expand Up @@ -127,4 +127,56 @@ def creator_text(work)
work.pseuds.map { |p| text_pseud(p) }.to_sentence.html_safe
end
end

def work_metadata_label(text)
text.html_safe + t("mailer.general.metadata_label_indicator")
end

# Spacing is dealt with in locale files, e.g. " : " for French.
def work_tag_metadata(tags)
return if tags.empty?

"#{work_tag_metadata_label(tags)}#{work_tag_metadata_list(tags)}"
end

def style_work_metadata_label(text)
style_bold(work_metadata_label(text))
end

# Spacing is dealt with in locale files, e.g. " : " for French.
def style_work_tag_metadata(tags)
return if tags.empty?

label = style_bold(work_tag_metadata_label(tags))
"#{label}#{style_work_tag_metadata_list(tags)}".html_safe
end

private

def work_tag_metadata_label(tags)
return if tags.empty?

type = tags.first.type
t("activerecord.models.#{type.underscore}", count: tags.count) + t("mailer.general.metadata_label_indicator")
end

# We don't use .to_sentence because these aren't links and we risk making any
# connector word (e.g., "and") look like part of the final tag.
def work_tag_metadata_list(tags)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this used directly in a view? If so, we should make it private and keep the list of available helpers shorter.

Then we can have specs just for the public ones as well.

return if tags.empty?

tags.pluck(:name).join(t("support.array.words_connector"))
end

def style_work_tag_metadata_list(tags)
return if tags.empty?

type = tags.first.type
# Fandom tags are linked and to_sentence'd.
if type == "Fandom"
tags.map { |f| style_link(f.name, fandom_url(f)) }.to_sentence.html_safe
else
work_tag_metadata_list(tags)
end
end
end # end of MailerHelper
6 changes: 6 additions & 0 deletions app/helpers/translation_helper.rb
Expand Up @@ -60,4 +60,10 @@ def time_ago_in_words(from_time, include_seconds = false)

alias distance_of_time_in_words_to_now time_ago_in_words

# Take some text and add whatever punctuation, symbols, and/or spacing
# we use to separate a metadata property from its value, e.g., "Property: ",
# "Propriété : ".
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Style/AsciiComments: Use only ascii symbols in comments.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Va te faire enculer, Hound. It's French.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Duo serait très fier de toi :P

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah we don't have to do anything here. This check will eventually be phased out (rubocop/rubocop#9674).

def metadata_property(text)
text.html_safe + t("mailer.general.metadata_label_indicator")
end
end
16 changes: 8 additions & 8 deletions app/mailers/user_mailer.rb
Expand Up @@ -311,15 +311,15 @@ def recipient_notification(user_id, work_id, collection_id = nil)
@user = User.find(user_id)
@work = Work.find(work_id)
@collection = Collection.find(collection_id) if collection_id
subject = if @collection
t("user_mailer.recipient_notification.subject.collection",
app_name: ArchiveConfig.APP_SHORT_NAME,
collection_title: @collection.title)
else
t("user_mailer.recipient_notification.subject.no_collection",
app_name: ArchiveConfig.APP_SHORT_NAME)
end
I18n.with_locale(Locale.find(@user.preference.preferred_locale).iso) do
subject = if @collection
t("user_mailer.recipient_notification.subject.collection",
app_name: ArchiveConfig.APP_SHORT_NAME,
collection_title: @collection.title)
else
t("user_mailer.recipient_notification.subject.no_collection",
app_name: ArchiveConfig.APP_SHORT_NAME)
end
mail(
to: @user.email,
subject: subject
Expand Down
24 changes: 24 additions & 0 deletions app/views/user_mailer/_work_info.html.erb
@@ -0,0 +1,24 @@
<% # expects work %>
<p>
<%= style_work_metadata_label(Work.human_attribute_name("chapter_total_display")) %><%= work.chapter_total_display %>
<br><%= style_work_tag_metadata(work.fandoms) %>
<br><%= style_work_tag_metadata(work.ratings) %>
<br><%= style_work_tag_metadata(work.archive_warnings) %>
<% unless work.relationship_string.blank? %>
<br><%= style_work_tag_metadata(work.relationships) %>
<% end %>
<% unless work.character_string.blank? %>
<br><%= style_work_tag_metadata(work.characters) %>
<% end %>
<% unless work.freeform_string.blank? %>
<br><%= style_work_tag_metadata(work.freeforms) %>
<% end %>
<% unless work.series.count.zero? %>
<br><%= style_work_metadata_label(Series.model_name.human(count: work.series.count)) %><%= series_list_for_feeds(work).html_safe %>
<% end %>
</p>

<% unless work.summary.blank? %>
<p><%= style_work_metadata_label(Work.human_attribute_name("summary")) %></p>
<%= style_quote(raw sanitize_field(work, :summary)) %>
<% end %>
22 changes: 22 additions & 0 deletions app/views/user_mailer/_work_info.text.erb
@@ -0,0 +1,22 @@
<% # expects work %>
<%= work_metadata_label(Work.human_attribute_name("chapter_total_display"))%><%= work.chapter_total_display %>
<%= work_tag_metadata(work.fandoms) %>
<%= work_tag_metadata(work.ratings) %>
<%= work_tag_metadata(work.archive_warnings) %>
<% unless work.relationship_string.blank? %>
<%= work_tag_metadata(work.relationships) %>
<% end %>
<% unless work.character_string.blank? %>
<%= work_tag_metadata(work.characters) %>
<% end %>
<% unless work.freeform_string.blank? %>
<%= work_tag_metadata(work.freeforms) %>
<% end %>
<% unless work.series.count.zero? %>
<%= Series.model_name.human(count: work.series.count) %><%= raw to_plain_text(series_list_for_feeds(work)) %>
<% end %>
<% unless work.summary.blank? %>

<%= work_metadata_label(Work.human_attribute_name("summary")) %>
<%= raw to_plain_text(sanitize_field(work, :summary)) %>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be indented 2 spaces?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nope, I wanted to match the indenting from the subscription emails (I assume we went with four spaces because it's more obviously done for a pretty formatting effect than two -- two just looks kinda like we misaligned the text):

Summary:
<%= raw to_plain_text(sanitize_field(this_work, :summary)) %><% @seen_summary[this_work.id] = true %><% end %><% if (index < @creations.length-1) %>

<% end %>
18 changes: 4 additions & 14 deletions app/views/user_mailer/recipient_notification.html.erb
Expand Up @@ -7,23 +7,13 @@
</p>

<p>
<% if @collection.nil? %>
<%= style_creation_link(@work.title, work_url(@work)) %> <%= "(#{@work.word_count} words)" %>
<% else %>
<%= style_creation_link(@work.title, collection_work_url(@collection, @work)) %> <%= "(#{@work.word_count} words)" %>
<% end %>
<% url = @collection ? collection_work_url(@collection, @work) : work_url(@work) %>
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(The work title/byline is separate from the other metadata because subscription emails display this info differently.)

<%= style_creation_link(@work.title, url) %> <%= "(#{@work.word_count} words)" %>
<br>
by <%= @work.anonymous? ? "an anonymous responder" : (@work.pseuds.map{|p| style_pseud_link(p)}.to_sentence.html_safe) %>
<br>
<% unless @work.fandom_string.blank? %>
<%= style_bold("Fandom:") %> <%= @work.fandom_string %>
<% end %>
by <%= creator_links(@work) %>
</p>

<% unless @work.summary.blank? %>
<%= style_bold("Summary:") %>
<%= style_quote(raw sanitize_field(@work, :summary)) %>
<% end %>
<%= render "work_info", work: @work %>

<% if @collection && !@collection.gift_notification.blank? %>
<p><%= @collection.gift_notification %></p>
Expand Down
7 changes: 2 additions & 5 deletions app/views/user_mailer/recipient_notification.text.erb
Expand Up @@ -6,11 +6,8 @@ A gift work has been posted for you<% if @collection %> in the "<%= @collection.
"<%= @work.title.html_safe %>" (<%= @work.word_count %> words)
<%= @collection ? collection_work_url(@collection, @work) : work_url(@work) %>

by <%= @work.anonymous? ? "an anonymous responder" : (@work.pseuds.map{|p| text_pseud(p)}.to_sentence) %>
by <%= creator_text(@work) %>

<% unless @work.fandom_string.blank? %>Fandom: <%= @work.fandom_string %><% end %>

<% unless @work.summary.blank? %>Summary:
<%= to_plain_text(raw sanitize_field(@work, :summary)) %><% end %>
<%= render "work_info", work: @work %>

<% if @collection && !@collection.gift_notification.blank? %><%= @collection.gift_notification %><% end %><% end %>
1 change: 1 addition & 0 deletions config/locales/mailers/en.yml
Expand Up @@ -10,6 +10,7 @@ en:
addressed: "Hi, %{name}!"
unaddressed: "Hi!"
introductory: "Hello from the Archive of Our Own!"
metadata_label_indicator: ": "
signature:
app_short_name: AO3
open_doors: The Open Doors team
Expand Down
16 changes: 13 additions & 3 deletions config/locales/models/en.yml
Expand Up @@ -23,12 +23,14 @@ en:
models:
archive_warning:
one: "Warning"
other: "Warnings"
other: "Warnings"
bookmark: "Bookmark"
category:
one: "Category"
other: "Categories"
chapter: "Chapter"
chapter:
one: "Chapter"
other: "Chapters"
character:
one: "Character"
other: "Characters"
Expand All @@ -40,10 +42,15 @@ en:
one: "Additional Tag"
other: "Additional Tags"
pseud: "Pseud"
rating: "Rating"
rating:
one: "Rating"
other: "Ratings"
relationship:
one: "Relationship"
other: "Relationships"
series:
one: "Series"
other: "Series"
tag:
one: "Tag"
other: "Tags"
Expand Down Expand Up @@ -108,4 +115,7 @@ en:
external_work:
user_defined_tags_count: "Fandom, relationship, and character tags"
work:
chapter_total_display: "Chapters"
summary: "Summary"
user_defined_tags_count: "Fandom, relationship, character, and additional tags"

2 changes: 1 addition & 1 deletion features/gift_exchanges/challenge_yuletide.feature
Expand Up @@ -574,7 +574,7 @@ Feature: Collection
And the email should contain "A gift work has been posted for you in the"
And the email should contain "Yuletide"
And the email should contain "at the Archive of Our Own"
And the email should contain "by an anonymous responder"
And the email should contain "by Anonymous"
And the email should not contain "by myname1"
And the email should not contain "by myname2"
And the email should not contain "by myname3"
Expand Down
93 changes: 93 additions & 0 deletions spec/helpers/mailer_helper_spec.rb
Expand Up @@ -7,4 +7,97 @@
expect(style_creation_link(work.title, work_url(work))).to eq("<i><b><a style=\"color:#990000\" href=\"#{work_url(work)}\">#{work.title}</a></b></i>")
end
end

describe "#work_metadata_label" do
it "appends the metadata indicator to a string" do
expect(work_metadata_label("Text")).to eq("Text: ")
end
end

describe "#work_tag_metadata" do
{
"Fandom" => ["Fandom: ", "Fandoms: "],
"Rating" => ["Rating: ", "Ratings: "],
"ArchiveWarning" => ["Warning: ", "Warnings: "],
"Relationship" => ["Relationship: ", "Relationships: "],
"Character" => ["Character: ", "Characters: "],
"Freeform" => ["Additional Tag: ", "Additional Tags: "]
}.each_pair do |klass, labels|
context "when given one #{klass.underscore.humanize.downcase.singularize}" do
let(:tag) { create(:tag, type: klass) }
let(:tags) { [tag] }

it "returns \"#{labels[0]}\" followed by the tag name" do
expect(work_tag_metadata(tags)).to eq("#{labels[0]}#{tag.name}")
end
end

context "when given multiple #{klass.underscore.humanize.downcase.pluralize}" do
let(:tag1) { create(:tag, type: klass) }
let(:tag2) { create(:tag, type: klass) }
let(:tags) { [tag1, tag2] }

it "returns \"#{labels[1]}\" followed by a comma-separated list of tag names" do
expect(work_tag_metadata(tags)).to eq("#{labels[1]}#{tag1.name}, #{tag2.name}")
end
end
end
end

describe "#style_work_tag_metadata" do
context "when given one fandom" do
let(:fandom) { create(:fandom) }
let(:fandoms) { [fandom] }

it "returns \"Fandom: \" styled bold and red followed by a link to the fandom" do
label = "<b style=\"color:#990000\">Fandom: </b>"
link = link_to(fandom.name, fandom_url(fandom), style: "color:#990000")
expect(style_work_tag_metadata(fandoms)).to eq("#{label}#{link}")
end
end

context "when given multiple fandoms" do
let(:fandom1) { create(:fandom) }
let(:fandom2) { create(:fandom) }
let(:fandoms) { [fandom1, fandom2] }

it "returns \"Fandoms: \" styled bold and red followed by links to the fandoms combined using to_sentence" do
label = "<b style=\"color:#990000\">Fandoms: </b>"
link1 = link_to(fandom1.name, fandom_url(fandom1), style: "color:#990000")
link2 = link_to(fandom2.name, fandom_url(fandom2), style: "color:#990000")
list = "#{link1} and #{link2}"
expect(style_work_tag_metadata(fandoms)).to eq("#{label}#{list}")
end
end

{
"Rating" => ["Rating:", "Ratings:"],
"ArchiveWarning" => ["Warning:", "Warnings:"],
"Relationship" => ["Relationship:", "Relationships:"],
"Character" => ["Character:", "Characters:"],
"Freeform" => ["Additional Tag:", "Additional Tags:"]
}.each_pair do |klass, labels|
context "when given one #{klass.underscore.humanize.downcase.singularize}" do
let(:tag) { create(:tag, type: klass) }
let(:tags) { [tag] }

it "returns \"#{labels[0]} \" styled bold and red followed by the tag name" do
label = "<b style=\"color:#990000\">#{labels[0]} </b>"
expect(style_work_tag_metadata(tags)).to eq("#{label}#{tag.name}")
end
end

context "when given multiple #{klass.underscore.humanize.downcase.pluralize}" do
let(:tag1) { create(:tag, type: klass) }
let(:tag2) { create(:tag, type: klass) }
let(:tags) { [tag1, tag2] }

it "returns \"#{labels[1]} \" styled bold and red followed by a comma-separated list of tag names" do
label = "<b style=\"color:#990000\">#{labels[1]} </b>"
list = "#{tag1.name}, #{tag2.name}"
expect(style_work_tag_metadata(tags)).to eq("#{label}#{list}")
end
end
end
end
end
6 changes: 5 additions & 1 deletion spec/mailers/user_mailer_spec.rb
Expand Up @@ -783,7 +783,7 @@
subject(:email) { UserMailer.recipient_notification(user.id, work.id, collection.id) }

let(:user) { create(:user) }
let(:work) { create(:work) }
let(:work) { create(:work, fandom_string: "Fandom 1, Fandom 2", character_string: "A, B") }
let(:collection) { create(:collection) }

# Test the headers
Expand All @@ -797,6 +797,8 @@
# Test both body contents
it_behaves_like "a multipart email"

it_behaves_like "a translated email"

describe "HTML version" do
it "has the correct content" do
expect(email).to have_html_part_content("Hi, <b")
Expand Down Expand Up @@ -828,6 +830,8 @@
# Test both body contents
it_behaves_like "a multipart email"

it_behaves_like "a translated email"

describe "HTML version" do
it "has the correct content" do
expect(email).to have_html_part_content("Hi, <b")
Expand Down