From b9a8d87e951e67a036d2c7494bdaecf63f67a548 Mon Sep 17 00:00:00 2001
From: Ridhwana
Date: Mon, 27 Apr 2020 15:18:16 +0200
Subject: [PATCH] [deploy] Refactor to create a helper for the mailer links
(#7502)
* refactor: set the email_from to use in teh defaults
* chore: remove some new lines
* feat: add a mail link helper that can be used in the views
* feat: returns the default if it doesn't understand the parameter
* feat: Quick replacement of links
* feat: allow subject to be passed through
* chore: update all hrefs
* chore: remove rel attribute
* chore: mail link
* update spec
* chore: space
* chore: update some whitespaces and emails
* style
* chore: PR mail_link to email_link and the comment
* feat: PR suggestions for encoding
* feat: use mail_to
---
app/controllers/users_controller.rb | 12 ++----
app/helpers/application_helper.rb | 7 ++++
app/javascript/packs/articleForm.jsx | 4 +-
app/mailers/application_mailer.rb | 6 ++-
app/mailers/digest_mailer.rb | 2 +-
app/mailers/pro_membership_mailer.rb | 2 +-
.../chat_channel_memberships/edit.html.erb | 2 +-
app/views/credits/new.html.erb | 2 +-
.../shared/_authorization_error.html.erb | 2 +-
app/views/events/index.html.erb | 2 +-
app/views/feedback_messages/index.html.erb | 2 +-
.../account_deleted_email.html.erb | 2 +-
.../account_deletion_requested_email.html.erb | 2 +-
app/views/moderations/index.html.erb | 2 +-
.../_notifications_list.html.erb | 2 +-
.../notifications/_tagadjustment.html.erb | 2 +-
app/views/pages/_coc_text.html.erb | 2 +-
app/views/pages/_terms_text.html.erb | 4 +-
app/views/pages/contact.html.erb | 2 +-
app/views/pages/privacy.html.erb | 6 +--
.../_devrel_consult_copy.html.erb | 2 +-
app/views/partnerships/_form.html.erb | 4 +-
.../partnerships/_gold_sponsor_copy.html.erb | 2 +-
.../partnerships/_media_sponsor_copy.html.erb | 2 +-
app/views/partnerships/index.html.erb | 2 +-
app/views/users/_account.html.erb | 4 +-
app/views/users/_publishing_from_rss.html.erb | 2 +-
app/views/users/confirm_destroy.html.erb | 4 +-
app/views/users/edit.html.erb | 2 +-
app/views/videos/new.html.erb | 2 +-
spec/helpers/application_helper_spec.rb | 40 +++++++++++++++++++
31 files changed, 88 insertions(+), 45 deletions(-)
diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb
index 816a3f488..e7bfcc48d 100644
--- a/app/controllers/users_controller.rb
+++ b/app/controllers/users_controller.rb
@@ -309,16 +309,10 @@ class UsersController < ApplicationController
def handle_account_tab
community_name = ApplicationConfig["COMMUNITY_NAME"]
@email_body = <<~HEREDOC
- Hello #{community_name} Team,
- %0A
- %0A
- I would like to delete my account.
- %0A%0A
- You can keep any comments and discussion posts under the Ghost account.
- %0A
- %0A
+ Hello #{community_name} Team,\n
+ I would like to delete my account.\n
+ You can keep any comments and discussion posts under the Ghost account.\n
Regards,
- %0A
YOUR-#{community_name}-USERNAME-HERE
HEREDOC
end
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index 57c427023..de3ab3ce0 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -170,6 +170,13 @@ module ApplicationHelper
"#{start_year} - #{current_year}"
end
+ def email_link(type = :default, text: nil, additional_info: nil)
+ # The allowed types for type is :default, :business, :privacy, and members.
+ # These options can be found in field :email_addresses of models/site_config.rb
+ email = SiteConfig.email_addresses[type] || SiteConfig.email_addresses[:default]
+ mail_to email, text || email, additional_info
+ end
+
# Creates an app internal URL
#
# @note Uses protocol and domain specified in the environment, ensure they are set.
diff --git a/app/javascript/packs/articleForm.jsx b/app/javascript/packs/articleForm.jsx
index 51a488427..33e287b39 100644
--- a/app/javascript/packs/articleForm.jsx
+++ b/app/javascript/packs/articleForm.jsx
@@ -2,7 +2,7 @@ import { h, render } from 'preact';
import { getUserDataAndCsrfToken } from '../chat/util';
import ArticleForm from '../article-form/articleForm';
-HTMLDocument.prototype.ready = new Promise(resolve => {
+HTMLDocument.prototype.ready = new Promise((resolve) => {
if (document.readyState !== 'loading') {
return resolve();
}
@@ -38,5 +38,3 @@ document.ready.then(() => {
}
});
});
-
-
diff --git a/app/mailers/application_mailer.rb b/app/mailers/application_mailer.rb
index 231b44389..3408e36df 100644
--- a/app/mailers/application_mailer.rb
+++ b/app/mailers/application_mailer.rb
@@ -7,10 +7,14 @@ class ApplicationMailer < ActionMailer::Base
helper ApplicationHelper
default(
- from: -> { "#{ApplicationConfig['COMMUNITY_NAME']} Community <#{SiteConfig.email_addresses[:default]}>" },
+ from: -> { email_from("Community") },
template_path: ->(mailer) { "mailers/#{mailer.class.name.underscore}" },
)
+ def email_from(topic)
+ "#{ApplicationConfig['COMMUNITY_NAME']} #{topic} <#{SiteConfig.email_addresses[:default]}>"
+ end
+
def generate_unsubscribe_token(id, email_type)
Rails.application.message_verifier(:unsubscribe).generate(
user_id: id,
diff --git a/app/mailers/digest_mailer.rb b/app/mailers/digest_mailer.rb
index 91e5f590f..65676199f 100644
--- a/app/mailers/digest_mailer.rb
+++ b/app/mailers/digest_mailer.rb
@@ -1,5 +1,5 @@
class DigestMailer < ApplicationMailer
- default from: -> { "#{ApplicationConfig['COMMUNITY_NAME']} Digest <#{SiteConfig.email_addresses[:default]}>" }
+ default from: -> { email_from("Digest") }
def digest_email(user, articles)
@user = user
diff --git a/app/mailers/pro_membership_mailer.rb b/app/mailers/pro_membership_mailer.rb
index 159d1ea42..08e4b4008 100644
--- a/app/mailers/pro_membership_mailer.rb
+++ b/app/mailers/pro_membership_mailer.rb
@@ -1,5 +1,5 @@
class ProMembershipMailer < ApplicationMailer
- default from: -> { "#{ApplicationConfig['COMMUNITY_NAME']} Pro Memberships <#{SiteConfig.email_addresses[:default]}>" }
+ default from: -> { email_from("Pro Memberships") }
def expiring_membership(pro_membership, expiration_date)
@pro_membership = pro_membership
diff --git a/app/views/chat_channel_memberships/edit.html.erb b/app/views/chat_channel_memberships/edit.html.erb
index b83fc4836..7e596c2bc 100644
--- a/app/views/chat_channel_memberships/edit.html.erb
+++ b/app/views/chat_channel_memberships/edit.html.erb
@@ -98,7 +98,7 @@
<% if @membership.role == "mod" %>
-
Questions about Connect Channel moderation? Contact <%= SiteConfig.email_addresses[:default] %>
+
Questions about Connect Channel moderation? Contact <%= email_link %>
<% else %>
Danger Zone
<%= form_for(@membership, html: { method: :delete, onsubmit: "return confirm('Are you absolutely sure you want to leave this channel? This action is permanent.');" }) do |f| %>
diff --git a/app/views/credits/new.html.erb b/app/views/credits/new.html.erb
index 07a496bc7..0822b6f92 100644
--- a/app/views/credits/new.html.erb
+++ b/app/views/credits/new.html.erb
@@ -37,7 +37,7 @@
- Contact <%= SiteConfig.email_addresses[:business] %> for custom bulk pricing and partnerships.
+ Contact <%= email_link(:business, additional_info: { subject: "Custom Bulk Pricing/Partnerships" }) %> for custom bulk pricing and partnerships.
How many credits does one listing cost?
diff --git a/app/views/devise/shared/_authorization_error.html.erb b/app/views/devise/shared/_authorization_error.html.erb
index 37909b928..62f0c0841 100644
--- a/app/views/devise/shared/_authorization_error.html.erb
+++ b/app/views/devise/shared/_authorization_error.html.erb
@@ -25,6 +25,6 @@
<%= flash[:alert] %>
<% end %>
- Please try again below, or contact <%= SiteConfig.email_addresses[:default] %> if this persists.
+ Please try again below, or contact <%= email_link %> if this persists.
<% end %>
diff --git a/app/views/events/index.html.erb b/app/views/events/index.html.erb
index 82a7b0334..c72684c39 100644
--- a/app/views/events/index.html.erb
+++ b/app/views/events/index.html.erb
@@ -30,7 +30,7 @@
<%= community_name %> Events is a series of ongoing talks and workshops designed to cover important topics to help community members level up. Because we have a global community we will be hosting events at varying times so nobody is restricted by time zone. Additionally,
some workshops are repeated multiple times to further account for this.
We have many more planned if you do not see a topic that interests you. Email
- <%= SiteConfig.email_addresses[:members] %> to request a topic. And if you're interested in speaking, please
+ <%= email_link(:members) %> to request a topic. And if you're interested in speaking, please
apply to our CFP.
<% @events.each do |event| %>
diff --git a/app/views/feedback_messages/index.html.erb b/app/views/feedback_messages/index.html.erb
index 684540c5d..c543a323a 100644
--- a/app/views/feedback_messages/index.html.erb
+++ b/app/views/feedback_messages/index.html.erb
@@ -9,7 +9,7 @@
Thank you for your report.
- Questions? Send an email to <%= SiteConfig.email_addresses[:default] %>
+ Questions? Send an email to <%= email_link %>
diff --git a/app/views/mailers/notify_mailer/account_deleted_email.html.erb b/app/views/mailers/notify_mailer/account_deleted_email.html.erb
index f0cea5ba8..ef62413d9 100644
--- a/app/views/mailers/notify_mailer/account_deleted_email.html.erb
+++ b/app/views/mailers/notify_mailer/account_deleted_email.html.erb
@@ -7,7 +7,7 @@
- Contact us at <%= SiteConfig.email_addresses[:default] %> if there is anything more we can help with. π
+ Contact us at <%= email_link %> if there is anything more we can help with. π
diff --git a/app/views/mailers/notify_mailer/account_deletion_requested_email.html.erb b/app/views/mailers/notify_mailer/account_deletion_requested_email.html.erb
index aa1df0d7a..d35112572 100644
--- a/app/views/mailers/notify_mailer/account_deletion_requested_email.html.erb
+++ b/app/views/mailers/notify_mailer/account_deletion_requested_email.html.erb
@@ -8,7 +8,7 @@
- Contact us at <%= SiteConfig.email_addresses[:default] %> if there is anything more we can help with. π
+ Contact us at <%= email_link %> if there is anything more we can help with. π
diff --git a/app/views/moderations/index.html.erb b/app/views/moderations/index.html.erb
index 19ae9df24..56c562c72 100644
--- a/app/views/moderations/index.html.erb
+++ b/app/views/moderations/index.html.erb
@@ -85,7 +85,7 @@
<%= community_name %> Mods
We periodically award some <%= community_name %> members with heightened privileges to help moderate the community.
-
Email <%= SiteConfig.email_addresses[:default] %> if you'd like to be considered right away.
+
Email <%= email_link %> if you'd like to be considered right away.
<% unless user_signed_in? %>
P.S. You are not currently signed in.
<% end %>
diff --git a/app/views/notifications/_notifications_list.html.erb b/app/views/notifications/_notifications_list.html.erb
index a9addee98..c74d4a6f7 100644
--- a/app/views/notifications/_notifications_list.html.erb
+++ b/app/views/notifications/_notifications_list.html.erb
@@ -14,7 +14,7 @@
<% end %>
diff --git a/app/views/notifications/_tagadjustment.html.erb b/app/views/notifications/_tagadjustment.html.erb
index 51cc2da24..68501286b 100644
--- a/app/views/notifications/_tagadjustment.html.erb
+++ b/app/views/notifications/_tagadjustment.html.erb
@@ -23,6 +23,6 @@
<% end %>
Thanks for being part of <%= community_name %>! If you feel like this mod action was a mistake, feel free to contact
-
<%= SiteConfig.email_addresses[:default] %>. π€
+ <%= email_link %>. π€
diff --git a/app/views/pages/_coc_text.html.erb b/app/views/pages/_coc_text.html.erb
index cc8065153..506ee66b9 100644
--- a/app/views/pages/_coc_text.html.erb
+++ b/app/views/pages/_coc_text.html.erb
@@ -31,7 +31,7 @@
Enforcement
Violations of the Code of Conduct may be reported by contacting the team via the
- ">abuse report form or by sending an email to <%= SiteConfig.email_addresses[:default] %>. All reports will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. Further details of specific enforcement policies may be posted separately.
+ ">abuse report form or by sending an email to <%= email_link %>. All reports will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. Further details of specific enforcement policies may be posted separately.
Moderators have the right and responsibility to remove comments or other contributions that are not aligned to this Code of Conduct, or to suspend temporarily or permanently any members for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
Attribution
diff --git a/app/views/pages/_terms_text.html.erb b/app/views/pages/_terms_text.html.erb
index a3d937ed9..c28c0afa0 100644
--- a/app/views/pages/_terms_text.html.erb
+++ b/app/views/pages/_terms_text.html.erb
@@ -76,7 +76,7 @@
Users agree and certify that they have rights to share all content that they post on dev.to β including, but not limited to, information posted in articles, discussions, and comments. This rule applies to prose, code snippets, collections of links, etc. Regardless of citation, users may not post copy and pasted content that does not belong to them. Users assume all risk for the content they post, including someone else's reliance on its accuracy, claims relating to intellectual property, or other legal rights. If you believe that a user has plagiarized content, misrepresented their identity, misappropriated work, or otherwise run afoul of DMCA regulations, please email
- <%= SiteConfig.email_addresses[:default] %>. <%= community_name %> may remove any content users post for any reason.
+ <%= email_link %>. <%= community_name %> may remove any content users post for any reason.
@@ -92,7 +92,7 @@
- All uses of the <%= community_name %> logo, <%= community_name %> badges, brand slogans, iconography, and the like, may only be used with express permission from <%= community_name %>. <%= community_name %> reserves all rights, even if certain assets are included in <%= community_name %> open source projects. Please contact <%= SiteConfig.email_addresses[:default] %> with any questions or to request permission.
+ All uses of the <%= community_name %> logo, <%= community_name %> badges, brand slogans, iconography, and the like, may only be used with express permission from <%= community_name %>. <%= community_name %> reserves all rights, even if certain assets are included in <%= community_name %> open source projects. Please contact <%= email_link %> with any questions or to request permission.
diff --git a/app/views/pages/contact.html.erb b/app/views/pages/contact.html.erb
index 2fb991850..7504279ca 100644
--- a/app/views/pages/contact.html.erb
+++ b/app/views/pages/contact.html.erb
@@ -30,7 +30,7 @@
<%= community_qualified_name %> would love to hear from you!
- Email: <%= SiteConfig.email_addresses[:default] %> π
+ Email: <%= email_link %> π
Twitter: ">@<%= SiteConfig.social_media_handles["twitter"] %> π»
diff --git a/app/views/pages/privacy.html.erb b/app/views/pages/privacy.html.erb
index 6e32e684a..50a8270d8 100644
--- a/app/views/pages/privacy.html.erb
+++ b/app/views/pages/privacy.html.erb
@@ -164,14 +164,14 @@
Deleting Your Personal Information
- You may request deletion of your personal information and account by emailing <%= SiteConfig.email_addresses[:privacy] %>.
+ You may request deletion of your personal information and account by emailing <%= email_link(:privacy) %>.
To protect information from accidental or malicious destruction, we may maintain residual copies for a brief time period. But, if you delete your account, your information and content will be unrecoverable after that time.
Data Portability
- If you would like to request a copy of your user data, please email <%= SiteConfig.email_addresses[:privacy] %>.
+ If you would like to request a copy of your user data, please email <%= email_link(:privacy) %>.
Business Transfers
If we are involved in a merger, acquisition, bankruptcy, reorganization or sale of assets such that your information would be transferred or become subject to a different privacy policy, weβll notify you in advance of any such change.
@@ -182,6 +182,6 @@
Questions
- We welcome feedback about this policy at <%= SiteConfig.email_addresses[:privacy] %>.
+ We welcome feedback about this policy at <%= email_link(:privacy) %>.
diff --git a/app/views/partnerships/_devrel_consult_copy.html.erb b/app/views/partnerships/_devrel_consult_copy.html.erb
index e25b7495d..999d2fd31 100644
--- a/app/views/partnerships/_devrel_consult_copy.html.erb
+++ b/app/views/partnerships/_devrel_consult_copy.html.erb
@@ -11,5 +11,5 @@ The <%= community_name %> team sees over 1000 new posts published every week to
You will be invited to a shared Slack channel to aid communication and provide a line of communication for deep collaboration. It is an open line to our devrel experts available during extended US East business hours.
<% unless user_signed_in? %>
-
+ Email <%= email_link(:business) %> for pricing information
<% end %>
diff --git a/app/views/partnerships/_form.html.erb b/app/views/partnerships/_form.html.erb
index 4657a3993..0c7f91649 100644
--- a/app/views/partnerships/_form.html.erb
+++ b/app/views/partnerships/_form.html.erb
@@ -50,7 +50,7 @@
<%# this should never happen but better safe than sorry %>
<% sponsorships.each do |sponsorship| %>
- π You are already subscribed as a <%= sponsorship.level %> sponsor. Contact <%= SiteConfig.email_addresses[:business] %> to change plans.
+ π You are already subscribed as a <%= sponsorship.level %> sponsor. Contact <%= email_link(:business) %>to change plans.
<% end %>
<% else %>
@@ -120,5 +120,5 @@
<% end %>
<% end %>
<% else %>
-Contact <%= SiteConfig.email_addresses[:business] %> to sign up
+Contact <%= email_link(:business) %> to sign up
<% end %>
diff --git a/app/views/partnerships/_gold_sponsor_copy.html.erb b/app/views/partnerships/_gold_sponsor_copy.html.erb
index 95120d5e3..7de30366a 100644
--- a/app/views/partnerships/_gold_sponsor_copy.html.erb
+++ b/app/views/partnerships/_gold_sponsor_copy.html.erb
@@ -40,5 +40,5 @@ It will also include a call-to-action to follow your organization directly in th
As a Gold sponsor, you will receive special flair that lives on your organization page. This visual cue will show the <%= community_name %> Community and broader ecosystem that you are an important community supporter, providing a natural draw for increased engagement on the platform. And, of course, youβll have bragging rights and company pride knowing that youβre supporting a wonderful community.
<% unless user_signed_in? %>
-
+ Email <%= email_link(:business) %> for pricing information
<% end %>
diff --git a/app/views/partnerships/_media_sponsor_copy.html.erb b/app/views/partnerships/_media_sponsor_copy.html.erb
index 0074ffdaf..ac2e05720 100644
--- a/app/views/partnerships/_media_sponsor_copy.html.erb
+++ b/app/views/partnerships/_media_sponsor_copy.html.erb
@@ -22,5 +22,5 @@ Sponsorship video insertion
As a media sponsor, your company will be included in all relevant sections around the content. For instance, in the <%= community_name %> post, in social media postings, email announcements, etc.
<% unless user_signed_in? %>
-
+ Email <%= email_link(:business) %> for pricing information
<% end %>
diff --git a/app/views/partnerships/index.html.erb b/app/views/partnerships/index.html.erb
index 7283b3139..15cdc5a03 100644
--- a/app/views/partnerships/index.html.erb
+++ b/app/views/partnerships/index.html.erb
@@ -111,6 +111,6 @@
-
+
Questions about anything?
Email <%= email_link(:business) %>
diff --git a/app/views/users/_account.html.erb b/app/views/users/_account.html.erb
index 74451a107..1d0cae238 100644
--- a/app/views/users/_account.html.erb
+++ b/app/views/users/_account.html.erb
@@ -103,10 +103,10 @@
<% if current_user.articles_count.positive? || current_user.comments_count.positive? %>
If you would like to keep your content under the <%= link_to "@ghost", "/ghost" %> account,
- please click here.
+ please <%= email_link(text: "click here", additional_info: { subject: "Request Account Deletion", body: @email_body }) %>.
<% end %>
- Feel free to contact <%= SiteConfig.email_addresses[:default] %> with any questions.
+ Feel free to contact <%= email_link %> with any questions.
diff --git a/app/views/users/_publishing_from_rss.html.erb b/app/views/users/_publishing_from_rss.html.erb
index 6cf883aeb..d6fb1b9f8 100644
--- a/app/views/users/_publishing_from_rss.html.erb
+++ b/app/views/users/_publishing_from_rss.html.erb
@@ -22,7 +22,7 @@
Your feed will be fetched every time you submit this form and updates will be automatically fetched periodically thereafter. Contact
- <%= SiteConfig.email_addresses[:default] %> if you encounter issues.
+ <%= email_link %> if you encounter issues.
FYI: Medium RSS feed URLs are https://medium.com/feed/@your_username
By submitting your RSS Feed URL, you agree that you own and/or have permission to syndicate the associated content.
diff --git a/app/views/users/confirm_destroy.html.erb b/app/views/users/confirm_destroy.html.erb
index a62acf5fc..7c6969e9f 100644
--- a/app/views/users/confirm_destroy.html.erb
+++ b/app/views/users/confirm_destroy.html.erb
@@ -45,11 +45,11 @@
If you would like to keep your content under the <%= link_to "@ghost", "/ghost" %> account,
- please click here.
+ please <%= email_link(text: "click here", additional_info: { subject: "Request Account Deletion", body: @email_body }) %>
- Feel free to contact <%= SiteConfig.email_addresses[:default] %> with any questions.
+ Feel free to contact <%= email_link %> with any questions.
diff --git a/app/views/users/edit.html.erb b/app/views/users/edit.html.erb
index a6a3e834f..faaa9ced6 100644
--- a/app/views/users/edit.html.erb
+++ b/app/views/users/edit.html.erb
@@ -15,7 +15,7 @@
<% if params[:state] == "previous-registration" %>
<% end %>
diff --git a/app/views/videos/new.html.erb b/app/views/videos/new.html.erb
index fe8dbcfcd..7dc0f5f31 100644
--- a/app/views/videos/new.html.erb
+++ b/app/views/videos/new.html.erb
@@ -33,7 +33,7 @@
<% end %>
diff --git a/spec/helpers/application_helper_spec.rb b/spec/helpers/application_helper_spec.rb
index 3e974c8be..d57f47b3a 100644
--- a/spec/helpers/application_helper_spec.rb
+++ b/spec/helpers/application_helper_spec.rb
@@ -107,4 +107,44 @@ RSpec.describe ApplicationHelper, type: :helper do
expect(sanitized_referer("")).to be nil
end
end
+
+ describe "#email_link" do
+ before do
+ allow(SiteConfig).to receive(:email_addresses).and_return(
+ {
+ default: "hi@dev.to",
+ business: "business@dev.to",
+ privacy: "privacy@dev.to",
+ members: "members@dev.to"
+ },
+ )
+ end
+
+ it "returns an 'a' tag" do
+ expect(helper.email_link).to have_selector("a")
+ end
+
+ it "sets the correct href" do
+ expect(helper.email_link).to have_link(href: "mailto:hi@dev.to")
+ expect(helper.email_link(:business)).to have_link(href: "mailto:business@dev.to")
+ end
+
+ it "has the correct text in the a tag" do
+ expect(helper.email_link(text: "Link Name")).to have_text("Link Name")
+ expect(helper.email_link).to have_text("hi@dev.to")
+ end
+
+ it "returns the default email if it doesn't understand the type parameter" do
+ expect(helper.email_link(:nonsense)).to have_link(href: "mailto:hi@dev.to")
+ end
+
+ it "returns an href with additional_info parameters" do
+ additional_info = {
+ subject: "This is a long subject",
+ body: "This is a longer body with a question mark ? \n and a newline"
+ }
+
+ expect(email_link(text: "text", additional_info: additional_info)).to eq("text")
+ end
+ end
end
- If you see too many of these, please report it to <%= SiteConfig.email_addresses[:default] %>! + If you see too many of these, please report it to <%= email_link %>!