fix(project): move mailer files into proper directories (#1676) r=vladikoff
This commit is contained in:
Родитель
0c52a7cf06
Коммит
d09759cee8
|
@ -17,5 +17,5 @@ secret*
|
|||
/.vagrant
|
||||
.nyc_output
|
||||
npm-debug.log
|
||||
mailer/server.pot
|
||||
mailer/.mail_output
|
||||
server.pot
|
||||
.mail_output
|
||||
|
|
3
.nsprc
3
.nsprc
|
@ -1,4 +1,7 @@
|
|||
{
|
||||
"exceptions": [
|
||||
// i18n-abide@0.0.25
|
||||
"https://nodesecurity.io/advisories/39",
|
||||
"https://nodesecurity.io/advisories/48"
|
||||
]
|
||||
}
|
||||
|
|
|
@ -46,10 +46,7 @@ script:
|
|||
- COVERALLS_REPO_TOKEN=vKN3jjhAOwxkv9HG0VBX4EYIlWLPwiJ9d npm test
|
||||
- npm run test-e2e
|
||||
# Test fxa-auth-mailer
|
||||
- cd mailer
|
||||
- grunt templates
|
||||
- npm test
|
||||
- grunt l10n-extract
|
||||
- cd ..
|
||||
# NSP check
|
||||
- grunt nsp
|
||||
|
|
|
@ -5,7 +5,12 @@
|
|||
module.exports = function (grunt) {
|
||||
require('load-grunt-tasks')(grunt)
|
||||
|
||||
grunt.initConfig({
|
||||
pkg: grunt.file.readJSON('package.json')
|
||||
})
|
||||
|
||||
grunt.loadTasks('grunttasks')
|
||||
|
||||
grunt.registerTask('default', ['eslint', 'copyright'])
|
||||
grunt.registerTask('mailer', ['templates', 'copy:strings', 'l10n-extract'])
|
||||
}
|
||||
|
|
|
@ -3,9 +3,9 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
var restify = require('restify')
|
||||
var config = require('../config')
|
||||
var config = require('../mailer/config')
|
||||
|
||||
var log = require('../log')('server')
|
||||
var log = require('../lib/senders/log')('server')
|
||||
var mailConfig = config.get('mail')
|
||||
|
||||
var packageJson = require('../package.json')
|
||||
|
@ -13,16 +13,16 @@ var P = require('bluebird')
|
|||
|
||||
// NOTE: Mailer is also used by fxa-auth-server directly with an old logging interface
|
||||
// the legacy log module provides an interface to convert old logs to new mozlog logging.
|
||||
var mailerLog = require('../log')('mailer')
|
||||
var legacyMailerLog = require('../legacy_log')(mailerLog)
|
||||
var Mailer = require('../mailer')(legacyMailerLog)
|
||||
var mailerLog = require('../lib/senders/log')('mailer')
|
||||
var legacyMailerLog = require('../lib/senders/legacy_log')(mailerLog)
|
||||
var Mailer = require('../lib/senders/email')(legacyMailerLog)
|
||||
|
||||
var dbConnect = require('../lib/db_connect')()
|
||||
var dbConnect = require('../lib/senders/db_connect')()
|
||||
|
||||
P.all(
|
||||
[
|
||||
require('../translator')(config.get('locales'), config.get('defaultLanguage')),
|
||||
require('../templates')()
|
||||
require('../lib/senders/translator')(config.get('locales'), config.get('defaultLanguage')),
|
||||
require('../lib/senders/templates')()
|
||||
]
|
||||
)
|
||||
.spread(
|
||||
|
@ -35,7 +35,7 @@ P.all(
|
|||
dbConnect()
|
||||
.then(function (db) {
|
||||
// fetch and process verification reminders
|
||||
var verificationReminders = require('../lib/verification-reminders')(mailer, db)
|
||||
var verificationReminders = require('../lib/senders/verification-reminders')(mailer, db)
|
||||
verificationReminders.poll()
|
||||
})
|
||||
.catch(function (err) {
|
|
@ -13,7 +13,7 @@ module.exports = function (grunt) {
|
|||
bumpVersion: true,
|
||||
commit: true,
|
||||
commitMessage: 'Release v%VERSION%',
|
||||
commitFiles: ['package.json', 'npm-shrinkwrap.json', 'CHANGELOG.md'],
|
||||
commitFiles: ['package.json', 'npm-shrinkwrap.json', 'CHANGELOG.md', 'AUTHORS'],
|
||||
createTag: true,
|
||||
tagName: 'v%VERSION%',
|
||||
tagMessage: 'Version %VERSION%',
|
||||
|
|
|
@ -30,7 +30,7 @@ module.exports = function (grunt) {
|
|||
var done = this.async()
|
||||
|
||||
var walker = extract({
|
||||
'input-dir': path.join(pkgroot, 'templates'),
|
||||
'input-dir': path.join(pkgroot, 'lib/senders/templates'),
|
||||
'output-dir': pkgroot,
|
||||
'output': 'server.pot',
|
||||
'join-existing': true,
|
||||
|
@ -43,12 +43,7 @@ module.exports = function (grunt) {
|
|||
|
||||
walker.on('end', function () {
|
||||
var jsWalker = extract({
|
||||
'input-dir': pkgroot,
|
||||
/* node_modules and test should not contain any strings
|
||||
* Gruntfile causes an error and should contain no strings
|
||||
* bin/server.js extracts "/", so it is excluded.
|
||||
*/
|
||||
exclude: /(node_modules|test|Gruntfile|grunttasks|bin|scripts|\.git|config)/,
|
||||
'input-dir': path.join(pkgroot, 'lib/senders'),
|
||||
'output-dir': pkgroot,
|
||||
'output': 'server.pot',
|
||||
'join-existing': true,
|
|
@ -9,6 +9,7 @@ module.exports = function (grunt) {
|
|||
|
||||
grunt.config('nunjucks', {
|
||||
options: {
|
||||
paths: 'lib/senders/',
|
||||
tags: {
|
||||
blockStart: '<%',
|
||||
blockEnd: '%>',
|
||||
|
@ -23,9 +24,9 @@ module.exports = function (grunt) {
|
|||
files: [
|
||||
{
|
||||
expand: true,
|
||||
cwd: 'partials/',
|
||||
cwd: 'lib/senders/partials/',
|
||||
src: '*.html',
|
||||
dest: 'templates/',
|
||||
dest: 'lib/senders/templates/',
|
||||
ext: '.html'
|
||||
}
|
||||
]
|
|
@ -2,9 +2,9 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
var butil = require('./crypto/butil')
|
||||
var log = require('../log')('db')
|
||||
var P = require('./promise')
|
||||
var butil = require('../crypto/butil')
|
||||
var log = require('./log')('db')
|
||||
var P = require('../promise')
|
||||
var Pool = require('./pool')
|
||||
var qs = require('querystring')
|
||||
|
||||
|
@ -40,7 +40,7 @@ module.exports = function () {
|
|||
.then(
|
||||
function (body) {
|
||||
var data = bufferize(body)
|
||||
data.emailVerified = !!data.emailVerified
|
||||
data.emailVerified = !! data.emailVerified
|
||||
return data
|
||||
},
|
||||
function (err) {
|
||||
|
@ -55,7 +55,7 @@ module.exports = function () {
|
|||
.then(
|
||||
function (body) {
|
||||
var data = bufferize(body)
|
||||
data.emailVerified = !!data.emailVerified
|
||||
data.emailVerified = !! data.emailVerified
|
||||
return data
|
||||
},
|
||||
function (err) {
|
|
@ -3,8 +3,8 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
var P = require('bluebird')
|
||||
var config = require('../config')
|
||||
var log = require('../log')('db')
|
||||
var config = require('../../mailer/config')
|
||||
var log = require('./log')('db')
|
||||
|
||||
var DB = require('./db')()
|
||||
|
||||
|
@ -29,10 +29,10 @@ module.exports = function () {
|
|||
function (err) {
|
||||
if (err && err.message && err.message.indexOf('ECONNREFUSED') > -1) {
|
||||
log.warn('db', {message: 'Failed to connect to database, retrying...'})
|
||||
if (!cancelled) {
|
||||
if (! cancelled) {
|
||||
return P.delay(dbConnectionRetry)
|
||||
.then(function () {
|
||||
if (!cancelled) {
|
||||
if (! cancelled) {
|
||||
return dbConnectPoll()
|
||||
}
|
||||
})
|
||||
|
@ -51,7 +51,7 @@ module.exports = function () {
|
|||
// report any errors to the db log and rethrow it to the consumer.
|
||||
log.error('db', {err: err})
|
||||
throw err
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
return dbConnect
|
|
@ -4,11 +4,16 @@
|
|||
|
||||
'use strict'
|
||||
|
||||
const P = require('./promise')
|
||||
const createSenders = require('../mailer/index')
|
||||
var P = require('../promise')
|
||||
// This indirection exists to accommodate different config properties
|
||||
// in the old auth mailer. If/when the two config files are merged and
|
||||
// there's nothing left that imports mailer/config, it is safe to merge
|
||||
// raw.js and this file into one. Be careful not to mix the arguments
|
||||
// up when you do that, they expect config and log in a different order.
|
||||
var createSenders = require('./legacy_index')
|
||||
|
||||
module.exports = (config, log) => {
|
||||
const defaultLanguage = config.i18n.defaultLanguage
|
||||
module.exports = function (config, log) {
|
||||
var defaultLanguage = config.i18n.defaultLanguage
|
||||
|
||||
return createSenders(
|
||||
log,
|
||||
|
@ -20,8 +25,8 @@ module.exports = (config, log) => {
|
|||
}
|
||||
)
|
||||
.then(
|
||||
senders => {
|
||||
const mailer = senders.email
|
||||
function (senders) {
|
||||
var mailer = senders.email
|
||||
mailer.sendVerifyCode = function (account, code, opts) {
|
||||
return P.resolve(mailer.verifyEmail(
|
||||
{
|
|
@ -2,9 +2,16 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
var P = require('bluebird')
|
||||
var createMailer = require('./mailer')
|
||||
var createSms = require('./lib/sms')
|
||||
// This module exists because some files still use the old mailer config.
|
||||
// Those files should import this module rather than its sibling index.js.
|
||||
// If/when we eliminate the old mailer config and everything is importing
|
||||
// index.js, we can merge this into there and get rid of the indirection.
|
||||
// Be careful when doing that btw, they expect the log and config arguments
|
||||
// in a different order.
|
||||
|
||||
var P = require('../promise')
|
||||
var createMailer = require('./email')
|
||||
var createSms = require('./sms')
|
||||
|
||||
module.exports = function (log, config, sender) {
|
||||
var Mailer = createMailer(log)
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
var mozlog = require('mozlog')
|
||||
|
||||
var logConfig = require('./config').get('logging')
|
||||
var logConfig = require('../../mailer/config').get('logging')
|
||||
|
||||
mozlog.config(logConfig)
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
var P = require('./promise')
|
||||
var P = require('../promise')
|
||||
var Poolee = require('poolee')
|
||||
|
||||
function parseUrl(url) {
|
|
@ -16,7 +16,7 @@ module.exports = function (log, translator, templates, smsConfig) {
|
|||
apiKey: smsConfig.apiKey,
|
||||
apiSecret: smsConfig.apiSecret
|
||||
})
|
||||
var sendSms = P.promisify(nexmo.message.sendSms, { context: nexmo.message })
|
||||
var sendSms = P.promisify(nexmo.message.sendSms, nexmo.message)
|
||||
|
||||
return {
|
||||
send: function (phoneNumber, senderId, messageId, acceptLanguage) {
|
|
@ -1,3 +1,7 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
var path = require('path')
|
||||
var P = require('bluebird')
|
||||
var handlebars = require('handlebars')
|
|
@ -1,3 +1,7 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
var path = require('path')
|
||||
var i18n = require('i18n-abide')
|
||||
var Jed = require('jed')
|
||||
|
@ -14,7 +18,7 @@ module.exports = function (locales, defaultLanguage) {
|
|||
return poParseFile(
|
||||
path.join(
|
||||
__dirname,
|
||||
'node_modules/fxa-content-server-l10n/locale',
|
||||
'../../node_modules/fxa-content-server-l10n/locale',
|
||||
i18n.normalizeLocale(locale),
|
||||
'LC_MESSAGES/server.po'
|
||||
),
|
|
@ -2,9 +2,9 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
var logger = require('../log')('verification-reminders')
|
||||
var P = require('./promise')
|
||||
var config = require('../config')
|
||||
var logger = require('./log')('verification-reminders')
|
||||
var P = require('../promise')
|
||||
var config = require('../../mailer/config')
|
||||
var reminderConfig = config.get('verificationReminders')
|
||||
|
||||
module.exports = function (mailer, db, options) {
|
||||
|
@ -22,25 +22,25 @@ module.exports = function (mailer, db, options) {
|
|||
* @private
|
||||
*/
|
||||
_processReminder: function (reminderData) {
|
||||
log.debug('_processReminder', reminderData)
|
||||
log.debug('_processReminder', reminderData)
|
||||
|
||||
return db.account(reminderData.uid)
|
||||
.then(function (account) {
|
||||
if (! account.emailVerified) {
|
||||
// if account is not verified then send the reminder
|
||||
mailer.verificationReminderEmail({
|
||||
email: account.email,
|
||||
uid: account.uid.toString('hex'),
|
||||
code: account.emailCode.toString('hex'),
|
||||
type: reminderData.type,
|
||||
acceptLanguage: account.locale
|
||||
})
|
||||
} else {
|
||||
log.debug('_processReminder', { msg: 'Already Verified' })
|
||||
}
|
||||
}, function (err) {
|
||||
log.error('_processReminder', { err: err })
|
||||
})
|
||||
return db.account(reminderData.uid)
|
||||
.then(function (account) {
|
||||
if (! account.emailVerified) {
|
||||
// if account is not verified then send the reminder
|
||||
mailer.verificationReminderEmail({
|
||||
email: account.email,
|
||||
uid: account.uid.toString('hex'),
|
||||
code: account.emailCode.toString('hex'),
|
||||
type: reminderData.type,
|
||||
acceptLanguage: account.locale
|
||||
})
|
||||
} else {
|
||||
log.debug('_processReminder', { msg: 'Already Verified' })
|
||||
}
|
||||
}, function (err) {
|
||||
log.error('_processReminder', { err: err })
|
||||
})
|
||||
},
|
||||
_continuousPoll: function () {
|
||||
var self = this
|
|
@ -1,5 +0,0 @@
|
|||
node_modules
|
||||
server.pot
|
||||
*.log
|
||||
.mail_output
|
||||
.nyc_output
|
|
@ -1,19 +0,0 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
module.exports = function (grunt) {
|
||||
'use strict'
|
||||
|
||||
require('load-grunt-tasks')(grunt)
|
||||
|
||||
grunt.initConfig({
|
||||
pkg: grunt.file.readJSON('package.json')
|
||||
})
|
||||
|
||||
grunt.loadTasks('grunttasks')
|
||||
|
||||
grunt.registerTask('default', [ 'templates', 'copy:strings', 'l10n-extract' ])
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
// takes care of bumping the version number in package.json
|
||||
|
||||
module.exports = function (grunt) {
|
||||
grunt.config('bump', {
|
||||
options: {
|
||||
files: [ 'package.json', 'npm-shrinkwrap.json' ],
|
||||
bumpVersion: true,
|
||||
commit: true,
|
||||
commitMessage: 'Release v%VERSION%',
|
||||
commitFiles: ['package.json', 'npm-shrinkwrap.json', 'CHANGELOG.md', 'AUTHORS'],
|
||||
createTag: true,
|
||||
tagName: 'v%VERSION%',
|
||||
tagMessage: 'Version %VERSION%',
|
||||
push: false,
|
||||
pushTo: 'origin',
|
||||
gitDescribeOptions: '--tags --always --abrev=1 --dirty=-d'
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
var fxaChangelog = require('fxa-conventional-changelog')()
|
||||
|
||||
module.exports = function (grunt) {
|
||||
grunt.config('conventionalChangelog', {
|
||||
options: {
|
||||
changelogOpts: {},
|
||||
parserOpts: fxaChangelog.parserOpts,
|
||||
writerOpts: fxaChangelog.writerOpts
|
||||
},
|
||||
release: {
|
||||
src: 'CHANGELOG.md'
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
module.exports = function (grunt) {
|
||||
'use strict'
|
||||
|
||||
grunt.config('eslint', {
|
||||
options: {
|
||||
eslintrc: '.eslintrc'
|
||||
},
|
||||
app: [
|
||||
'*.js', 'bin/*.js', 'grunttasks/*.js', 'templates/*.js', 'test/**/*.js', 'scripts/**/*.js'
|
||||
]
|
||||
})
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
// meta grunt task to run other linters.
|
||||
|
||||
module.exports = function (grunt) {
|
||||
|
||||
var SUBTASKS = [
|
||||
'eslint'
|
||||
]
|
||||
|
||||
grunt.registerTask('lint', 'lint all the things', SUBTASKS)
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
// A task to stamp a new version.
|
||||
//
|
||||
// * version is updated in package.json
|
||||
// * CHANGELOG.md updated with changes since last version
|
||||
// * git tag with version name is created.
|
||||
// * git commit with updated package.json and CHANGELOG.md created.
|
||||
|
||||
module.exports = function (grunt) {
|
||||
grunt.registerTask('version', [
|
||||
'bump-only:minor',
|
||||
'conventionalChangelog',
|
||||
'bump-commit'
|
||||
])
|
||||
|
||||
grunt.registerTask('version:patch', [
|
||||
'bump-only:patch',
|
||||
'conventionalChangelog',
|
||||
'bump-commit'
|
||||
])
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
var HEX = /^(?:[a-fA-F0-9]{2})+$/
|
||||
|
||||
module.exports.unbuffer = function unbuffer(object, inplace) {
|
||||
var keys = Object.keys(object)
|
||||
var copy = inplace ? object : {}
|
||||
for (var i = 0; i < keys.length; i++) {
|
||||
var x = object[keys[i]]
|
||||
copy[keys[i]] = Buffer.isBuffer(x) ? x.toString('hex') : x
|
||||
}
|
||||
return copy
|
||||
}
|
||||
|
||||
module.exports.bufferize = function bufferize(object, options) {
|
||||
var keys = Object.keys(object)
|
||||
options = options || {}
|
||||
var copy = options.inplace ? object : {}
|
||||
var ignore = options.ignore || []
|
||||
for (var i = 0; i < keys.length; i++) {
|
||||
var key = keys[i]
|
||||
var value = object[key]
|
||||
if (
|
||||
ignore.indexOf(key) === -1 &&
|
||||
typeof value === 'string' &&
|
||||
HEX.test(value)
|
||||
) {
|
||||
copy[key] = Buffer(value, 'hex')
|
||||
} else {
|
||||
copy[key] = value
|
||||
}
|
||||
}
|
||||
return copy
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
// for easy promise lib switching
|
||||
module.exports = require('bluebird')
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,60 +0,0 @@
|
|||
{
|
||||
"name": "fxa-auth-mailer",
|
||||
"version": "1.81.0",
|
||||
"description": "Library to send out verification emails in the fxa-auth-server which renders emails from a template (and handles localization).",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"start": "NODE_ENV=dev node bin/server.js",
|
||||
"test": "grunt lint && ./scripts/tap-coverage.js test/local",
|
||||
"prepush": "grunt templates && git status -s | (! grep 'M templates/')",
|
||||
"postinstall": "scripts/download_l10n.sh",
|
||||
"shrinkwrap": "npmshrink"
|
||||
},
|
||||
"author": "Mozilla (https://mozilla.org/)",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/mozilla/fxa-auth-mailer"
|
||||
},
|
||||
"homepage": "https://github.com/mozilla/fxa-auth-mailer",
|
||||
"bugs": "https://github.com/mozilla/fxa-auth-mailer/issues",
|
||||
"license": "MPL-2.0",
|
||||
"dependencies": {
|
||||
"bluebird": "3.4.7",
|
||||
"convict": "2.0.0",
|
||||
"fxa-shared": "1.0.4",
|
||||
"grunt-nunjucks-2-html": "vitkarpov/grunt-nunjucks-2-html#1900f91a756b2eaf900b20",
|
||||
"handlebars": "1.3.0",
|
||||
"i18n-abide": "0.0.25",
|
||||
"jed": "0.5.4",
|
||||
"moment-timezone": "0.5.11",
|
||||
"mozlog": "2.0.6",
|
||||
"nexmo": "1.2.0",
|
||||
"nodemailer": "2.7.2",
|
||||
"po2json": "0.4.5",
|
||||
"poolee": "1.0.1",
|
||||
"request": "2.79.0",
|
||||
"restify": "4.3.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"eslint-config-fxa": "2.1.0",
|
||||
"fxa-auth-db-mysql": "git+https://github.com/mozilla/fxa-auth-db-mysql.git#master",
|
||||
"fxa-conventional-changelog": "1.1.0",
|
||||
"grunt": "1.0.1",
|
||||
"grunt-bump": "0.8.0",
|
||||
"grunt-cli": "1.2.0",
|
||||
"grunt-contrib-copy": "1.0.0",
|
||||
"grunt-conventional-changelog": "5.0.0",
|
||||
"grunt-copyright": "0.3.0",
|
||||
"grunt-eslint": "18.0.0",
|
||||
"husky": "0.13.1",
|
||||
"jsxgettext-recursive": "0.0.5",
|
||||
"load-grunt-tasks": "3.5.0",
|
||||
"mkdirp": "0.5.1",
|
||||
"npmshrink": "1.0.1",
|
||||
"proxyquire": "1.7.10",
|
||||
"simplesmtp": "0.3.35",
|
||||
"sinon": "1.17.4",
|
||||
"tap": "6.2.0",
|
||||
"uuid": "1.4.1"
|
||||
}
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
{
|
||||
"rules": {
|
||||
"handle-callback-err": 0,
|
||||
"no-console": 0
|
||||
}
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
#!/usr/bin/env node
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
var cp = require('child_process')
|
||||
var util = require('util')
|
||||
|
||||
// Generate legacy-format output that looks something like:
|
||||
//
|
||||
// {
|
||||
// "version": {
|
||||
// "hash": "88f6f24e53da56faa933c357bffb61cbeaec7ff3",
|
||||
// "subject": "Merge pull request #2939 from vladikoff/sentry-patch3",
|
||||
// "committer date": "1439472293",
|
||||
// "source": "git://github.com/mozilla/fxa-content-server.git"
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// This content is placed in the stage/prod rpm at `./config/version.json`.
|
||||
// Ignore errors and always produce a (possibly empty struct) output.
|
||||
|
||||
var args = '{"hash":"%H","subject":"%s","committer date":"%ct"}'
|
||||
var cmd = util.format('git --no-pager log --format=format:\'%s\' -1', args)
|
||||
cp.exec(cmd, function (err, stdout) {
|
||||
var info = {
|
||||
version: JSON.parse(stdout || '{}')
|
||||
}
|
||||
|
||||
var cmd = 'git config --get remote.origin.url'
|
||||
cp.exec(cmd, function (err, stdout) {
|
||||
info.version.source = (stdout && stdout.trim()) || ''
|
||||
console.log(JSON.stringify(info, null, 2))
|
||||
})
|
||||
})
|
|
@ -1,21 +0,0 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
var path = require('path'),
|
||||
spawn = require('child_process').spawn
|
||||
|
||||
var COVERAGE_ARGS = ['--coverage', '--cov']
|
||||
if (process.env.NO_COVERAGE) {
|
||||
COVERAGE_ARGS = []
|
||||
}
|
||||
|
||||
var p = spawn(path.join(path.dirname(__dirname), 'node_modules', '.bin', 'tap'),
|
||||
process.argv.slice(2).concat(COVERAGE_ARGS), { stdio: 'inherit', env: process.env })
|
||||
|
||||
// exit this process with the same exit code as the test process
|
||||
p.on('close', function (code) {
|
||||
process.exit(code)
|
||||
})
|
|
@ -1,40 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
var sinon = require('sinon')
|
||||
var tap = require('tap')
|
||||
var test = tap.test
|
||||
var legacyLog = require('../../legacy_log')
|
||||
|
||||
var spyLog = {
|
||||
critical: sinon.spy(),
|
||||
debug: sinon.spy(),
|
||||
error: sinon.spy(),
|
||||
info: sinon.spy(),
|
||||
warn: sinon.spy()
|
||||
}
|
||||
|
||||
test('legacy_log unit tests', function (t) {
|
||||
var data = {
|
||||
op: 'testOp',
|
||||
err: 'Nooo!'
|
||||
}
|
||||
var log = legacyLog(spyLog)
|
||||
log.trace(data)
|
||||
t.equal(spyLog.debug.args[0][0], data.op)
|
||||
t.equal(spyLog.debug.args[0][1], data)
|
||||
log.error(data)
|
||||
t.equal(spyLog.error.args[0][0], data.op)
|
||||
t.equal(spyLog.error.args[0][1], data)
|
||||
log.fatal(data)
|
||||
t.equal(spyLog.critical.args[0][0], data.op)
|
||||
t.equal(spyLog.critical.args[0][1], data)
|
||||
log.warn(data)
|
||||
t.equal(spyLog.warn.args[0][0], data.op)
|
||||
t.equal(spyLog.warn.args[0][1], data)
|
||||
log.info(data)
|
||||
t.equal(spyLog.info.args[0][0], data.op)
|
||||
t.equal(spyLog.info.args[0][1], data)
|
||||
t.done()
|
||||
})
|
|
@ -1,257 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
var tap = require('tap')
|
||||
var test = tap.test
|
||||
var sinon = require('sinon')
|
||||
var proxyquire = require('proxyquire')
|
||||
var Pool, poolee
|
||||
|
||||
test(
|
||||
'pool.request with default options',
|
||||
function (t) {
|
||||
setup()
|
||||
|
||||
var pool = new Pool('http://example.com/ignore/me')
|
||||
pool.request()
|
||||
|
||||
t.equal(poolee.request.callCount, 1, 'poolee.request was called once')
|
||||
|
||||
var args = poolee.request.getCall(0).args
|
||||
t.equal(args.length, 2, 'poolee.request was passed two arguments')
|
||||
|
||||
var options = args[0]
|
||||
t.equal(typeof options, 'object', 'options is object')
|
||||
t.equal(Object.keys(options).length, 4, 'options has 4 properties')
|
||||
t.equal(options.method, 'GET', 'options.method is GET')
|
||||
t.equal(options.path, undefined, 'options.path is undefined')
|
||||
t.equal(typeof options.headers, 'object', 'options.headers is object')
|
||||
t.equal(Object.keys(options.headers).length, 1, 'options.headers has 1 property')
|
||||
t.equal(options.headers['Content-Type'], 'application/json', 'Content-Type header is application/json')
|
||||
t.equal(options.data, undefined, 'options.data is undefined')
|
||||
|
||||
var callback = args[1]
|
||||
t.equal(typeof callback, 'function', 'callback is function')
|
||||
|
||||
t.end()
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'pool.request with alternative options',
|
||||
function (t) {
|
||||
setup()
|
||||
|
||||
var pool = new Pool('http://example.com/')
|
||||
pool.request('POST', '/foo', { bar: 'baz' })
|
||||
|
||||
t.equal(poolee.request.callCount, 1, 'poolee.request was called once')
|
||||
|
||||
var args = poolee.request.getCall(0).args
|
||||
t.equal(args.length, 2, 'poolee.request was passed two arguments')
|
||||
|
||||
var options = args[0]
|
||||
t.equal(typeof options, 'object', 'options is object')
|
||||
t.equal(Object.keys(options).length, 4, 'options has 4 properties')
|
||||
t.equal(options.method, 'POST', 'options.method is POST')
|
||||
t.equal(options.path, '/foo', 'options.path is /foo')
|
||||
t.equal(typeof options.headers, 'object', 'options.headers is object')
|
||||
t.equal(Object.keys(options.headers).length, 1, 'options.headers has 1 property')
|
||||
t.equal(options.headers['Content-Type'], 'application/json', 'Content-Type header is application/json')
|
||||
t.equal(options.data, '{"bar":"baz"}', 'options.data is correct')
|
||||
|
||||
var callback = args[1]
|
||||
t.equal(typeof callback, 'function', 'callback is function')
|
||||
|
||||
t.end()
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'pool.request callback with error',
|
||||
function (t) {
|
||||
setup()
|
||||
|
||||
var pool = new Pool('http://example.com/')
|
||||
pool.request()
|
||||
.then(function () {
|
||||
t.fail('request should have failed')
|
||||
t.end()
|
||||
}, function (error) {
|
||||
t.equal(typeof error, 'string', 'error is string')
|
||||
t.equal(error, 'foo', 'error is correct')
|
||||
t.end()
|
||||
})
|
||||
|
||||
var args = poolee.request.getCall(0).args
|
||||
var callback = args[1]
|
||||
callback('foo')
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'pool.request callback with HTTP error response',
|
||||
function (t) {
|
||||
setup()
|
||||
|
||||
var pool = new Pool('http://example.com/')
|
||||
pool.request()
|
||||
.then(function () {
|
||||
t.fail('request should have failed')
|
||||
t.end()
|
||||
}, function (error) {
|
||||
t.ok(error instanceof Error, 'error is Error instance')
|
||||
t.equal(error.statusCode, 404, 'error.statusCode is 404')
|
||||
t.equal(error.message, 'wibble', 'error.message is correct')
|
||||
t.end()
|
||||
})
|
||||
|
||||
var args = poolee.request.getCall(0).args
|
||||
var callback = args[1]
|
||||
callback(null, { statusCode: 404 }, 'wibble')
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'pool.request callback with HTTP error response and JSON body',
|
||||
function (t) {
|
||||
setup()
|
||||
|
||||
var pool = new Pool('http://example.com/')
|
||||
pool.request()
|
||||
.then(function () {
|
||||
t.fail('request should have failed')
|
||||
t.end()
|
||||
}, function (error) {
|
||||
t.equal(error instanceof Error, false, 'error is not Error instance')
|
||||
t.equal(typeof error, 'object', 'error is object')
|
||||
t.equal(Object.keys(error).length, 2, 'error has two properties')
|
||||
t.equal(error.statusCode, 418, 'error.statusCode is 418')
|
||||
t.equal(error.foo, 'bar', 'other error data is correct')
|
||||
t.end()
|
||||
})
|
||||
|
||||
var args = poolee.request.getCall(0).args
|
||||
var callback = args[1]
|
||||
callback(null, { statusCode: 418 }, '{"foo":"bar"}')
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'pool.request callback with HTTP success response and empty body',
|
||||
function (t) {
|
||||
setup()
|
||||
|
||||
var pool = new Pool('http://example.com/')
|
||||
pool.request()
|
||||
.then(function (result) {
|
||||
t.equal(result, undefined, 'result is undefined')
|
||||
t.end()
|
||||
}, function () {
|
||||
t.fail('request should have succeeded')
|
||||
t.end()
|
||||
})
|
||||
|
||||
var args = poolee.request.getCall(0).args
|
||||
var callback = args[1]
|
||||
callback(null, { statusCode: 200 }, '')
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'pool.request callback with HTTP success response and valid JSON body',
|
||||
function (t) {
|
||||
setup()
|
||||
|
||||
var pool = new Pool('http://example.com/')
|
||||
pool.request()
|
||||
.then(function (result) {
|
||||
t.equal(typeof result, 'object', 'result is object')
|
||||
t.equal(Object.keys(result).length, 1, 'result has 1 property')
|
||||
t.equal(result.foo, 'bar', 'result data is correct')
|
||||
t.end()
|
||||
}, function () {
|
||||
t.fail('request should have succeeded')
|
||||
t.end()
|
||||
})
|
||||
|
||||
var args = poolee.request.getCall(0).args
|
||||
var callback = args[1]
|
||||
callback(null, { statusCode: 200 }, '{"foo":"bar"}')
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'pool.request callback with HTTP success response and invalid JSON body',
|
||||
function (t) {
|
||||
setup()
|
||||
|
||||
var pool = new Pool('http://example.com/')
|
||||
pool.request()
|
||||
.then(function () {
|
||||
t.fail('request should have failed')
|
||||
t.end()
|
||||
}, function (error) {
|
||||
t.ok(error instanceof Error, 'error is Error instance')
|
||||
t.equal(error.statusCode, undefined, 'error.statusCode is undefined')
|
||||
t.equal(error.message, 'Invalid JSON', 'error.message is correct')
|
||||
t.end()
|
||||
})
|
||||
|
||||
var args = poolee.request.getCall(0).args
|
||||
var callback = args[1]
|
||||
callback(null, { statusCode: 200 }, 'foo')
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'pool.get',
|
||||
function (t) {
|
||||
setup()
|
||||
|
||||
var pool = new Pool('http://example.com/')
|
||||
sinon.stub(pool, 'request', function () {})
|
||||
pool.get('foo')
|
||||
|
||||
t.equal(pool.request.callCount, 1, 'pool.request was called once')
|
||||
|
||||
var args = pool.request.getCall(0).args
|
||||
t.equal(args.length, 2, 'pool.request was passed three arguments')
|
||||
t.equal(args[0], 'GET', 'first argument to pool.request was POST')
|
||||
t.equal(args[1], 'foo', 'second argument to pool.request was correct')
|
||||
|
||||
t.end()
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'pool.put',
|
||||
function (t) {
|
||||
setup()
|
||||
|
||||
var pool = new Pool('http://example.com/')
|
||||
sinon.stub(pool, 'request', function () {})
|
||||
pool.put('baz', 'qux')
|
||||
|
||||
t.equal(pool.request.callCount, 1, 'pool.request was called once')
|
||||
|
||||
var args = pool.request.getCall(0).args
|
||||
t.equal(args.length, 3, 'pool.request was passed three arguments')
|
||||
t.equal(args[0], 'PUT', 'first argument to pool.request was POST')
|
||||
t.equal(args[1], 'baz', 'second argument to pool.request was correct')
|
||||
t.equal(args[2], 'qux', 'third argument to pool.request was correct')
|
||||
|
||||
t.end()
|
||||
}
|
||||
)
|
||||
|
||||
function setup () {
|
||||
poolee = sinon.createStubInstance(require('poolee'))
|
||||
Pool = proxyquire('../../lib/pool', {
|
||||
poolee: function () {
|
||||
return poolee
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
@ -1,144 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
'use strict'
|
||||
|
||||
const P = require('bluebird')
|
||||
const proxyquire = require('proxyquire')
|
||||
const sinon = require('sinon')
|
||||
const test = require('tap').test
|
||||
|
||||
const log = {
|
||||
error: sinon.spy(),
|
||||
info: sinon.spy(),
|
||||
trace: sinon.spy()
|
||||
}
|
||||
|
||||
let nexmoStatus = '0'
|
||||
const sendSms = sinon.spy((from, to, message, callback) => {
|
||||
callback(null, {
|
||||
message_count: '1',
|
||||
messages: [
|
||||
{
|
||||
to: to.substr(1),
|
||||
'message-id': 'foo',
|
||||
status: nexmoStatus,
|
||||
'error-text': 'bar',
|
||||
'remaining-balance': '42',
|
||||
'message-price': '1',
|
||||
'network': 'baz'
|
||||
}
|
||||
]
|
||||
})
|
||||
})
|
||||
function Nexmo () {}
|
||||
Nexmo.prototype.message = { sendSms }
|
||||
|
||||
P.all([
|
||||
require('../../translator')(['en'], 'en'),
|
||||
require('../../templates')()
|
||||
]).spread((translator, templates) => {
|
||||
const sms = proxyquire('../../lib/sms', {
|
||||
nexmo: Nexmo
|
||||
})(log, translator, templates, {
|
||||
apiKey: 'foo',
|
||||
apiSecret: 'bar',
|
||||
installFirefoxLink: 'https://baz/qux'
|
||||
})
|
||||
|
||||
test('interface is correct', t => {
|
||||
t.equal(typeof sms.send, 'function', 'sms.send is function')
|
||||
t.equal(sms.send.length, 4, 'sms.send expects 4 arguments')
|
||||
t.equal(Object.keys(sms).length, 1, 'sms has no other methods')
|
||||
t.done()
|
||||
})
|
||||
|
||||
test('send a valid sms', t => {
|
||||
t.plan(13)
|
||||
return sms.send('+442078553000', 'Firefox', 1, 'en')
|
||||
.then(() => {
|
||||
t.equal(sendSms.callCount, 1, 'nexmo.message.sendSms was called once')
|
||||
const args = sendSms.args[0]
|
||||
t.equal(args.length, 4, 'nexmo.message.sendSms was passed four arguments')
|
||||
t.equal(args[0], 'Firefox', 'nexmo.message.sendSms was passed the correct sender id')
|
||||
t.equal(args[1], '+442078553000', 'nexmo.message.sendSms was passed the correct phone number')
|
||||
t.equal(args[2], 'As requested, here is a link to install Firefox on your mobile device: https://baz/qux', 'nexmo.message.sendSms was passed the correct message')
|
||||
t.equal(typeof args[3], 'function', 'nexmo.message.sendSms was passed a callback function')
|
||||
|
||||
t.equal(log.trace.callCount, 1, 'log.trace was called once')
|
||||
t.equal(log.trace.args[0].length, 1, 'log.trace was passed one argument')
|
||||
t.deepEqual(log.trace.args[0][0], {
|
||||
op: 'sms.send',
|
||||
senderId: 'Firefox',
|
||||
messageId: 1,
|
||||
acceptLanguage: 'en'
|
||||
}, 'log.info was passed the correct data')
|
||||
|
||||
t.equal(log.info.callCount, 1, 'log.info was called once')
|
||||
t.equal(log.info.args[0].length, 1, 'log.info was passed one argument')
|
||||
t.deepEqual(log.info.args[0][0], {
|
||||
op: 'sms.send.success',
|
||||
senderId: 'Firefox',
|
||||
messageId: 1,
|
||||
acceptLanguage: 'en'
|
||||
}, 'log.info was passed the correct data')
|
||||
|
||||
t.equal(log.error.callCount, 0, 'log.error was not called')
|
||||
})
|
||||
.finally(() => {
|
||||
sendSms.reset()
|
||||
log.trace.reset()
|
||||
log.info.reset()
|
||||
})
|
||||
})
|
||||
|
||||
test('try to send an sms with an invalid message id', t => {
|
||||
t.plan(7)
|
||||
return sms.send('+442078553000', 'Firefox', 2, 'en')
|
||||
.then(() => t.notOk(true, 'sms.send should have rejected'))
|
||||
.catch(error => {
|
||||
t.equal(error.status, 400, 'error.statusCode was set correctly')
|
||||
t.equal(error.message, 'Invalid message id', 'error.message was set correctly')
|
||||
|
||||
t.equal(log.trace.callCount, 1, 'log.trace was called once')
|
||||
t.equal(log.info.callCount, 0, 'log.info was not called')
|
||||
|
||||
t.equal(log.error.callCount, 1, 'log.error was called once')
|
||||
t.deepEqual(log.error.args[0][0], {
|
||||
op: 'sms.send',
|
||||
err: error.message
|
||||
}, 'log.error was passed the correct data')
|
||||
|
||||
t.equal(sendSms.callCount, 0, 'nexmo.message.sendSms was not called')
|
||||
})
|
||||
.finally(() => {
|
||||
log.trace.reset()
|
||||
log.error.reset()
|
||||
})
|
||||
})
|
||||
|
||||
test('send an sms that is rejected by the network provider', t => {
|
||||
t.plan(7)
|
||||
nexmoStatus = '1'
|
||||
return sms.send('+442078553000', 'Firefox', 1, 'en')
|
||||
.then(() => t.notOk(true, 'sms.send should have rejected'))
|
||||
.catch(error => {
|
||||
t.equal(error.status, 500, 'error.statusCode was set correctly')
|
||||
t.equal(error.message, 'Message rejected', 'error.message was set correctly')
|
||||
t.equal(error.reason, 'bar', 'error.reason was set correctly')
|
||||
t.equal(error.reasonCode, '1', 'error.reasonCode was set correctly')
|
||||
|
||||
t.equal(log.trace.callCount, 1, 'log.trace was called once')
|
||||
t.equal(log.info.callCount, 0, 'log.info was not called')
|
||||
|
||||
t.equal(sendSms.callCount, 1, 'nexmo.message.sendSms was called once')
|
||||
})
|
||||
.finally(() => {
|
||||
log.trace.reset()
|
||||
sendSms.reset()
|
||||
log.error.reset()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
var test = require('tap').test
|
||||
|
||||
require('../../translator')(['en', 'pt_br', 'DE', 'ES_AR', 'ES_cl'], 'en')
|
||||
.done(
|
||||
function (translator) {
|
||||
test(
|
||||
'translator works with upper and lowercase languages',
|
||||
function (t) {
|
||||
var x = translator('PT-br,DE')
|
||||
t.equal(x.language, 'pt-BR')
|
||||
x = translator('bu-ll,es-ar')
|
||||
t.equal(x.language, 'es-AR')
|
||||
x = translator('es-CL')
|
||||
t.equal(x.language, 'es-CL')
|
||||
x = translator('en-US')
|
||||
t.equal(x.language, 'en')
|
||||
x = translator('db-LB') // a locale that does not exist
|
||||
t.equal(x.language, 'en')
|
||||
t.end()
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
29
package.json
29
package.json
|
@ -9,9 +9,9 @@
|
|||
"test": "test"
|
||||
},
|
||||
"scripts": {
|
||||
"prepush": "grunt quicklint && cd mailer && npm run prepush",
|
||||
"postinstall": "cd mailer && npm install",
|
||||
"shrinkwrap": "npmshrink",
|
||||
"prepush": "grunt quicklint && grunt templates && git status -s | (! grep 'M lib/senders/templates/')",
|
||||
"postinstall": "scripts/download_l10n.sh",
|
||||
"shrinkwrap": "npmshrink && npm run postinstall",
|
||||
"start": "NODE_ENV=dev scripts/start-local.sh 2>&1",
|
||||
"start-mysql": "NODE_ENV=dev scripts/start-local-mysql.sh 2>&1",
|
||||
"test": "NODE_ENV=dev CORS_ORIGIN=http://foo,http://bar scripts/test-local.sh",
|
||||
|
@ -39,27 +39,36 @@
|
|||
"binary-split": "0.1.2",
|
||||
"bluebird": "2.10.2",
|
||||
"buffer-equal-constant-time": "1.0.1",
|
||||
"convict": "1.5.0",
|
||||
"convict": "2.0.0",
|
||||
"email-addresses": "2.0.2",
|
||||
"envc": "2.4.0",
|
||||
"fxa-geodb": "0.0.7",
|
||||
"fxa-jwtool": "0.7.1",
|
||||
"fxa-shared": "1.0.3",
|
||||
"fxa-shared": "1.0.4",
|
||||
"google-libphonenumber": "2.0.10",
|
||||
"grunt-nunjucks-2-html": "vitkarpov/grunt-nunjucks-2-html#1900f91a756b2eaf900b20",
|
||||
"handlebars": "4.0.6",
|
||||
"hapi": "14.2.0",
|
||||
"hapi-auth-hawk": "3.0.1",
|
||||
"hapi-fxa-oauth": "2.2.0",
|
||||
"hapi-hpkp": "git+https://github.com/vbudhram/hapi-hpkp.git#master",
|
||||
"hkdf": "0.0.2",
|
||||
"i18n-abide": "0.0.25",
|
||||
"inert": "4.0.2",
|
||||
"jed": "0.5.4",
|
||||
"joi": "9.0.4",
|
||||
"memcached": "2.2.2",
|
||||
"mozlog": "2.0.5",
|
||||
"moment-timezone": "0.5.11",
|
||||
"mozlog": "2.0.6",
|
||||
"newrelic": "1.30.1",
|
||||
"nexmo": "1.2.0",
|
||||
"node-statsd": "0.1.1",
|
||||
"node-uap": "git+https://github.com/vladikoff/node-uap.git#9cdd16247",
|
||||
"nodemailer": "2.7.2",
|
||||
"po2json": "0.4.5",
|
||||
"poolee": "1.0.1",
|
||||
"request": "2.74.0",
|
||||
"request": "2.79.0",
|
||||
"restify": "4.3.0",
|
||||
"scrypt-hash": "1.1.14",
|
||||
"through": "2.3.8",
|
||||
"uuid": "1.4.1",
|
||||
|
@ -72,18 +81,22 @@
|
|||
"fxa-conventional-changelog": "1.1.0",
|
||||
"grunt": "1.0.1",
|
||||
"grunt-bump": "0.8.0",
|
||||
"grunt-cli": "1.2.0",
|
||||
"grunt-contrib-copy": "1.0.0",
|
||||
"grunt-conventional-changelog": "6.1.0",
|
||||
"grunt-copyright": "0.3.0",
|
||||
"grunt-eslint": "19.0.0",
|
||||
"grunt-newer": "1.2.0",
|
||||
"grunt-nsp": "2.3.1",
|
||||
"hawk": "2.3.1",
|
||||
"husky": "0.11.7",
|
||||
"husky": "0.13.1",
|
||||
"insist": "1.0.0",
|
||||
"jsxgettext-recursive": "0.0.5",
|
||||
"jws": "3.1.3",
|
||||
"leftpad": "0.0.0",
|
||||
"load-grunt-tasks": "3.5.2",
|
||||
"mailparser": "0.6.1",
|
||||
"mkdirp": "0.5.1",
|
||||
"mocha": "3.1.2",
|
||||
"nock": "8.0.0",
|
||||
"npmshrink": "1.0.1",
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
{
|
||||
"plugins": ["fxa"],
|
||||
"rules": {
|
||||
"handle-callback-err": 0,
|
||||
"no-console": 0,
|
||||
"fxa/async-crypto-random": 0,
|
||||
"fxa/no-new-buffer": 2
|
||||
|
|
|
@ -27,6 +27,8 @@ require('../lib/senders')(config, log)
|
|||
let message = error.message
|
||||
if (error.reason && error.reasonCode) {
|
||||
message = `${message}: ${error.reasonCode} ${error.reason}`
|
||||
} else if (error.stack) {
|
||||
message = error.stack
|
||||
}
|
||||
fail(message)
|
||||
})
|
||||
|
|
|
@ -28,9 +28,9 @@
|
|||
|
||||
var P = require('bluebird')
|
||||
var config = require('../config')
|
||||
const createSenders = require('../index')
|
||||
const createSenders = require('../lib/senders')
|
||||
var fs = require('fs')
|
||||
const log = require('../legacy_log')(require('../log')('server'))
|
||||
const log = require('../lib/senders/legacy_log')(require('../lib/senders/log')('server'))
|
||||
var mkdirp = require('mkdirp')
|
||||
var path = require('path')
|
||||
|
||||
|
@ -53,7 +53,7 @@ var mailSender = {
|
|||
}
|
||||
|
||||
|
||||
createSenders(log, config.getProperties(), mailSender)
|
||||
createSenders(config.getProperties(), log, mailSender)
|
||||
.then((senders) => {
|
||||
const mailer = senders.email
|
||||
checkMessageType(mailer, messageToSend)
|
|
@ -2,9 +2,10 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
const ROOT_DIR = '../../../..'
|
||||
|
||||
const assert = require('insist')
|
||||
var P = require('bluebird')
|
||||
var tap = require('tap')
|
||||
var test = tap.test
|
||||
var proxyquire = require('proxyquire')
|
||||
var dbConnect
|
||||
|
||||
|
@ -27,11 +28,11 @@ var mockConfig = {
|
|||
}
|
||||
}
|
||||
|
||||
test(
|
||||
it(
|
||||
'keeps polling until time limit',
|
||||
function (t) {
|
||||
dbConnect = proxyquire('../../lib/db_connect', {
|
||||
'../log': mockLog,
|
||||
function () {
|
||||
dbConnect = proxyquire(`${ROOT_DIR}/lib/senders/db_connect`, {
|
||||
'./log': mockLog,
|
||||
'./db': function () {
|
||||
return {
|
||||
connect: function() {
|
||||
|
@ -39,26 +40,25 @@ test(
|
|||
}
|
||||
}
|
||||
},
|
||||
'../config': mockConfig
|
||||
'../../mailer/config': mockConfig
|
||||
})()
|
||||
|
||||
dbConnect()
|
||||
return dbConnect()
|
||||
.catch(function (err) {
|
||||
t.equal(err.name, 'TimeoutError')
|
||||
t.equal(err.message, 'operation timed out')
|
||||
t.end()
|
||||
assert.equal(err.name, 'TimeoutError')
|
||||
assert.equal(err.message, 'operation timed out')
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'connects to db after polling',
|
||||
function (t) {
|
||||
function () {
|
||||
var dbConnectedMs = 30
|
||||
var testStart = Date.now()
|
||||
|
||||
dbConnect = proxyquire('../../lib/db_connect', {
|
||||
'../log': mockLog,
|
||||
dbConnect = proxyquire(`${ROOT_DIR}/lib/senders/db_connect`, {
|
||||
'./log': mockLog,
|
||||
'./db': function () {
|
||||
return {
|
||||
connect: function() {
|
||||
|
@ -73,13 +73,12 @@ test(
|
|||
}
|
||||
}
|
||||
},
|
||||
'../config': mockConfig
|
||||
'../../mailer/config': mockConfig
|
||||
})()
|
||||
|
||||
dbConnect()
|
||||
return dbConnect()
|
||||
.then(function (db) {
|
||||
t.equal(db.name, 'TestDB')
|
||||
t.end()
|
||||
assert.equal(db.name, 'TestDB')
|
||||
})
|
||||
}
|
||||
)
|
|
@ -2,11 +2,14 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
var extend = require('util')._extend
|
||||
'use strict'
|
||||
|
||||
const ROOT_DIR = '../../../..'
|
||||
|
||||
const assert = require('insist')
|
||||
var extend = require('util')._extend
|
||||
var sinon = require('sinon')
|
||||
var P = require('bluebird')
|
||||
var test = require('tap').test
|
||||
|
||||
var nullLog = {
|
||||
trace: function () {},
|
||||
|
@ -14,8 +17,8 @@ var nullLog = {
|
|||
error: function () {}
|
||||
}
|
||||
|
||||
var config = require('../../config')
|
||||
var Mailer = require('../../mailer')(nullLog)
|
||||
var config = require(`${ROOT_DIR}/mailer/config`)
|
||||
var Mailer = require(`${ROOT_DIR}/lib/senders/email`)(nullLog)
|
||||
|
||||
var messageTypes = [
|
||||
'newDeviceLoginEmail',
|
||||
|
@ -99,19 +102,22 @@ function sesMessageTagsHeaderValue(templateName) {
|
|||
return 'messageType=fxa-' + templateName + ', app=fxa'
|
||||
}
|
||||
|
||||
P.all(
|
||||
[
|
||||
require('../../translator')(['en'], 'en'),
|
||||
require('../../templates')()
|
||||
]
|
||||
)
|
||||
.spread(
|
||||
function (translator, templates) {
|
||||
describe(
|
||||
'lib/senders/email:',
|
||||
() => {
|
||||
let mailer
|
||||
|
||||
before(() => {
|
||||
return P.all([
|
||||
require(`${ROOT_DIR}/lib/senders/translator`)(['en'], 'en'),
|
||||
require(`${ROOT_DIR}/lib/senders/templates`)()
|
||||
]).spread((translator, templates) => {
|
||||
mailer = new Mailer(translator, templates, config.get('mail'))
|
||||
})
|
||||
})
|
||||
|
||||
messageTypes.forEach(
|
||||
function (type) {
|
||||
var mailer = new Mailer(translator, templates, config.get('mail'))
|
||||
|
||||
var message = {
|
||||
code: 'abc123',
|
||||
email: 'a@b.com',
|
||||
|
@ -123,83 +129,78 @@ P.all(
|
|||
flowBeginTime: Date.now()
|
||||
}
|
||||
|
||||
test(
|
||||
it(
|
||||
'Contains template header for ' + type,
|
||||
function (t) {
|
||||
function () {
|
||||
mailer.mailer.sendMail = function (emailConfig) {
|
||||
var templateName = emailConfig.headers['X-Template-Name']
|
||||
|
||||
if (type === 'verificationReminderEmail') {
|
||||
// Handle special case for verification reminders
|
||||
t.equal(templateName, 'verificationReminderFirstEmail' || 'verificationReminderSecondEmail')
|
||||
assert.equal(templateName, 'verificationReminderFirstEmail' || 'verificationReminderSecondEmail')
|
||||
} else if (type === 'verifyEmail') {
|
||||
// Handle special case for verify email
|
||||
t.equal(templateName, 'verifySyncEmail')
|
||||
assert.equal(templateName, 'verifySyncEmail')
|
||||
} else {
|
||||
t.equal(templateName, type)
|
||||
assert.equal(templateName, type)
|
||||
}
|
||||
t.end()
|
||||
}
|
||||
mailer[type](message)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'Contains flow headers for ' + type,
|
||||
function (t) {
|
||||
function () {
|
||||
if (type !== 'verificationReminderEmail') {
|
||||
mailer.mailer.sendMail = function (emailConfig) {
|
||||
var flowIdHeader = emailConfig.headers['X-Flow-Id']
|
||||
t.equal(flowIdHeader, message.flowId)
|
||||
assert.equal(flowIdHeader, message.flowId)
|
||||
|
||||
var flowBeginHeader = emailConfig.headers['X-Flow-Begin-Time']
|
||||
t.equal(flowBeginHeader, message.flowBeginTime)
|
||||
assert.equal(flowBeginHeader, message.flowBeginTime)
|
||||
}
|
||||
mailer[type](message)
|
||||
}
|
||||
|
||||
t.end()
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'test privacy link is in email template output for ' + type,
|
||||
function (t) {
|
||||
function () {
|
||||
var privacyLink = mailer.createPrivacyLink(type)
|
||||
|
||||
mailer.mailer.sendMail = function (emailConfig) {
|
||||
t.ok(includes(emailConfig.html, privacyLink))
|
||||
t.ok(includes(emailConfig.text, privacyLink))
|
||||
t.end()
|
||||
assert.ok(includes(emailConfig.html, privacyLink))
|
||||
assert.ok(includes(emailConfig.text, privacyLink))
|
||||
}
|
||||
mailer[type](message)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'If sesConfigurationSet is not defined, then outgoing email does not contain X-SES* headers, for type ' + type,
|
||||
function (t) {
|
||||
function () {
|
||||
mailer.mailer.sendMail = function (emailConfig) {
|
||||
var sesConfigurationSetHeader = emailConfig.headers['X-SES-CONFIGURATION-SET']
|
||||
t.ok(! sesConfigurationSetHeader)
|
||||
assert.ok(! sesConfigurationSetHeader)
|
||||
var sesMessageTags = emailConfig.headers['X-SES-MESSAGE-TAGS']
|
||||
t.ok(! sesMessageTags)
|
||||
t.end()
|
||||
assert.ok(! sesMessageTags)
|
||||
}
|
||||
|
||||
mailer[type](message) // invoke
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'If sesConfigurationSet is defined, then outgoing email will contain X-SES* headers, for type ' + type,
|
||||
function (t) {
|
||||
function () {
|
||||
var savedSesConfigurationSet = mailer.sesConfigurationSet
|
||||
mailer.sesConfigurationSet = 'some-defined-value'
|
||||
|
||||
mailer.mailer.sendMail = function (emailConfig) {
|
||||
var sesConfigurationSetHeader = emailConfig.headers['X-SES-CONFIGURATION-SET']
|
||||
t.equal(sesConfigurationSetHeader, 'some-defined-value')
|
||||
assert.equal(sesConfigurationSetHeader, 'some-defined-value')
|
||||
|
||||
var sesMessageTags = emailConfig.headers['X-SES-MESSAGE-TAGS']
|
||||
var expectedSesMessageTags = sesMessageTagsHeaderValue(type)
|
||||
|
@ -209,10 +210,9 @@ P.all(
|
|||
expectedSesMessageTags = sesMessageTagsHeaderValue('verificationReminderSecondEmail')
|
||||
}
|
||||
}
|
||||
t.equal(sesMessageTags, expectedSesMessageTags)
|
||||
assert.equal(sesMessageTags, expectedSesMessageTags)
|
||||
|
||||
mailer.sesConfigurationSet = savedSesConfigurationSet
|
||||
t.end()
|
||||
}
|
||||
|
||||
mailer[type](message) // invoke
|
||||
|
@ -220,15 +220,14 @@ P.all(
|
|||
)
|
||||
|
||||
if (includes(typesContainSupportLinks, type)) {
|
||||
test(
|
||||
it(
|
||||
'test support link is in email template output for ' + type,
|
||||
function (t) {
|
||||
function () {
|
||||
var supportTextLink = mailer.createSupportLink(type)
|
||||
|
||||
mailer.mailer.sendMail = function (emailConfig) {
|
||||
t.ok(includes(emailConfig.html, supportTextLink))
|
||||
t.ok(includes(emailConfig.text, supportTextLink))
|
||||
t.end()
|
||||
assert.ok(includes(emailConfig.html, supportTextLink))
|
||||
assert.ok(includes(emailConfig.text, supportTextLink))
|
||||
}
|
||||
mailer[type](message)
|
||||
}
|
||||
|
@ -236,15 +235,14 @@ P.all(
|
|||
}
|
||||
|
||||
if (includes(typesContainPasswordResetLinks, type)) {
|
||||
var resetPasswordLink = mailer.createPasswordResetLink(message.email, type)
|
||||
|
||||
test(
|
||||
it(
|
||||
'reset password link is in email template output for ' + type,
|
||||
function (t) {
|
||||
function () {
|
||||
var resetPasswordLink = mailer.createPasswordResetLink(message.email, type)
|
||||
|
||||
mailer.mailer.sendMail = function (emailConfig) {
|
||||
t.ok(includes(emailConfig.html, resetPasswordLink))
|
||||
t.ok(includes(emailConfig.text, resetPasswordLink))
|
||||
t.end()
|
||||
assert.ok(includes(emailConfig.html, resetPasswordLink))
|
||||
assert.ok(includes(emailConfig.text, resetPasswordLink))
|
||||
}
|
||||
mailer[type](message)
|
||||
}
|
||||
|
@ -252,14 +250,14 @@ P.all(
|
|||
}
|
||||
|
||||
if (includes(typesContainPasswordChangeLinks, type)) {
|
||||
var passwordChangeLink = mailer.createPasswordChangeLink(message.email, type)
|
||||
test(
|
||||
it(
|
||||
'password change link is in email template output for ' + type,
|
||||
function (t) {
|
||||
function () {
|
||||
var passwordChangeLink = mailer.createPasswordChangeLink(message.email, type)
|
||||
|
||||
mailer.mailer.sendMail = function (emailConfig) {
|
||||
t.ok(includes(emailConfig.html, passwordChangeLink))
|
||||
t.ok(includes(emailConfig.text, passwordChangeLink))
|
||||
t.end()
|
||||
assert.ok(includes(emailConfig.html, passwordChangeLink))
|
||||
assert.ok(includes(emailConfig.text, passwordChangeLink))
|
||||
}
|
||||
mailer[type](message)
|
||||
}
|
||||
|
@ -267,14 +265,12 @@ P.all(
|
|||
}
|
||||
|
||||
if (includes(typesContainUnblockCode, type)) {
|
||||
test(
|
||||
it(
|
||||
'unblock code is in email template output for ' + type,
|
||||
function (t) {
|
||||
function () {
|
||||
mailer.mailer.sendMail = function (emailConfig) {
|
||||
t.ok(includes(emailConfig.html, message.unblockCode))
|
||||
t.ok(includes(emailConfig.text, message.unblockCode))
|
||||
|
||||
t.end()
|
||||
assert.ok(includes(emailConfig.html, message.unblockCode))
|
||||
assert.ok(includes(emailConfig.text, message.unblockCode))
|
||||
}
|
||||
mailer[type](message)
|
||||
}
|
||||
|
@ -282,16 +278,14 @@ P.all(
|
|||
}
|
||||
|
||||
if (includes(typesContainReportSignInLinks, type)) {
|
||||
test(
|
||||
it(
|
||||
'report sign-in link is in email template output for ' + type,
|
||||
function (t) {
|
||||
function () {
|
||||
mailer.mailer.sendMail = function (emailConfig) {
|
||||
var reportSignInLink =
|
||||
mailer.createReportSignInLink(type, message)
|
||||
t.ok(includes(emailConfig.html, reportSignInLink))
|
||||
t.ok(includes(emailConfig.text, reportSignInLink))
|
||||
|
||||
t.end()
|
||||
assert.ok(includes(emailConfig.html, reportSignInLink))
|
||||
assert.ok(includes(emailConfig.text, reportSignInLink))
|
||||
}
|
||||
mailer[type](message)
|
||||
}
|
||||
|
@ -299,15 +293,14 @@ P.all(
|
|||
}
|
||||
|
||||
if (includes(typesContainAndroidStoreLinks, type)) {
|
||||
var androidStoreLink = mailer.androidUrl
|
||||
|
||||
test(
|
||||
it(
|
||||
'Android store link is in email template output for ' + type,
|
||||
function (t) {
|
||||
function () {
|
||||
var androidStoreLink = mailer.androidUrl
|
||||
|
||||
mailer.mailer.sendMail = function (emailConfig) {
|
||||
t.ok(includes(emailConfig.html, androidStoreLink))
|
||||
assert.ok(includes(emailConfig.html, androidStoreLink))
|
||||
// only the html email contains links to the store
|
||||
t.end()
|
||||
}
|
||||
mailer[type](message)
|
||||
}
|
||||
|
@ -315,15 +308,14 @@ P.all(
|
|||
}
|
||||
|
||||
if (includes(typesContainIOSStoreLinks, type)) {
|
||||
var iosStoreLink = mailer.iosUrl
|
||||
|
||||
test(
|
||||
it(
|
||||
'IOS store link is in email template output for ' + type,
|
||||
function (t) {
|
||||
function () {
|
||||
var iosStoreLink = mailer.iosUrl
|
||||
|
||||
mailer.mailer.sendMail = function (emailConfig) {
|
||||
t.ok(includes(emailConfig.html, iosStoreLink))
|
||||
assert.ok(includes(emailConfig.html, iosStoreLink))
|
||||
// only the html email contains links to the store
|
||||
t.end()
|
||||
}
|
||||
mailer[type](message)
|
||||
}
|
||||
|
@ -331,15 +323,14 @@ P.all(
|
|||
}
|
||||
|
||||
if (includes(typesContainPasswordManagerInfoLinks, type)) {
|
||||
var passwordManagerInfoUrl = mailer._generateLinks(config.get('mail').passwordManagerInfoUrl, message.email, {}, type).passwordManagerInfoUrl
|
||||
|
||||
test(
|
||||
it(
|
||||
'password manager info link is in email template output for ' + type,
|
||||
function (t) {
|
||||
function () {
|
||||
var passwordManagerInfoUrl = mailer._generateLinks(config.get('mail').passwordManagerInfoUrl, message.email, {}, type).passwordManagerInfoUrl
|
||||
|
||||
mailer.mailer.sendMail = function (emailConfig) {
|
||||
t.ok(includes(emailConfig.html, passwordManagerInfoUrl))
|
||||
t.ok(includes(emailConfig.text, passwordManagerInfoUrl))
|
||||
t.end()
|
||||
assert.ok(includes(emailConfig.html, passwordManagerInfoUrl))
|
||||
assert.ok(includes(emailConfig.text, passwordManagerInfoUrl))
|
||||
}
|
||||
mailer[type](message)
|
||||
}
|
||||
|
@ -354,72 +345,68 @@ P.all(
|
|||
stateCode: 'CA'
|
||||
}
|
||||
|
||||
test(
|
||||
it(
|
||||
'ip data is in template for ' + type,
|
||||
function (t) {
|
||||
function () {
|
||||
var message = getLocationMessage(defaultLocation)
|
||||
|
||||
mailer.mailer.sendMail = function (emailConfig) {
|
||||
t.ok(includes(emailConfig.html, message.ip))
|
||||
assert.ok(includes(emailConfig.html, message.ip))
|
||||
|
||||
t.ok(includes(emailConfig.text, message.ip))
|
||||
t.end()
|
||||
assert.ok(includes(emailConfig.text, message.ip))
|
||||
}
|
||||
mailer[type](message)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'location is correct with city, country, stateCode for ' + type,
|
||||
function (t) {
|
||||
function () {
|
||||
var location = defaultLocation
|
||||
var message = getLocationMessage(defaultLocation)
|
||||
|
||||
mailer.mailer.sendMail = function (emailConfig) {
|
||||
t.ok(includes(emailConfig.html, location.city + ', ' + location.stateCode + ', ' + location.country))
|
||||
t.ok(includes(emailConfig.text, location.city + ', ' + location.stateCode + ', ' + location.country))
|
||||
t.end()
|
||||
assert.ok(includes(emailConfig.html, location.city + ', ' + location.stateCode + ', ' + location.country))
|
||||
assert.ok(includes(emailConfig.text, location.city + ', ' + location.stateCode + ', ' + location.country))
|
||||
}
|
||||
mailer[type](message)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'location is correct with city, country for ' + type,
|
||||
function (t) {
|
||||
function () {
|
||||
var location = extend({}, defaultLocation)
|
||||
delete location.stateCode
|
||||
var message = getLocationMessage(location)
|
||||
|
||||
|
||||
mailer.mailer.sendMail = function (emailConfig) {
|
||||
t.ok(includes(emailConfig.html, location.city + ', ' + location.country))
|
||||
t.ok(includes(emailConfig.text, location.city + ', ' + location.country))
|
||||
t.end()
|
||||
assert.ok(includes(emailConfig.html, location.city + ', ' + location.country))
|
||||
assert.ok(includes(emailConfig.text, location.city + ', ' + location.country))
|
||||
}
|
||||
mailer[type](message)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'location is correct with stateCode, country for ' + type,
|
||||
function (t) {
|
||||
function () {
|
||||
var location = extend({}, defaultLocation)
|
||||
delete location.city
|
||||
var message = getLocationMessage(location)
|
||||
|
||||
mailer.mailer.sendMail = function (emailConfig) {
|
||||
t.ok(includes(emailConfig.html, location.stateCode + ', ' + location.country))
|
||||
t.ok(includes(emailConfig.text, location.stateCode + ', ' + location.country))
|
||||
t.end()
|
||||
assert.ok(includes(emailConfig.html, location.stateCode + ', ' + location.country))
|
||||
assert.ok(includes(emailConfig.text, location.stateCode + ', ' + location.country))
|
||||
}
|
||||
mailer[type](message)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'location is correct with country for ' + type,
|
||||
function (t) {
|
||||
function () {
|
||||
var location = extend({}, defaultLocation)
|
||||
delete location.city
|
||||
delete location.stateCode
|
||||
|
@ -427,9 +414,8 @@ P.all(
|
|||
|
||||
|
||||
mailer.mailer.sendMail = function (emailConfig) {
|
||||
t.ok(includes(emailConfig.html, location.country))
|
||||
t.ok(includes(emailConfig.text, location.country))
|
||||
t.end()
|
||||
assert.ok(includes(emailConfig.html, location.country))
|
||||
assert.ok(includes(emailConfig.text, location.country))
|
||||
}
|
||||
mailer[type](message)
|
||||
}
|
||||
|
@ -438,32 +424,29 @@ P.all(
|
|||
}
|
||||
|
||||
if (type === 'verifyLoginEmail') {
|
||||
test(
|
||||
it(
|
||||
'test verify token email',
|
||||
function (t) {
|
||||
function () {
|
||||
mailer.mailer.sendMail = function (emailConfig) {
|
||||
var verifyLoginUrl = config.get('mail').verifyLoginUrl
|
||||
t.ok(emailConfig.html.indexOf(verifyLoginUrl) > 0)
|
||||
t.ok(emailConfig.text.indexOf(verifyLoginUrl) > 0)
|
||||
|
||||
t.end()
|
||||
assert.ok(emailConfig.html.indexOf(verifyLoginUrl) > 0)
|
||||
assert.ok(emailConfig.text.indexOf(verifyLoginUrl) > 0)
|
||||
}
|
||||
mailer[type](message)
|
||||
}
|
||||
)
|
||||
} else if (type === 'postVerifyEmail') {
|
||||
test(
|
||||
it(
|
||||
'test utm params for ' + type,
|
||||
function (t) {
|
||||
function () {
|
||||
var syncLink = mailer._generateUTMLink(config.get('mail').syncUrl, {}, type, 'connect-device')
|
||||
var androidLink = mailer._generateUTMLink(config.get('mail').androidUrl, {}, type, 'connect-android')
|
||||
var iosLink = mailer._generateUTMLink(config.get('mail').iosUrl, {}, type, 'connect-ios')
|
||||
|
||||
mailer.mailer.sendMail = function (emailConfig) {
|
||||
t.ok(includes(emailConfig.html, syncLink))
|
||||
t.ok(includes(emailConfig.html, androidLink))
|
||||
t.ok(includes(emailConfig.html, iosLink))
|
||||
t.end()
|
||||
assert.ok(includes(emailConfig.html, syncLink))
|
||||
assert.ok(includes(emailConfig.html, androidLink))
|
||||
assert.ok(includes(emailConfig.html, iosLink))
|
||||
}
|
||||
mailer[type](message)
|
||||
}
|
||||
|
@ -473,13 +456,12 @@ P.all(
|
|||
type: 'customType'
|
||||
})
|
||||
|
||||
test(
|
||||
it(
|
||||
'custom reminder types are supported in output for ' + type,
|
||||
function (t) {
|
||||
function () {
|
||||
mailer.mailer.sendMail = function (emailConfig) {
|
||||
t.ok(includes(emailConfig.html, 'reminder=customType'))
|
||||
t.ok(includes(emailConfig.text, 'reminder=customType'))
|
||||
t.end()
|
||||
assert.ok(includes(emailConfig.html, 'reminder=customType'))
|
||||
assert.ok(includes(emailConfig.text, 'reminder=customType'))
|
||||
}
|
||||
mailer[type](reminderMessage)
|
||||
}
|
||||
|
@ -488,82 +470,77 @@ P.all(
|
|||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'test user-agent info rendering',
|
||||
function (t) {
|
||||
var mailer = new Mailer(translator, templates, config.get('mail'))
|
||||
|
||||
t.equal(mailer._formatUserAgentInfo({
|
||||
function () {
|
||||
assert.equal(mailer._formatUserAgentInfo({
|
||||
uaBrowser: 'Firefox',
|
||||
uaBrowserVersion: '32',
|
||||
uaOS: 'Windows',
|
||||
uaOSVersion: '8.1'
|
||||
}), 'Firefox on Windows 8.1')
|
||||
|
||||
t.equal(mailer._formatUserAgentInfo({
|
||||
assert.equal(mailer._formatUserAgentInfo({
|
||||
uaBrowser: 'Chrome',
|
||||
uaBrowserVersion: undefined,
|
||||
uaOS: 'Windows',
|
||||
uaOSVersion: '10',
|
||||
}), 'Chrome on Windows 10')
|
||||
|
||||
t.equal(mailer._formatUserAgentInfo({
|
||||
assert.equal(mailer._formatUserAgentInfo({
|
||||
uaBrowser: undefined,
|
||||
uaBrowserVersion: '12',
|
||||
uaOS: 'Windows',
|
||||
uaOSVersion: '10'
|
||||
}), 'Windows 10')
|
||||
|
||||
t.equal(mailer._formatUserAgentInfo({
|
||||
assert.equal(mailer._formatUserAgentInfo({
|
||||
uaBrowser: 'MSIE',
|
||||
uaBrowserVersion: '6',
|
||||
uaOS: 'Linux',
|
||||
uaOSVersion: '9'
|
||||
}), 'MSIE on Linux 9')
|
||||
|
||||
t.equal(mailer._formatUserAgentInfo({
|
||||
assert.equal(mailer._formatUserAgentInfo({
|
||||
uaBrowser: 'MSIE',
|
||||
uaBrowserVersion: undefined,
|
||||
uaOS: 'Linux',
|
||||
uaOSVersion: undefined
|
||||
}), 'MSIE on Linux')
|
||||
|
||||
t.equal(mailer._formatUserAgentInfo({
|
||||
assert.equal(mailer._formatUserAgentInfo({
|
||||
uaBrowser: 'MSIE',
|
||||
uaBrowserVersion: '8',
|
||||
uaOS: undefined,
|
||||
uaOSVersion: '4'
|
||||
}), 'MSIE')
|
||||
|
||||
t.equal(mailer._formatUserAgentInfo({
|
||||
assert.equal(mailer._formatUserAgentInfo({
|
||||
uaBrowser: 'MSIE',
|
||||
uaBrowserVersion: undefined,
|
||||
uaOS: undefined,
|
||||
uaOSVersion: undefined
|
||||
}), 'MSIE')
|
||||
|
||||
t.equal(mailer._formatUserAgentInfo({
|
||||
assert.equal(mailer._formatUserAgentInfo({
|
||||
uaBrowser: undefined,
|
||||
uaBrowserVersion: undefined,
|
||||
uaOS: 'Windows',
|
||||
uaOSVersion: undefined
|
||||
}), 'Windows')
|
||||
|
||||
t.equal(mailer._formatUserAgentInfo({
|
||||
assert.equal(mailer._formatUserAgentInfo({
|
||||
uaBrowser: undefined,
|
||||
uaBrowserVersion: undefined,
|
||||
uaOS: undefined,
|
||||
uaOSVersion: undefined
|
||||
}), '')
|
||||
|
||||
t.end()
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'resolves sendMail status',
|
||||
function (t) {
|
||||
var mailer = new Mailer(translator, templates, config.get('mail'))
|
||||
function () {
|
||||
sinon.stub(mailer.mailer, 'sendMail', function (config, cb) {
|
||||
cb(null, { resp: 'ok' })
|
||||
})
|
||||
|
@ -577,19 +554,15 @@ P.all(
|
|||
|
||||
return mailer.send(message)
|
||||
.then(function (status) {
|
||||
t.equal(status.resp, 'ok')
|
||||
t.done()
|
||||
assert.equal(status.resp, 'ok')
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'rejects sendMail status',
|
||||
function (t) {
|
||||
var mailer = new Mailer(translator, templates, config.get('mail'))
|
||||
sinon.stub(mailer.mailer, 'sendMail', function (config, cb) {
|
||||
cb(new Error('Fail'))
|
||||
})
|
||||
function () {
|
||||
mailer.mailer.sendMail.reset()
|
||||
|
||||
var message = {
|
||||
email: 'test@restmail.net',
|
||||
|
@ -599,9 +572,8 @@ P.all(
|
|||
}
|
||||
|
||||
return mailer.send(message)
|
||||
.then(t.notOk, function (err) {
|
||||
t.equal(err.message, 'Fail')
|
||||
t.done()
|
||||
.then(assert.notOk, function (err) {
|
||||
assert.equal(err.message, 'Fail')
|
||||
})
|
||||
}
|
||||
)
|
|
@ -0,0 +1,38 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
const assert = require('insist')
|
||||
var sinon = require('sinon')
|
||||
var legacyLog = require('../../../../lib/senders/legacy_log')
|
||||
|
||||
var spyLog = {
|
||||
critical: sinon.spy(),
|
||||
debug: sinon.spy(),
|
||||
error: sinon.spy(),
|
||||
info: sinon.spy(),
|
||||
warn: sinon.spy()
|
||||
}
|
||||
|
||||
it('legacy_log unit tests', function () {
|
||||
var data = {
|
||||
op: 'testOp',
|
||||
err: 'Nooo!'
|
||||
}
|
||||
var log = legacyLog(spyLog)
|
||||
log.trace(data)
|
||||
assert.equal(spyLog.debug.args[0][0], data.op)
|
||||
assert.equal(spyLog.debug.args[0][1], data)
|
||||
log.error(data)
|
||||
assert.equal(spyLog.error.args[0][0], data.op)
|
||||
assert.equal(spyLog.error.args[0][1], data)
|
||||
log.fatal(data)
|
||||
assert.equal(spyLog.critical.args[0][0], data.op)
|
||||
assert.equal(spyLog.critical.args[0][1], data)
|
||||
log.warn(data)
|
||||
assert.equal(spyLog.warn.args[0][0], data.op)
|
||||
assert.equal(spyLog.warn.args[0][1], data)
|
||||
log.info(data)
|
||||
assert.equal(spyLog.info.args[0][0], data.op)
|
||||
assert.equal(spyLog.info.args[0][1], data)
|
||||
})
|
|
@ -0,0 +1,248 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
const assert = require('insist')
|
||||
var sinon = require('sinon')
|
||||
var proxyquire = require('proxyquire')
|
||||
var Pool, poolee
|
||||
|
||||
it(
|
||||
'pool.request with default options',
|
||||
function () {
|
||||
setup()
|
||||
|
||||
var pool = new Pool('http://example.com/ignore/me')
|
||||
pool.request()
|
||||
|
||||
assert.equal(poolee.request.callCount, 1, 'poolee.request was called once')
|
||||
|
||||
var args = poolee.request.getCall(0).args
|
||||
assert.equal(args.length, 2, 'poolee.request was passed two arguments')
|
||||
|
||||
var options = args[0]
|
||||
assert.equal(typeof options, 'object', 'options is object')
|
||||
assert.equal(Object.keys(options).length, 4, 'options has 4 properties')
|
||||
assert.equal(options.method, 'GET', 'options.method is GET')
|
||||
assert.equal(options.path, undefined, 'options.path is undefined')
|
||||
assert.equal(typeof options.headers, 'object', 'options.headers is object')
|
||||
assert.equal(Object.keys(options.headers).length, 1, 'options.headers has 1 property')
|
||||
assert.equal(options.headers['Content-Type'], 'application/json', 'Content-Type header is application/json')
|
||||
assert.equal(options.data, undefined, 'options.data is undefined')
|
||||
|
||||
var callback = args[1]
|
||||
assert.equal(typeof callback, 'function', 'callback is function')
|
||||
}
|
||||
)
|
||||
|
||||
it(
|
||||
'pool.request with alternative options',
|
||||
function () {
|
||||
setup()
|
||||
|
||||
var pool = new Pool('http://example.com/')
|
||||
pool.request('POST', '/foo', { bar: 'baz' })
|
||||
|
||||
assert.equal(poolee.request.callCount, 1, 'poolee.request was called once')
|
||||
|
||||
var args = poolee.request.getCall(0).args
|
||||
assert.equal(args.length, 2, 'poolee.request was passed two arguments')
|
||||
|
||||
var options = args[0]
|
||||
assert.equal(typeof options, 'object', 'options is object')
|
||||
assert.equal(Object.keys(options).length, 4, 'options has 4 properties')
|
||||
assert.equal(options.method, 'POST', 'options.method is POST')
|
||||
assert.equal(options.path, '/foo', 'options.path is /foo')
|
||||
assert.equal(typeof options.headers, 'object', 'options.headers is object')
|
||||
assert.equal(Object.keys(options.headers).length, 1, 'options.headers has 1 property')
|
||||
assert.equal(options.headers['Content-Type'], 'application/json', 'Content-Type header is application/json')
|
||||
assert.equal(options.data, '{"bar":"baz"}', 'options.data is correct')
|
||||
|
||||
var callback = args[1]
|
||||
assert.equal(typeof callback, 'function', 'callback is function')
|
||||
}
|
||||
)
|
||||
|
||||
it(
|
||||
'pool.request callback with error',
|
||||
function (done) {
|
||||
setup()
|
||||
|
||||
var pool = new Pool('http://example.com/')
|
||||
pool.request()
|
||||
.then(function () {
|
||||
assert.fail('request should have failed')
|
||||
done()
|
||||
}, function (error) {
|
||||
assert.equal(typeof error, 'string', 'error is string')
|
||||
assert.equal(error, 'foo', 'error is correct')
|
||||
done()
|
||||
})
|
||||
|
||||
var args = poolee.request.getCall(0).args
|
||||
var callback = args[1]
|
||||
callback('foo')
|
||||
}
|
||||
)
|
||||
|
||||
it(
|
||||
'pool.request callback with HTTP error response',
|
||||
function (done) {
|
||||
setup()
|
||||
|
||||
var pool = new Pool('http://example.com/')
|
||||
pool.request()
|
||||
.then(function () {
|
||||
assert.fail('request should have failed')
|
||||
done()
|
||||
}, function (error) {
|
||||
assert.ok(error instanceof Error, 'error is Error instance')
|
||||
assert.equal(error.statusCode, 404, 'error.statusCode is 404')
|
||||
assert.equal(error.message, 'wibble', 'error.message is correct')
|
||||
done()
|
||||
})
|
||||
|
||||
var args = poolee.request.getCall(0).args
|
||||
var callback = args[1]
|
||||
callback(null, { statusCode: 404 }, 'wibble')
|
||||
}
|
||||
)
|
||||
|
||||
it(
|
||||
'pool.request callback with HTTP error response and JSON body',
|
||||
function (done) {
|
||||
setup()
|
||||
|
||||
var pool = new Pool('http://example.com/')
|
||||
pool.request()
|
||||
.then(function () {
|
||||
assert.fail('request should have failed')
|
||||
done()
|
||||
}, function (error) {
|
||||
assert.equal(error instanceof Error, false, 'error is not Error instance')
|
||||
assert.equal(typeof error, 'object', 'error is object')
|
||||
assert.equal(Object.keys(error).length, 2, 'error has two properties')
|
||||
assert.equal(error.statusCode, 418, 'error.statusCode is 418')
|
||||
assert.equal(error.foo, 'bar', 'other error data is correct')
|
||||
done()
|
||||
})
|
||||
|
||||
var args = poolee.request.getCall(0).args
|
||||
var callback = args[1]
|
||||
callback(null, { statusCode: 418 }, '{"foo":"bar"}')
|
||||
}
|
||||
)
|
||||
|
||||
it(
|
||||
'pool.request callback with HTTP success response and empty body',
|
||||
function (done) {
|
||||
setup()
|
||||
|
||||
var pool = new Pool('http://example.com/')
|
||||
pool.request()
|
||||
.then(function (result) {
|
||||
assert.equal(result, undefined, 'result is undefined')
|
||||
done()
|
||||
}, function () {
|
||||
assert.fail('request should have succeeded')
|
||||
done()
|
||||
})
|
||||
|
||||
var args = poolee.request.getCall(0).args
|
||||
var callback = args[1]
|
||||
callback(null, { statusCode: 200 }, '')
|
||||
}
|
||||
)
|
||||
|
||||
it(
|
||||
'pool.request callback with HTTP success response and valid JSON body',
|
||||
function (done) {
|
||||
setup()
|
||||
|
||||
var pool = new Pool('http://example.com/')
|
||||
pool.request()
|
||||
.then(function (result) {
|
||||
assert.equal(typeof result, 'object', 'result is object')
|
||||
assert.equal(Object.keys(result).length, 1, 'result has 1 property')
|
||||
assert.equal(result.foo, 'bar', 'result data is correct')
|
||||
done()
|
||||
}, function () {
|
||||
assert.fail('request should have succeeded')
|
||||
done()
|
||||
})
|
||||
|
||||
var args = poolee.request.getCall(0).args
|
||||
var callback = args[1]
|
||||
callback(null, { statusCode: 200 }, '{"foo":"bar"}')
|
||||
}
|
||||
)
|
||||
|
||||
it(
|
||||
'pool.request callback with HTTP success response and invalid JSON body',
|
||||
function (done) {
|
||||
setup()
|
||||
|
||||
var pool = new Pool('http://example.com/')
|
||||
pool.request()
|
||||
.then(function () {
|
||||
assert.fail('request should have failed')
|
||||
done()
|
||||
}, function (error) {
|
||||
assert.ok(error instanceof Error, 'error is Error instance')
|
||||
assert.equal(error.statusCode, undefined, 'error.statusCode is undefined')
|
||||
assert.equal(error.message, 'Invalid JSON', 'error.message is correct')
|
||||
done()
|
||||
})
|
||||
|
||||
var args = poolee.request.getCall(0).args
|
||||
var callback = args[1]
|
||||
callback(null, { statusCode: 200 }, 'foo')
|
||||
}
|
||||
)
|
||||
|
||||
it(
|
||||
'pool.get',
|
||||
function () {
|
||||
setup()
|
||||
|
||||
var pool = new Pool('http://example.com/')
|
||||
sinon.stub(pool, 'request', function () {})
|
||||
pool.get('foo')
|
||||
|
||||
assert.equal(pool.request.callCount, 1, 'pool.request was called once')
|
||||
|
||||
var args = pool.request.getCall(0).args
|
||||
assert.equal(args.length, 2, 'pool.request was passed three arguments')
|
||||
assert.equal(args[0], 'GET', 'first argument to pool.request was POST')
|
||||
assert.equal(args[1], 'foo', 'second argument to pool.request was correct')
|
||||
}
|
||||
)
|
||||
|
||||
it(
|
||||
'pool.put',
|
||||
function () {
|
||||
setup()
|
||||
|
||||
var pool = new Pool('http://example.com/')
|
||||
sinon.stub(pool, 'request', function () {})
|
||||
pool.put('baz', 'qux')
|
||||
|
||||
assert.equal(pool.request.callCount, 1, 'pool.request was called once')
|
||||
|
||||
var args = pool.request.getCall(0).args
|
||||
assert.equal(args.length, 3, 'pool.request was passed three arguments')
|
||||
assert.equal(args[0], 'PUT', 'first argument to pool.request was POST')
|
||||
assert.equal(args[1], 'baz', 'second argument to pool.request was correct')
|
||||
assert.equal(args[2], 'qux', 'third argument to pool.request was correct')
|
||||
}
|
||||
)
|
||||
|
||||
function setup () {
|
||||
poolee = sinon.createStubInstance(require('poolee'))
|
||||
Pool = proxyquire('../../../../lib/senders/pool', {
|
||||
poolee: function () {
|
||||
return poolee
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
@ -2,12 +2,13 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
const ROOT_DIR = '../../../../'
|
||||
|
||||
const assert = require('insist')
|
||||
var sinon = require('sinon')
|
||||
var extend = require('util')._extend
|
||||
var tap = require('tap')
|
||||
var test = tap.test
|
||||
var P = require('../../lib/promise')
|
||||
var config = require('../../config')
|
||||
var P = require(`${ROOT_DIR}/lib/promise`)
|
||||
var config = require(`${ROOT_DIR}/mailer/config`)
|
||||
|
||||
var TEST_EMAIL = 'test@restmail.net'
|
||||
var TEST_ACCOUNT_RECORD = {
|
||||
|
@ -42,44 +43,44 @@ var mockLog = function(methods) {
|
|||
return log
|
||||
}
|
||||
|
||||
test('_processReminder sends first reminder for unverified emails', function (t) {
|
||||
it('_processReminder sends first reminder for unverified emails', function () {
|
||||
setup()
|
||||
|
||||
var legacyMailerLog = require('../../legacy_log')(mockLog())
|
||||
var Mailer = require('../../mailer')(legacyMailerLog)
|
||||
var legacyMailerLog = require(`${ROOT_DIR}/lib/senders/legacy_log`)(mockLog())
|
||||
var Mailer = require(`${ROOT_DIR}/lib/senders/email`)(legacyMailerLog)
|
||||
var mailer = new Mailer({}, {}, config.get('mail'))
|
||||
sandbox.stub(mailer, 'send', function (vals) {
|
||||
t.equal(vals.acceptLanguage, TEST_ACCOUNT_RECORD.locale, 'correct locale')
|
||||
t.equal(vals.uid, TEST_ACCOUNT_RECORD.uid.toString('hex'), 'correct uid')
|
||||
t.equal(vals.email, TEST_ACCOUNT_RECORD.email, 'correct email')
|
||||
t.equal(vals.template, 'verificationReminderFirstEmail', 'correct template')
|
||||
t.equal(vals.subject, 'Hello again.', 'correct subject')
|
||||
t.equal(vals.headers['X-Verify-Code'], TEST_ACCOUNT_RECORD.emailCode.toString('hex'), 'correct code')
|
||||
t.ok(vals.templateValues.link.indexOf(TEST_ACCOUNT_RECORD.emailCode.toString('hex')) >= 0, 'correct link')
|
||||
done(t)
|
||||
assert.equal(vals.acceptLanguage, TEST_ACCOUNT_RECORD.locale, 'correct locale')
|
||||
assert.equal(vals.uid, TEST_ACCOUNT_RECORD.uid.toString('hex'), 'correct uid')
|
||||
assert.equal(vals.email, TEST_ACCOUNT_RECORD.email, 'correct email')
|
||||
assert.equal(vals.template, 'verificationReminderFirstEmail', 'correct template')
|
||||
assert.equal(vals.subject, 'Hello again.', 'correct subject')
|
||||
assert.equal(vals.headers['X-Verify-Code'], TEST_ACCOUNT_RECORD.emailCode.toString('hex'), 'correct code')
|
||||
assert.ok(vals.templateValues.link.indexOf(TEST_ACCOUNT_RECORD.emailCode.toString('hex')) >= 0, 'correct link')
|
||||
done()
|
||||
})
|
||||
|
||||
require('../../lib/verification-reminders')(mailer, mockDb)
|
||||
require(`${ROOT_DIR}/lib/senders/verification-reminders`)(mailer, mockDb)
|
||||
._processReminder(SAMPLE_REMINDER)
|
||||
})
|
||||
|
||||
test('_processReminder sends second reminder for unverified emails', function (t) {
|
||||
it('_processReminder sends second reminder for unverified emails', function () {
|
||||
setup()
|
||||
var legacyMailerLog = require('../../legacy_log')(mockLog())
|
||||
var Mailer = require('../../mailer')(legacyMailerLog)
|
||||
var legacyMailerLog = require(`${ROOT_DIR}/lib/senders/legacy_log`)(mockLog())
|
||||
var Mailer = require(`${ROOT_DIR}/lib/senders/email`)(legacyMailerLog)
|
||||
var mailer = new Mailer({}, {}, config.get('mail'))
|
||||
sandbox.stub(mailer, 'send', function (vals) {
|
||||
t.equal(vals.template, 'verificationReminderSecondEmail', 'correct template')
|
||||
t.equal(vals.headers['X-Verify-Code'], TEST_ACCOUNT_RECORD.emailCode.toString('hex'), 'correct code')
|
||||
t.ok(vals.templateValues.link.indexOf(TEST_ACCOUNT_RECORD.emailCode.toString('hex')) >= 0, 'correct link')
|
||||
done(t)
|
||||
assert.equal(vals.template, 'verificationReminderSecondEmail', 'correct template')
|
||||
assert.equal(vals.headers['X-Verify-Code'], TEST_ACCOUNT_RECORD.emailCode.toString('hex'), 'correct code')
|
||||
assert.ok(vals.templateValues.link.indexOf(TEST_ACCOUNT_RECORD.emailCode.toString('hex')) >= 0, 'correct link')
|
||||
done()
|
||||
})
|
||||
|
||||
require('../../lib/verification-reminders')(mailer, mockDb)
|
||||
require(`${ROOT_DIR}/lib/senders/verification-reminders`)(mailer, mockDb)
|
||||
._processReminder({uid: TEST_ACCOUNT_RECORD.uid, type: 'second'})
|
||||
})
|
||||
|
||||
test('_processReminder - does not send email for verified emails', function (t) {
|
||||
it('_processReminder - does not send email for verified emails', function () {
|
||||
setup()
|
||||
sandbox.stub(mockDb, 'account', function () {
|
||||
return P.resolve({
|
||||
|
@ -90,16 +91,16 @@ test('_processReminder - does not send email for verified emails', function (t)
|
|||
var log = mockLog({
|
||||
debug: function (op, data) {
|
||||
if (data.msg === 'Already Verified') {
|
||||
done(t)
|
||||
done()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
require('../../lib/verification-reminders')(mockMailer, mockDb, { log: log })
|
||||
require(`${ROOT_DIR}/lib/senders/verification-reminders`)(mockMailer, mockDb, { log: log })
|
||||
._processReminder(SAMPLE_REMINDER)
|
||||
})
|
||||
|
||||
test('_processReminder - catches errors', function (t) {
|
||||
it('_processReminder - catches errors', function () {
|
||||
setup()
|
||||
var errorMsg = 'Something is wrong.'
|
||||
|
||||
|
@ -110,23 +111,23 @@ test('_processReminder - catches errors', function (t) {
|
|||
var log = mockLog({
|
||||
error: function (op, data) {
|
||||
if (data.err && data.err.message === errorMsg) {
|
||||
done(t)
|
||||
done()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
require('../../lib/verification-reminders')(mockMailer, mockDb, { log: log })
|
||||
require(`${ROOT_DIR}/lib/senders/verification-reminders`)(mockMailer, mockDb, { log: log })
|
||||
._processReminder(SAMPLE_REMINDER)
|
||||
})
|
||||
|
||||
|
||||
test('_continuousPoll - calls _continuousPoll', function (t) {
|
||||
it('_continuousPoll - calls _continuousPoll', function () {
|
||||
setup()
|
||||
|
||||
sandbox.stub(mockDb, 'fetchReminders', function (options) {
|
||||
t.ok(options.type)
|
||||
t.ok(options.reminderTime)
|
||||
t.ok(options.limit)
|
||||
assert.ok(options.type)
|
||||
assert.ok(options.reminderTime)
|
||||
assert.ok(options.limit)
|
||||
|
||||
if (options.type === 'first') {
|
||||
return P.resolve([SAMPLE_REMINDER])
|
||||
|
@ -136,13 +137,13 @@ test('_continuousPoll - calls _continuousPoll', function (t) {
|
|||
})
|
||||
|
||||
sandbox.stub(mockDb, 'account', function () {
|
||||
done(t)
|
||||
done()
|
||||
return P.resolve({
|
||||
emailVerified: true
|
||||
})
|
||||
})
|
||||
|
||||
require('../../lib/verification-reminders')(mockMailer, mockDb)
|
||||
require(`${ROOT_DIR}/lib/senders/verification-reminders`)(mockMailer, mockDb)
|
||||
._continuousPoll()
|
||||
})
|
||||
|
||||
|
@ -151,7 +152,6 @@ function setup() {
|
|||
sandbox = sinon.sandbox.create()
|
||||
}
|
||||
|
||||
function done(t) {
|
||||
function done() {
|
||||
sandbox.restore()
|
||||
t.done()
|
||||
}
|
|
@ -0,0 +1,139 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
'use strict'
|
||||
|
||||
const assert = require('insist')
|
||||
const P = require('bluebird')
|
||||
const proxyquire = require('proxyquire')
|
||||
const sinon = require('sinon')
|
||||
|
||||
const log = {
|
||||
error: sinon.spy(),
|
||||
info: sinon.spy(),
|
||||
trace: sinon.spy()
|
||||
}
|
||||
|
||||
let nexmoStatus = '0'
|
||||
const sendSms = sinon.spy((from, to, message, callback) => {
|
||||
callback(null, {
|
||||
message_count: '1',
|
||||
messages: [
|
||||
{
|
||||
to: to.substr(1),
|
||||
'message-id': 'foo',
|
||||
status: nexmoStatus,
|
||||
'error-text': 'bar',
|
||||
'remaining-balance': '42',
|
||||
'message-price': '1',
|
||||
'network': 'baz'
|
||||
}
|
||||
]
|
||||
})
|
||||
})
|
||||
function Nexmo () {}
|
||||
Nexmo.prototype.message = { sendSms }
|
||||
|
||||
describe('lib/senders/sms:', () => {
|
||||
let sms
|
||||
|
||||
before(() => {
|
||||
return P.all([
|
||||
require('../../../../lib/senders/translator')(['en'], 'en'),
|
||||
require('../../../../lib/senders/templates')()
|
||||
]).spread((translator, templates) => {
|
||||
sms = proxyquire('../../../../lib/senders/sms', {
|
||||
nexmo: Nexmo
|
||||
})(log, translator, templates, {
|
||||
apiKey: 'foo',
|
||||
apiSecret: 'bar',
|
||||
installFirefoxLink: 'https://baz/qux'
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
sendSms.reset()
|
||||
log.error.reset()
|
||||
log.info.reset()
|
||||
log.trace.reset()
|
||||
})
|
||||
|
||||
it('interface is correct', () => {
|
||||
assert.equal(typeof sms.send, 'function', 'sms.send is function')
|
||||
assert.equal(sms.send.length, 4, 'sms.send expects 4 arguments')
|
||||
assert.equal(Object.keys(sms).length, 1, 'sms has no other methods')
|
||||
})
|
||||
|
||||
it('sends a valid sms', () => {
|
||||
return sms.send('+442078553000', 'Firefox', 1, 'en')
|
||||
.then(() => {
|
||||
assert.equal(sendSms.callCount, 1, 'nexmo.message.sendSms was called once')
|
||||
const args = sendSms.args[0]
|
||||
assert.equal(args.length, 4, 'nexmo.message.sendSms was passed four arguments')
|
||||
assert.equal(args[0], 'Firefox', 'nexmo.message.sendSms was passed the correct sender id')
|
||||
assert.equal(args[1], '+442078553000', 'nexmo.message.sendSms was passed the correct phone number')
|
||||
assert.equal(args[2], 'As requested, here is a link to install Firefox on your mobile device: https://baz/qux', 'nexmo.message.sendSms was passed the correct message')
|
||||
assert.equal(typeof args[3], 'function', 'nexmo.message.sendSms was passed a callback function')
|
||||
|
||||
assert.equal(log.trace.callCount, 1, 'log.trace was called once')
|
||||
assert.equal(log.trace.args[0].length, 1, 'log.trace was passed one argument')
|
||||
assert.deepEqual(log.trace.args[0][0], {
|
||||
op: 'sms.send',
|
||||
senderId: 'Firefox',
|
||||
messageId: 1,
|
||||
acceptLanguage: 'en'
|
||||
}, 'log.info was passed the correct data')
|
||||
|
||||
assert.equal(log.info.callCount, 1, 'log.info was called once')
|
||||
assert.equal(log.info.args[0].length, 1, 'log.info was passed one argument')
|
||||
assert.deepEqual(log.info.args[0][0], {
|
||||
op: 'sms.send.success',
|
||||
senderId: 'Firefox',
|
||||
messageId: 1,
|
||||
acceptLanguage: 'en'
|
||||
}, 'log.info was passed the correct data')
|
||||
|
||||
assert.equal(log.error.callCount, 0, 'log.error was not called')
|
||||
})
|
||||
})
|
||||
|
||||
it('try to send an sms with an invalid message id', () => {
|
||||
return sms.send('+442078553000', 'Firefox', 2, 'en')
|
||||
.then(() => assert.fail('sms.send should have rejected'))
|
||||
.catch(error => {
|
||||
assert.equal(error.status, 400, 'error.statusCode was set correctly')
|
||||
assert.equal(error.message, 'Invalid message id', 'error.message was set correctly')
|
||||
|
||||
assert.equal(log.trace.callCount, 1, 'log.trace was called once')
|
||||
assert.equal(log.info.callCount, 0, 'log.info was not called')
|
||||
|
||||
assert.equal(log.error.callCount, 1, 'log.error was called once')
|
||||
assert.deepEqual(log.error.args[0][0], {
|
||||
op: 'sms.send',
|
||||
err: error.message
|
||||
}, 'log.error was passed the correct data')
|
||||
|
||||
assert.equal(sendSms.callCount, 0, 'nexmo.message.sendSms was not called')
|
||||
})
|
||||
})
|
||||
|
||||
it('send an sms that is rejected by the network provider', () => {
|
||||
nexmoStatus = '1'
|
||||
return sms.send('+442078553000', 'Firefox', 1, 'en')
|
||||
.then(() => assert.fail('sms.send should have rejected'))
|
||||
.catch(error => {
|
||||
assert.equal(error.status, 500, 'error.statusCode was set correctly')
|
||||
assert.equal(error.message, 'Message rejected', 'error.message was set correctly')
|
||||
assert.equal(error.reason, 'bar', 'error.reason was set correctly')
|
||||
assert.equal(error.reasonCode, '1', 'error.reasonCode was set correctly')
|
||||
|
||||
assert.equal(log.trace.callCount, 1, 'log.trace was called once')
|
||||
assert.equal(log.info.callCount, 0, 'log.info was not called')
|
||||
|
||||
assert.equal(sendSms.callCount, 1, 'nexmo.message.sendSms was called once')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
const assert = require('insist')
|
||||
|
||||
require('../../../../lib/senders/translator')(['en', 'pt_br', 'DE', 'ES_AR', 'ES_cl'], 'en')
|
||||
.done(
|
||||
function (translator) {
|
||||
it(
|
||||
'translator works with upper and lowercase languages',
|
||||
function (t) {
|
||||
var x = translator('PT-br,DE')
|
||||
assert.equal(x.language, 'pt-BR')
|
||||
x = translator('bu-ll,es-ar')
|
||||
assert.equal(x.language, 'es-AR')
|
||||
x = translator('es-CL')
|
||||
assert.equal(x.language, 'es-CL')
|
||||
x = translator('en-US')
|
||||
assert.equal(x.language, 'en')
|
||||
x = translator('db-LB') // a locale that does not exist
|
||||
assert.equal(x.language, 'en')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
|
@ -2,55 +2,57 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
var tap = require('tap')
|
||||
var test = tap.test
|
||||
'use strict'
|
||||
|
||||
const assert = require('insist')
|
||||
var butil = require('../../lib/crypto/butil')
|
||||
var unbuffer = butil.unbuffer
|
||||
var config = require('../../config').getProperties()
|
||||
var TestServer = require('../test_server')
|
||||
var config = require('../../mailer/config').getProperties()
|
||||
var TestServer = require('../test_mailer_server')
|
||||
|
||||
var testHelpers = require('../helpers')
|
||||
var testHelper = require('../mailer_helper')
|
||||
|
||||
var DB = require('../../lib/db')()
|
||||
var DB = require('../../lib/senders/db')()
|
||||
|
||||
var dbServer
|
||||
var dbConn = TestServer.start(config)
|
||||
.then(
|
||||
function (server) {
|
||||
dbServer = server
|
||||
return DB.connect(config[config.db.backend])
|
||||
}
|
||||
)
|
||||
describe('mailer db', () => {
|
||||
let dbServer, dbConn
|
||||
|
||||
test(
|
||||
'ping',
|
||||
function (t) {
|
||||
t.plan(1)
|
||||
before(() => {
|
||||
return dbConn = TestServer.start(config)
|
||||
.then(server => {
|
||||
dbServer = server
|
||||
return DB.connect(config[config.db.backend])
|
||||
})
|
||||
})
|
||||
|
||||
after(() => {
|
||||
return dbConn.then(db => {
|
||||
return db.close()
|
||||
}).then(() => {
|
||||
return dbServer.stop()
|
||||
})
|
||||
})
|
||||
|
||||
it('ping', () => {
|
||||
return dbConn
|
||||
.then(function (db) {
|
||||
return db.ping()
|
||||
})
|
||||
.then(function () {
|
||||
t.pass('Got the ping ok')
|
||||
assert.ok('Got the ping ok')
|
||||
}, function (err) {
|
||||
throw err
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'get email record',
|
||||
function (t) {
|
||||
t.plan(1)
|
||||
})
|
||||
|
||||
it('get email record', () => {
|
||||
var accountData
|
||||
var db
|
||||
|
||||
return dbConn
|
||||
.then(function (dbObj) {
|
||||
db = dbObj
|
||||
accountData = testHelpers.createTestAccount()
|
||||
accountData = testHelper.createTestAccount()
|
||||
|
||||
return db.pool.put(
|
||||
'/account/' + accountData.uid.toString('hex'),
|
||||
|
@ -61,26 +63,20 @@ test(
|
|||
return db.emailRecord(accountData.email)
|
||||
})
|
||||
.then(function (account) {
|
||||
t.false(account.emailVerified, false)
|
||||
t.end()
|
||||
assert.equal(account.emailVerified, false)
|
||||
}, function (err) {
|
||||
throw err
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'get account by uid',
|
||||
function (t) {
|
||||
t.plan(1)
|
||||
})
|
||||
|
||||
it('get account by uid', () => {
|
||||
var accountData
|
||||
var db
|
||||
|
||||
return dbConn
|
||||
.then(function (dbObj) {
|
||||
db = dbObj
|
||||
accountData = testHelpers.createTestAccount()
|
||||
accountData = testHelper.createTestAccount()
|
||||
|
||||
return db.pool.put(
|
||||
'/account/' + accountData.uid.toString('hex'),
|
||||
|
@ -91,18 +87,13 @@ test(
|
|||
return db.account(accountData.uid)
|
||||
})
|
||||
.then(function (account) {
|
||||
t.false(account.emailVerified, false)
|
||||
t.end()
|
||||
assert.equal(account.emailVerified, false)
|
||||
}, function (err) {
|
||||
throw err
|
||||
})
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
test(
|
||||
'throws db errors',
|
||||
function (t) {
|
||||
t.plan(2)
|
||||
it('throws db errors', () => {
|
||||
var db
|
||||
|
||||
return dbConn
|
||||
|
@ -111,32 +102,16 @@ test(
|
|||
return db.emailRecord('unknownEmail@restmail.net')
|
||||
})
|
||||
.then(function () {
|
||||
t.notOk()
|
||||
assert.fail()
|
||||
}, function (err) {
|
||||
t.ok(err)
|
||||
assert.ok(err)
|
||||
return db.emailRecord('unknownEmail@restmail.net')
|
||||
|
||||
})
|
||||
.then(function () {
|
||||
t.notOk()
|
||||
assert.fail()
|
||||
}, function (err) {
|
||||
t.ok(err)
|
||||
t.end()
|
||||
assert.ok(err)
|
||||
})
|
||||
|
||||
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'teardown',
|
||||
function (t) {
|
||||
return dbConn.then(function(db) {
|
||||
return db.close()
|
||||
}).then(function() {
|
||||
return dbServer.stop()
|
||||
}).then(function () {
|
||||
t.end()
|
||||
})
|
||||
}
|
||||
)
|
||||
})
|
||||
})
|
|
@ -2,37 +2,45 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
var tap = require('tap')
|
||||
var test = tap.test
|
||||
'use strict'
|
||||
|
||||
const assert = require('insist')
|
||||
var P = require('../../lib/promise')
|
||||
var butil = require('../../lib/crypto/butil')
|
||||
var unbuffer = butil.unbuffer
|
||||
var config = require('../../config').getProperties()
|
||||
var TestServer = require('../test_server')
|
||||
var testHelpers = require('../helpers')
|
||||
var TestServer = require('../test_mailer_server')
|
||||
var testHelper = require('../mailer_helper')
|
||||
|
||||
var DB = require('../../lib/db')()
|
||||
var DB = require('../../lib/senders/db')()
|
||||
|
||||
var dbServer
|
||||
var dbConn = TestServer.start(config)
|
||||
.then(
|
||||
function (server) {
|
||||
dbServer = server
|
||||
return DB.connect(config[config.db.backend])
|
||||
}
|
||||
)
|
||||
describe('mailer reminder db', () => {
|
||||
let dbServer, dbConn
|
||||
|
||||
test(
|
||||
'fetchReminders',
|
||||
function (t) {
|
||||
before(() => {
|
||||
return dbConn = TestServer.start(config)
|
||||
.then(server => {
|
||||
dbServer = server
|
||||
return DB.connect(config[config.db.backend])
|
||||
})
|
||||
})
|
||||
|
||||
after(() => {
|
||||
return dbConn.then(db => {
|
||||
return db.close()
|
||||
}).then(() => {
|
||||
return dbServer.stop()
|
||||
})
|
||||
})
|
||||
|
||||
it('fetchReminders', () => {
|
||||
var accountData
|
||||
var db
|
||||
|
||||
return dbConn
|
||||
.then(function (dbObj) {
|
||||
db = dbObj
|
||||
accountData = testHelpers.createTestAccount()
|
||||
accountData = testHelper.createTestAccount()
|
||||
|
||||
return db.pool.put(
|
||||
'/account/' + accountData.uid.toString('hex'),
|
||||
|
@ -75,25 +83,11 @@ test(
|
|||
}
|
||||
})
|
||||
|
||||
t.ok(reminderFound, 'fetched the created reminder')
|
||||
t.end()
|
||||
assert.ok(reminderFound, 'fetched the created reminder')
|
||||
},
|
||||
function (err) {
|
||||
throw err
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'teardown',
|
||||
function (t) {
|
||||
return dbConn.then(function(db) {
|
||||
return db.close()
|
||||
}).then(function() {
|
||||
return dbServer.stop()
|
||||
}).then(function () {
|
||||
t.end()
|
||||
})
|
||||
}
|
||||
)
|
||||
})
|
||||
})
|
Загрузка…
Ссылка в новой задаче