• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mozilla / blurts-server / #13283

pending completion
#13283

push

circleci

Vinnl
Add a maximum width for email address

On large viewports, we don't want the hero content part to
endlessly grow if the user's email address happens to be
ridiculously long. This change limits it to a reasonable size that
maintains readability for the regular content, and truncates the
email address if it is wider than that.

282 of 1679 branches covered (16.8%)

Branch coverage included in aggregate %.

959 of 4548 relevant lines covered (21.09%)

1.76 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/controllers/email-l10n.js
1
'use strict'
2

3
const EmailUtils = require('../email-utils')
×
4
const AppConstants = require('../app-constants')
×
5
const path = require('path')
×
6
const { readFile } = require('fs/promises')
×
7

8
const partials = ['alert', 'report', 'email_verify', 'email-monthly-unresolved']
×
9
const mockBreaches = ['Dropbox', 'Apollo', 'Adobe']
×
10
const mockBreachStats = {
×
11
  passwords: {
12
    count: 1,
13
    numResolved: 0
14
  },
15
  numBreaches: {
16
    count: 2,
17
    numResolved: 0,
18
    numUnresolved: 2
19
  },
20
  monitoredEmails: {
21
    count: 2
22
  }
23
}
24

25
async function getEmailMockup (req, res) {
26
  if (!['dev', 'heroku', 'stage'].includes(AppConstants.NODE_ENV)) return res.sendStatus(404)
×
27

28
  if (!req.query.partial) {
×
29
    return res.redirect('/email-l10n/?partial=email_verify&type=email_verify') // default when no specific partial requested
×
30
  } else if (!partials.includes(req.query.partial)) {
×
31
    return res.sendStatus(404) // requested partial is not in partials list
×
32
  }
33

34
  const emailStr = await readFile(path.resolve('views/layouts/email-2022.hbs'), { encoding: 'utf-8' })
×
35
  const emailStyle = emailStr.substring(emailStr.indexOf('<style>'), emailStr.indexOf('</style>') + 8)
×
36
  const { unsafeBreachesForEmail, emailSubject, breachAlert, unsubscribeUrl, heading, subheading } = getPartialData(req.query.type, req.app.locals.breaches)
×
37
  const utmCampaign = req.query.type
×
38

39
  res.render('email_l10n', {
×
40
    layout: 'email_l10n_mockups.hbs',
41
    unsafeBreachesForEmail,
42
    supportedLocales: req.supportedLocales,
43
    whichPartial: `email_partials/${req.query.partial}`,
44
    partialType: req.query.type,
45
    breachedEmail: req.user?.primary_email || 'breachedEmail@testing.com',
×
46
    breachAlert,
47
    emailSubject: req.fluentFormat(emailSubject),
48
    heading: req.fluentFormat(heading),
49
    subheading: req.fluentFormat(subheading),
50
    ctaHref: EmailUtils.getEmailCtaHref(utmCampaign, 'dashboard-cta'),
51
    utmCampaign,
52
    emailStyle,
53
    unsubscribeUrl,
54
    csrfToken: req.csrfToken(),
55
    breachStats: mockBreachStats
56
  })
57
}
58

59
function getPartialData (partialType, breaches) {
60
  const unsafeBreachesForEmail = []
×
61
  let emailSubject, breachAlert, unsubscribeUrl, heading, subheading
62

63
  switch (partialType) {
×
64
    case 'email_verify':
65
      emailSubject = 'email-subject-verify'
×
66
      heading = 'email-verify-heading'
×
67
      subheading = 'email-verify-subhead'
×
68
      break
×
69
    case 'noBreaches':
70
      emailSubject = 'email-subject-no-breaches'
×
71
      heading = 'email-breach-summary'
×
72
      break
×
73
    case 'singleBreach':
74
      emailSubject = 'email-subject-found-breaches'
×
75
      heading = 'email-breach-summary'
×
76
      unsafeBreachesForEmail.push(breaches.find(breach => breach.Name === mockBreaches[0]))
×
77
      break
×
78
    case 'multipleBreaches':
79
      emailSubject = 'email-subject-found-breaches'
×
80
      heading = 'email-breach-summary'
×
81
      mockBreaches.forEach(name => {
×
82
        unsafeBreachesForEmail.push(breaches.find(breach => breach.Name === name))
×
83
      })
84
      break
×
85
    case 'alert':
86
      emailSubject = 'breach-alert-subject'
×
87
      heading = 'email-spotted-new-breach'
×
88
      breachAlert = breaches.find(breach => breach.Name === 'LinkedIn')
×
89
      break
×
90
    case 'email-monthly-unresolved':
91
      emailSubject = 'email-unresolved-heading'
×
92
      heading = 'email-unresolved-heading'
×
93
      subheading = 'email-unresolved-subhead'
×
94
      unsubscribeUrl = 'fakeunsubscribe.test.com'
×
95
      break
×
96
  }
97

98
  return { unsafeBreachesForEmail, emailSubject, breachAlert, unsubscribeUrl, heading, subheading }
×
99
}
100

101
async function sendTestEmail (req, res) {
102
  const { unsafeBreachesForEmail, emailSubject, breachAlert, heading, subheading } = getPartialData(req.body.partialType, req.app.locals.breaches)
×
103
  const supportedLocales = req.supportedLocales
×
104

105
  const unsubscribeUrl = EmailUtils.getMonthlyUnsubscribeUrl(req.user, 'monthly-unresolved', 'unsubscribe-cta')
×
106
  const utmCampaign = req.body.partialType
×
107
  const context = {
×
108
    whichPartial: req.body.whichPartial,
109
    supportedLocales,
110
    heading: req.fluentFormat(heading),
111
    subheading: req.fluentFormat(subheading),
112
    breachedEmail: req.user.primary_email,
113
    unsafeBreachesForEmail,
114
    breachAlert,
115
    breachStats: req.user.breach_stats,
116
    unsubscribeUrl,
117
    ctaHref: EmailUtils.getEmailCtaHref(utmCampaign, 'dashboard-cta'),
118
    utmCampaign
119
  }
120

121
  await EmailUtils.sendEmail(req.body.recipientEmail, req.fluentFormat(emailSubject), 'email-2022', context)
×
122

123
  res.send(`
×
124
    <h2>Email sent!</h2>
125
    <a href='/email-l10n/'>Go Back</a> | <a href='/user/logout'>Sign Out</a>
126
    `)
127
}
128

129
function notFound (req, res) {
130
  res.status(404)
×
131
  res.render('subpage', {
×
132
    analyticsID: 'error',
133
    headline: req.fluentFormat('error-headline'),
134
    subhead: req.fluentFormat('home-not-found')
135
  })
136
}
137

138
module.exports = {
×
139
  getEmailMockup,
140
  notFound,
141
  sendTestEmail
142
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc