feat(profile): send push notifications after a profile update
This commit is contained in:
Родитель
c90719a041
Коммит
2e8342093c
|
@ -0,0 +1,33 @@
|
|||
/* 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 config = require('../config').getProperties()
|
||||
var log = require('../lib/log')(config.log.level, 'profile-server-messaging')
|
||||
var error = require('../lib/error')
|
||||
var Token = require('../lib/tokens')(log, config)
|
||||
var SQSReceiver = require('../lib/sqs')(log)
|
||||
var profileUpdates = require('../lib/profile/updates')(log)
|
||||
var push = require('../lib/push')
|
||||
|
||||
var DB = require('../lib/db')(
|
||||
config,
|
||||
log,
|
||||
error,
|
||||
Token.SessionToken,
|
||||
Token.KeyFetchToken,
|
||||
Token.AccountResetToken,
|
||||
Token.PasswordForgotToken,
|
||||
Token.PasswordChangeToken
|
||||
)
|
||||
|
||||
var profileUpdatesQueue = new SQSReceiver(config.profileServerMessaging.region, [
|
||||
config.profileServerMessaging.profileUpdatesQueueUrl
|
||||
])
|
||||
|
||||
DB.connect(config[config.db.backend])
|
||||
.then(
|
||||
function (db) {
|
||||
profileUpdates(profileUpdatesQueue, push(log, db, config))
|
||||
}
|
||||
)
|
|
@ -373,6 +373,20 @@ var conf = convict({
|
|||
default: ''
|
||||
}
|
||||
},
|
||||
profileServerMessaging: {
|
||||
region: {
|
||||
doc: 'The region where the queues live',
|
||||
format: String,
|
||||
env: 'PROFILE_MESSAGING_REGION',
|
||||
default: ''
|
||||
},
|
||||
profileUpdatesQueueUrl: {
|
||||
doc: 'The queue URL to use (should include https://sqs.<region>.amazonaws.com/<account-id>/<queue-name>)',
|
||||
format: String,
|
||||
env: 'PROFILE_UPDATES_QUEUE_URL',
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
verificationReminders: {
|
||||
rate: {
|
||||
doc: 'Rate of users getting the verification reminder. If "0" then the feature is disabled. If "1" all users get it.',
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
"anyOf":[
|
||||
{ "$ref":"#/definitions/deviceConnected" },
|
||||
{ "$ref":"#/definitions/deviceDisconnected" },
|
||||
{ "$ref":"#/definitions/profileUpdated" },
|
||||
{ "$ref":"#/definitions/collectionsChanged" },
|
||||
{ "$ref":"#/definitions/passwordChanged" },
|
||||
{ "$ref":"#/definitions/passwordReset" }
|
||||
|
@ -77,6 +78,24 @@
|
|||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"profileUpdated":{
|
||||
"required":[
|
||||
"version",
|
||||
"command"
|
||||
],
|
||||
"properties":{
|
||||
"version":{
|
||||
"type":"integer"
|
||||
},
|
||||
"command":{
|
||||
"type":"string",
|
||||
"enum":[
|
||||
"fxaccounts:profile_updated"
|
||||
]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"collectionsChanged":{
|
||||
"required":[
|
||||
"version",
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
/* 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 P = require('./../promise')
|
||||
|
||||
module.exports = function (log) {
|
||||
|
||||
return function start(messageQueue, push) {
|
||||
|
||||
function handleProfileUpdated(message) {
|
||||
return new P(resolve => {
|
||||
const uid = Buffer.from(message.uid, 'hex')
|
||||
resolve(push.notifyProfileUpdated(uid))
|
||||
})
|
||||
.catch(function(err) {
|
||||
log.error({ op: 'handleProfileUpdated', err: err })
|
||||
})
|
||||
.then(function () {
|
||||
// We always delete the message, we are not really mission critical
|
||||
message.del()
|
||||
})
|
||||
}
|
||||
|
||||
messageQueue.on('data', handleProfileUpdated)
|
||||
messageQueue.start()
|
||||
|
||||
return {
|
||||
messageQueue: messageQueue,
|
||||
handleProfileUpdated: handleProfileUpdated
|
||||
}
|
||||
}
|
||||
}
|
24
lib/push.js
24
lib/push.js
|
@ -15,6 +15,7 @@ var PUSH_PAYLOAD_SCHEMA_VERSION = 1
|
|||
var PUSH_COMMANDS = {
|
||||
DEVICE_CONNECTED: 'fxaccounts:device_connected',
|
||||
DEVICE_DISCONNECTED: 'fxaccounts:device_disconnected',
|
||||
PROFILE_UPDATED: 'fxaccounts:profile_updated',
|
||||
PASSWORD_CHANGED: 'fxaccounts:password_changed',
|
||||
PASSWORD_RESET: 'fxaccounts:password_reset'
|
||||
}
|
||||
|
@ -76,6 +77,14 @@ var reasonToEvents = {
|
|||
noCallback: 'push.device_disconnected.no_push_callback',
|
||||
noKeys: 'push.device_disconnected.data_but_no_keys'
|
||||
},
|
||||
profileUpdated: {
|
||||
send: 'push.profile_updated.send',
|
||||
success: 'push.profile_updated.success',
|
||||
resetSettings: 'push.profile_updated.reset_settings',
|
||||
failed: 'push.profile_updated.failed',
|
||||
noCallback: 'push.profile_updated.no_push_callback',
|
||||
noKeys: 'push.profile_updated.data_but_no_keys'
|
||||
},
|
||||
devicesNotify: {
|
||||
send: 'push.devices_notify.send',
|
||||
success: 'push.devices_notify.success',
|
||||
|
@ -198,6 +207,21 @@ module.exports = function (log, db, config) {
|
|||
return this.pushToDevice(uid, idToDisconnect, 'deviceDisconnected', options)
|
||||
},
|
||||
|
||||
/**
|
||||
* Notifies all devices that a the profile attached to the account was updated
|
||||
*
|
||||
* @param uid
|
||||
* @promise
|
||||
*/
|
||||
notifyProfileUpdated: function notifyProfileUpdated(uid) {
|
||||
var data = Buffer.from(JSON.stringify({
|
||||
version: PUSH_PAYLOAD_SCHEMA_VERSION,
|
||||
command: PUSH_COMMANDS.PROFILE_UPDATED
|
||||
}))
|
||||
var options = { data: data }
|
||||
return this.pushToAllDevices(uid, 'profileUpdated', options)
|
||||
},
|
||||
|
||||
/**
|
||||
* Notifies a set of devices that the password was changed
|
||||
*
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
/* 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')
|
||||
|
||||
const EventEmitter = require('events').EventEmitter
|
||||
const sinon = require('sinon')
|
||||
const spyLog = require('../../mocks').spyLog
|
||||
const profileUpdates = require('../../../lib/profile/updates')
|
||||
const P = require('../../../lib/promise')
|
||||
|
||||
const mockDeliveryQueue = new EventEmitter()
|
||||
mockDeliveryQueue.start = function start() {}
|
||||
|
||||
function mockMessage(msg) {
|
||||
msg.del = sinon.spy()
|
||||
return msg
|
||||
}
|
||||
|
||||
var pushShouldThrow = false
|
||||
const mockPush = {
|
||||
notifyProfileUpdated: sinon.spy(() => {
|
||||
if (pushShouldThrow) {
|
||||
throw new Error('oops')
|
||||
}
|
||||
return P.resolve()
|
||||
})
|
||||
}
|
||||
|
||||
function mockProfileUpdates(log) {
|
||||
return profileUpdates(log)(mockDeliveryQueue, mockPush)
|
||||
}
|
||||
|
||||
describe('profile updates', () => {
|
||||
it(
|
||||
'should log errors',
|
||||
() => {
|
||||
pushShouldThrow = true
|
||||
const mockLog = spyLog()
|
||||
return mockProfileUpdates(mockLog).handleProfileUpdated(mockMessage({
|
||||
uid: 'bogusuid'
|
||||
})).then(() => {
|
||||
assert.equal(mockPush.notifyProfileUpdated.callCount, 1)
|
||||
assert.equal(mockLog.messages.length, 1)
|
||||
pushShouldThrow = false
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
it(
|
||||
'should send push notifications',
|
||||
() => {
|
||||
const mockLog = spyLog()
|
||||
const uid = '1e2122ba'
|
||||
|
||||
return mockProfileUpdates(mockLog).handleProfileUpdated(mockMessage({
|
||||
uid: uid
|
||||
})).then(function () {
|
||||
assert.equal(mockLog.messages.length, 0)
|
||||
assert.equal(mockPush.notifyProfileUpdated.callCount, 2)
|
||||
var args = mockPush.notifyProfileUpdated.getCall(1).args
|
||||
assert.deepEqual(args[0], Buffer.from(uid, 'hex'))
|
||||
})
|
||||
}
|
||||
)
|
||||
})
|
Загрузка…
Ссылка в новой задаче