Skip to content
This repository has been archived by the owner on Apr 3, 2019. It is now read-only.

Commit

Permalink
Merge pull request #158 from mozilla/issue-155-reset-password-from-ch…
Browse files Browse the repository at this point in the history
…ange-password r=vladikoff,philbooth

fix(mailer): Several mailer fixes
  • Loading branch information
vladikoff committed May 20, 2016
2 parents 069b83e + 864c262 commit a173bac
Show file tree
Hide file tree
Showing 11 changed files with 125 additions and 40 deletions.
48 changes: 28 additions & 20 deletions mailer.js
Expand Up @@ -66,7 +66,11 @@ module.exports = function (log) {
return linkAttributes(this.supportUrl)
}

Mailer.prototype._initiatePasswordChange = function (email) {
Mailer.prototype._passwordResetLinkAttributes = function (email) {
return linkAttributes(this.createPasswordResetLink(email))
}

Mailer.prototype._passwordChangeLinkAttributes = function (email) {
return linkAttributes(this.createPasswordChangeLink(email))
}

Expand Down Expand Up @@ -214,7 +218,7 @@ module.exports = function (log) {
link: link,
oneClickLink: oneClickLink,
passwordChangeLink: this.createPasswordChangeLink(message.email),
passwordChangeLinkAttributes: this._initiatePasswordChange(message.email),
passwordChangeLinkAttributes: this._passwordChangeLinkAttributes(message.email),
supportLinkAttributes: linkAttributes(this.supportUrl),
supportUrl: this.supportUrl
},
Expand Down Expand Up @@ -247,7 +251,7 @@ module.exports = function (log) {
code: message.code,
email: message.email,
link: link,
signInUrl: this.signInUrl,
signInUrl: this.createSignInLink(message.email),
supportUrl: this.supportUrl,
supportLinkAttributes: this._supportLinkAttributes()
},
Expand Down Expand Up @@ -288,7 +292,7 @@ module.exports = function (log) {
}

Mailer.prototype.passwordChangedEmail = function (message) {
var link = this.createPasswordChangeLink(message.email)
var link = this.createPasswordResetLink(message.email)

return this.send({
acceptLanguage: message.acceptLanguage,
Expand All @@ -299,9 +303,8 @@ module.exports = function (log) {
subject: gettext('Your Firefox Account password has been changed'),
template: 'passwordChangedEmail',
templateValues: {
passwordChangeLinkAttributes: this._initiatePasswordChange(message.email),
resetLink: link,
signInUrl: this.signInUrl,
resetLinkAttributes: this._passwordResetLinkAttributes(message.email),
supportLinkAttributes: this._supportLinkAttributes(),
supportUrl: this.supportUrl
},
Expand All @@ -322,16 +325,16 @@ module.exports = function (log) {
template: 'passwordResetEmail',
templateValues: {
resetLink: link,
resetLinkAttributes: this._passwordResetLinkAttributes(message.email),
supportUrl: this.supportUrl,
supportLinkAttributes: this._supportLinkAttributes(),
resetPasswordUrl: this.signInUrl
supportLinkAttributes: this._supportLinkAttributes()
},
uid: message.uid
})
}

Mailer.prototype.passwordResetRequiredEmail = function (message) {
var link = this.createPasswordResetLink(message.email, { reset_password_confirm: false })
var link = this.createPasswordResetLink(message.email)

return this.send({
acceptLanguage: message.acceptLanguage,
Expand Down Expand Up @@ -368,7 +371,7 @@ module.exports = function (log) {
template: 'newDeviceLoginEmail',
templateValues: {
device: this._formatUserAgentInfo(message),
passwordChangeLinkAttributes: this._initiatePasswordChange(message.email),
passwordChangeLinkAttributes: this._passwordChangeLinkAttributes(message.email),
resetLink: link,
supportLinkAttributes: this._supportLinkAttributes(),
supportUrl: this.supportUrl,
Expand All @@ -385,6 +388,8 @@ module.exports = function (log) {
// details at github.com/mozilla/fxa-auth-mailer/issues/110
var postVerifyUtmParams = '?utm_source=email&utm_medium=email&utm_campaign=fx-account-verified'
var link = this.syncUrl + postVerifyUtmParams
var anrdoidLink = this.androidUrl + postVerifyUtmParams
var iosLink = this.iosUrl + postVerifyUtmParams

return this.send({
acceptLanguage: message.acceptLanguage,
Expand All @@ -396,8 +401,10 @@ module.exports = function (log) {
template: 'postVerifyEmail',
templateValues: {
link: link,
androidUrl: this.androidUrl + postVerifyUtmParams,
iosUrl: this.iosUrl + postVerifyUtmParams,
androidUrl: anrdoidLink,
androidLinkAttributes: linkAttributes(anrdoidLink),
iosUrl: iosLink,
iosLinkAttributes: linkAttributes(iosLink),
supportUrl: this.supportUrl,
supportLinkAttributes: this._supportLinkAttributes()
},
Expand All @@ -408,7 +415,7 @@ module.exports = function (log) {
Mailer.prototype.suspiciousLocationEmail = function (message) {
log.trace({ op: 'mailer.suspiciousLocationEmail', email: message.email, uid: message.uid })

var link = this.createPasswordResetLink(message.email, { reset_password_confirm: false })
var link = this.createPasswordResetLink(message.email)

// the helper function `t` references `this.translator`. Because of
// the way Handlebars `each` loops work, a translator instance must be
Expand Down Expand Up @@ -480,13 +487,8 @@ module.exports = function (log) {
})
}

Mailer.prototype.createPasswordResetLink = function (email, extraQueryParams) {
var queryParams = { email: email }
extraQueryParams = extraQueryParams || {}

for (var key in extraQueryParams) {
queryParams[key] = extraQueryParams[key]
}
Mailer.prototype.createPasswordResetLink = function (email) {
var queryParams = { email: email, reset_password_confirm: false }

return this.initiatePasswordResetUrl + '?' + qs.stringify(queryParams)
}
Expand All @@ -497,5 +499,11 @@ module.exports = function (log) {
return this.initiatePasswordChangeUrl + '?' + qs.stringify(queryParams)
}

Mailer.prototype.createSignInLink = function (email) {
var queryParams = { email: email }

return this.signInUrl + '?' + qs.stringify(queryParams)
}

return Mailer
}
23 changes: 20 additions & 3 deletions partials/password_changed.html
@@ -1,4 +1,21 @@
<% extends "partials/base/base_text_only.html" %>
<% extends "partials/base/base.html" %>

<% block heading %>{{t "Password changed successfully"}}<% endblock %>
<% block text_primary %>{{t "Your Firefox Account password has been successfully changed." }}<% endblock %>
<% block content %>
<!--Header Area-->
<tr style="page-break-before: always">
<td valign="top">
<h1 style="font-family: sans-serif; font-weight: normal; margin: 0 0 24px 0; text-align: center;">{{t "Password changed successfully"}}</h1>
<p class="primary" style="font-family: sans-serif; font-size: 14px; font-weight: normal; margin: 0 0 12px 0; text-align: center;">{{t "Your Firefox Account password has been successfully changed." }}</p>
</td>
</tr>

<!--Button Area-->
<tr style="page-break-before: always">
<td border="0" cellpadding="0" cellspacing="0" height="100%" width="100%">
<br/>
<p class="secondary" style="font-family: sans-serif; font-weight: normal; margin: 0 0 12px 0; text-align: center; color: #8A9BA8; font-size: 11px; line-height: 13px; width: 310px !important; word-wrap:break-word">
{{{t "This is an automated email; if you did not authorize this action, then <a %(resetLinkAttributes)s>please reset your password</a>." }}} {{{t "For more information, please visit <a %(supportLinkAttributes)s>Mozilla Support</a>."}}}
</p>
</td>
</tr>
<% endblock %>
2 changes: 1 addition & 1 deletion partials/password_reset.html
Expand Up @@ -5,7 +5,7 @@
<tr style="page-break-before: always">
<td valign="top">
<h3 style="font-family: sans-serif; font-weight: normal; margin: 0 0 24px 0; text-align: center;">{{t "Your password has been reset"}}</h3>
<p class="primary" style="font-family: sans-serif; font-size: 14px; font-weight: normal; margin: 0 0 12px 0; text-align: center;">{{{t "Your Firefox Account password has changed. If you did not change it, please <a href='%(resetLink)s'>reset your password</a> now." }}}</p>
<p class="primary" style="font-family: sans-serif; font-size: 14px; font-weight: normal; margin: 0 0 12px 0; text-align: center;">{{{t "Your Firefox Account password has changed. If you did not change it, please <a %(resetLinkAttributes)s>reset your password</a> now." }}}</p>
</td>
</tr>

Expand Down
2 changes: 1 addition & 1 deletion partials/post_verify.html
Expand Up @@ -5,7 +5,7 @@
<tr style="page-break-before: always">
<td valign="top">
<h1 style="font-family: sans-serif; font-weight: normal; margin: 0 0 24px 0; text-align: center;">{{t "Account verified!" }}</h1>
<p class="primary" style="font-family: sans-serif; font-size: 14px; font-weight: normal; margin: 0 0 24px 0; text-align: center;">{{{t "You successfully connected your first device to your Firefox Account. Now you can sign in to Sync from your other devices, including Firefox for <a href='%(androidUrl)s'>Android</a> and <a href='%(iosUrl)s'>iOS</a>." }}}</p>
<p class="primary" style="font-family: sans-serif; font-size: 14px; font-weight: normal; margin: 0 0 24px 0; text-align: center;">{{{t "You successfully connected your first device to your Firefox Account. Now you can sign in to Sync from your other devices, including Firefox for <a %(androidLinkAttributes)s>Android</a> and <a %(iosLinkAttributes)s>iOS</a>." }}}</p>
</td>
</tr>

Expand Down
3 changes: 2 additions & 1 deletion templates/password_changed.html
Expand Up @@ -24,11 +24,12 @@ <h1 style="font-family: sans-serif; font-weight: normal; margin: 0 0 24px 0; tex
</td>
</tr>

<!--Button Area-->
<tr style="page-break-before: always">
<td border="0" cellpadding="0" cellspacing="0" height="100%" width="100%">
<br/>
<p class="secondary" style="font-family: sans-serif; font-weight: normal; margin: 0 0 12px 0; text-align: center; color: #8A9BA8; font-size: 11px; line-height: 13px; width: 310px !important; word-wrap:break-word">
{{{t "This is an automated email; if you did not authorize this action, then <a %(passwordChangeLinkAttributes)s>please change your password.</a>" }}} {{{t "For more information, please visit <a %(supportLinkAttributes)s>Mozilla Support</a>."}}}
{{{t "This is an automated email; if you did not authorize this action, then <a %(resetLinkAttributes)s>please reset your password</a>." }}} {{{t "For more information, please visit <a %(supportLinkAttributes)s>Mozilla Support</a>."}}}
</p>
</td>
</tr>
Expand Down
2 changes: 1 addition & 1 deletion templates/password_changed.txt
@@ -1,7 +1,7 @@
{{t "Password changed successfully" }}
{{t "Your Firefox Account password has been successfully changed." }}

{{t "This is an automated email; if you didn’t change the password to your Firefox Account, you should reset it immediately at %(resetLink)s." }}
{{{t "This is an automated email; if you didn’t change the password to your Firefox Account, you should reset it immediately at %(resetLink)s." }}}
{{t "For more information, please visit %(supportUrl)s" }}

Mozilla. 331 E Evelyn Ave, Mountain View, CA 94041
Expand Down
2 changes: 1 addition & 1 deletion templates/password_reset.html
Expand Up @@ -20,7 +20,7 @@
<tr style="page-break-before: always">
<td valign="top">
<h3 style="font-family: sans-serif; font-weight: normal; margin: 0 0 24px 0; text-align: center;">{{t "Your password has been reset"}}</h3>
<p class="primary" style="font-family: sans-serif; font-size: 14px; font-weight: normal; margin: 0 0 12px 0; text-align: center;">{{{t "Your Firefox Account password has changed. If you did not change it, please <a href='%(resetLink)s'>reset your password</a> now." }}}</p>
<p class="primary" style="font-family: sans-serif; font-size: 14px; font-weight: normal; margin: 0 0 12px 0; text-align: center;">{{{t "Your Firefox Account password has changed. If you did not change it, please <a %(resetLinkAttributes)s>reset your password</a> now." }}}</p>
</td>
</tr>

Expand Down
4 changes: 1 addition & 3 deletions templates/password_reset.txt
@@ -1,9 +1,7 @@
{{t "Password reset successfully" }}
{{t "Your Firefox Account password has been successfully reset." }}

{{{t "Your Firefox Account password has changed. If you did not change it, please <a href='%(resetLink)s'>reset your password</a> now." }}}

{{t "This is an automated email; if you didn’t reset the password to your Firefox Account, you should reset it immediately at %(resetLink)s." }}
{{{t "This is an automated email; if you didn’t reset the password to your Firefox Account, you should reset it immediately at %(resetLink)s." }}}
{{t "For more information, please visit %(supportUrl)s" }}

Mozilla. 331 E Evelyn Ave, Mountain View, CA 94041
Expand Down
2 changes: 1 addition & 1 deletion templates/post_verify.html
Expand Up @@ -20,7 +20,7 @@
<tr style="page-break-before: always">
<td valign="top">
<h1 style="font-family: sans-serif; font-weight: normal; margin: 0 0 24px 0; text-align: center;">{{t "Account verified!" }}</h1>
<p class="primary" style="font-family: sans-serif; font-size: 14px; font-weight: normal; margin: 0 0 24px 0; text-align: center;">{{{t "You successfully connected your first device to your Firefox Account. Now you can sign in to Sync from your other devices, including Firefox for <a href='%(androidUrl)s'>Android</a> and <a href='%(iosUrl)s'>iOS</a>." }}}</p>
<p class="primary" style="font-family: sans-serif; font-size: 14px; font-weight: normal; margin: 0 0 24px 0; text-align: center;">{{{t "You successfully connected your first device to your Firefox Account. Now you can sign in to Sync from your other devices, including Firefox for <a %(androidLinkAttributes)s>Android</a> and <a %(iosLinkAttributes)s>iOS</a>." }}}</p>
</td>
</tr>

Expand Down
2 changes: 1 addition & 1 deletion templates/reset.txt
@@ -1,7 +1,7 @@
{{t "Forgot your password?"}}

{{{t "Click the button within the next hour to set a new password for your Firefox Account." }}}
{{t "Remember password? Sign in."}}
{{t "Remember password? Sign in."}} {{{ signInUrl }}}
{{t "Reset password"}} {{{link}}}

{{t "This is an automated email; if you received it in error, no action is required."}} {{t "For more information, please visit %(supportUrl)s"}}
Expand Down
75 changes: 68 additions & 7 deletions test/local/mailer_tests.js
Expand Up @@ -27,7 +27,7 @@ var messageTypes = [
'verifyLoginEmail'
]

var typesWithSupportLinks = [
var typesContainSupportLinks = [
'newDeviceLoginEmail',
'passwordChangedEmail',
'passwordResetEmail',
Expand All @@ -38,7 +38,9 @@ var typesWithSupportLinks = [
'verifyEmail'
]

var typesContainConfirmlessPasswordResetLinks = [
var typesContainPasswordResetLinks = [
'passwordChangedEmail',
'passwordResetEmail',
'passwordResetRequiredEmail',
'suspiciousLocationEmail'
]
Expand All @@ -48,6 +50,18 @@ var typesContainPasswordChangeLinks = [
'verifyLoginEmail'
]

var typesContainSignInLinks = [
'recoveryEmail'
]

var typesContainAndroidStoreLinks = [
'postVerifyEmail'
]

var typesContainIOSStoreLinks = [
'postVerifyEmail'
]

function includes(haystack, needle) {
return (haystack.indexOf(needle) > -1)
}
Expand Down Expand Up @@ -76,7 +90,7 @@ P.all(
var supportHtmlLink = new RegExp('<a href="' + config.get('mail').supportUrl + '" style="color: #0095dd; text-decoration: none; font-family: sans-serif;">Mozilla Support</a>')
var supportTextLink = config.get('mail').supportUrl

if (includes(typesWithSupportLinks, type)) {
if (includes(typesContainSupportLinks, type)) {
test(
'test support link is in email template output for ' + type,
function (t) {
Expand All @@ -90,15 +104,15 @@ P.all(
)
}

if (includes(typesContainConfirmlessPasswordResetLinks, type)) {
var confirmlessResetPasswordLink = mailer.createPasswordResetLink(message.email, { reset_password_confirm: false })
if (includes(typesContainPasswordResetLinks, type)) {
var resetPasswordLink = mailer.createPasswordResetLink(message.email)

test(
'reset password link is in email template output for ' + type,
function (t) {
mailer.mailer.sendMail = function (emailConfig) {
t.ok(includes(emailConfig.html, confirmlessResetPasswordLink))
t.ok(includes(emailConfig.text, confirmlessResetPasswordLink))
t.ok(includes(emailConfig.html, resetPasswordLink))
t.ok(includes(emailConfig.text, resetPasswordLink))
t.end()
}
mailer[type](message)
Expand All @@ -121,6 +135,53 @@ P.all(
)
}

if (includes(typesContainAndroidStoreLinks, type)) {
var androidStoreLink = mailer.androidUrl

test(
'Android store link is in email template output for ' + type,
function (t) {
mailer.mailer.sendMail = function (emailConfig) {
t.ok(includes(emailConfig.html, androidStoreLink))
// only the html email contains links to the store
t.end()
}
mailer[type](message)
}
)
}

if (includes(typesContainIOSStoreLinks, type)) {
var iosStoreLink = mailer.iosUrl

test(
'IOS store link is in email template output for ' + type,
function (t) {
mailer.mailer.sendMail = function (emailConfig) {
t.ok(includes(emailConfig.html, iosStoreLink))
// only the html email contains links to the store
t.end()
}
mailer[type](message)
}
)
}

if (includes(typesContainSignInLinks, type)) {
var signInLink = mailer.createSignInLink(message.email)
test(
'sign in link is in email template output for ' + type,
function (t) {
mailer.mailer.sendMail = function (emailConfig) {
t.ok(includes(emailConfig.html, signInLink))
t.ok(includes(emailConfig.text, signInLink))
t.end()
}
mailer[type](message)
}
)
}

if (type === 'verifyLoginEmail') {
test(
'test verify token email',
Expand Down

0 comments on commit a173bac

Please sign in to comment.