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

feat(account): add Account Preferences #205

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions fxa-auth-db-server/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ function createServer(db) {
api.post('/account/:id/verifyEmail', withIdAndBody(db.verifyEmail))
api.post('/account/:id/locale', withIdAndBody(db.updateLocale))
api.get('/account/:id/sessions', withIdAndBody(db.sessions))
api.get('/account/:id/preferences', withIdAndBody(db.getAccountPreferences))
api.post('/account/:id/preferences', withIdAndBody(db.setAccountPreferences))

api.get('/sessionToken/:id', withIdAndBody(db.sessionToken))
api.del('/sessionToken/:id', withIdAndBody(db.deleteSessionToken))
Expand Down
27 changes: 27 additions & 0 deletions fxa-auth-db-server/test/backend/remote.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */

'use strict'

var test = require('tap').test

var crypto = require('crypto')
Expand Down Expand Up @@ -1117,6 +1119,31 @@ module.exports = function(cfg, server) {
}
)

test(
'account preferences',
t => {
t.plan(9)
const user = fake.newUserDataHex()
const uid = user.accountId
return client.getThen('/account/' + uid + '/preferences')
.then(r => {
respOk(t, r)
t.equal(r.obj.signinConfirmation, 0)
return client.postThen('/account/' + uid + '/preferences', {
signinConfirmation: 1
})
})
.then(r => {
respOkEmpty(t, r)
return client.getThen('/account/' + uid + '/preferences')
})
.then(r => {
respOk(t, r)
t.equal(r.obj.signinConfirmation, 1)
})
}
)

test(
'GET an unknown path',
function (t) {
Expand Down
51 changes: 36 additions & 15 deletions lib/db/mem.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,26 @@ const ip = require('ip')
const dbUtil = require('./util')

// our data stores
var accounts = {}
var uidByNormalizedEmail = {}
var sessionTokens = {}
var keyFetchTokens = {}
var unverifiedTokens = {}
var accountResetTokens = {}
var passwordChangeTokens = {}
var passwordForgotTokens = {}
var reminders = {}
var securityEvents = {}
var unblockCodes = {}
var emailBounces = {}

var DEVICE_FIELDS = [
const accounts = {}
const uidByNormalizedEmail = {}
const sessionTokens = {}
const keyFetchTokens = {}
const unverifiedTokens = {}
const accountResetTokens = {}
const passwordChangeTokens = {}
const passwordForgotTokens = {}
const reminders = {}
const securityEvents = {}
const unblockCodes = {}
const emailBounces = {}
const accountPreferences = {}

const DEFAULT_ACCOUNT_PREFERENCES = Object.freeze({
signinConfirmation: 0
})


const DEVICE_FIELDS = [
'sessionTokenId',
'name',
'type',
Expand All @@ -33,7 +39,7 @@ var DEVICE_FIELDS = [
'callbackAuthKey'
]

var SESSION_FIELDS = [
const SESSION_FIELDS = [
'uaBrowser',
'uaBrowserVersion',
'uaOS',
Expand Down Expand Up @@ -910,6 +916,21 @@ module.exports = function (log, error) {
return P.resolve(emailBounces[email] || [])
}

Memory.prototype.setAccountPreferences = function (uid, values) {
uid = uid.toString('hex')
const prefs = accountPreferences[uid]
|| (accountPreferences[uid] = extend({}, DEFAULT_ACCOUNT_PREFERENCES))
prefs.signinConfirmation = values.signinConfirmation
return P.resolve({})
}

Memory.prototype.getAccountPreferences = function (uid) {
uid = uid.toString('hex')
const prefs = accountPreferences[uid]
|| (accountPreferences[uid] = extend({}, DEFAULT_ACCOUNT_PREFERENCES))
return P.resolve(prefs)
}

// UTILITY FUNCTIONS

Memory.prototype.ping = function () {
Expand Down
12 changes: 11 additions & 1 deletion lib/db/mysql.js
Original file line number Diff line number Diff line change
Expand Up @@ -496,7 +496,7 @@ module.exports = function (log, error) {
// Delete : sessionTokens, keyFetchTokens, accountResetTokens, passwordChangeTokens,
// passwordForgotTokens, accounts, devices, unverifiedTokens
// Where : uid = $1
var DELETE_ACCOUNT = 'CALL deleteAccount_11(?)'
var DELETE_ACCOUNT = 'CALL deleteAccount_12(?)'

MySql.prototype.deleteAccount = function (uid) {
return this.write(DELETE_ACCOUNT, [uid])
Expand Down Expand Up @@ -1092,5 +1092,15 @@ module.exports = function (log, error) {
.then(result => result[0])
}

const SET_PREFERENCES = 'CALL setAccountPreferences_1(?, ?)'
MySql.prototype.setAccountPreferences = function (uid, values) {
return this.write(SET_PREFERENCES, [uid, values.signinConfirmation])
}

const GET_PREFERENCES = 'CALL getAccountPreferences_1(?)'
MySql.prototype.getAccountPreferences = function (uid) {
return this.readFirstResult(GET_PREFERENCES, [uid])
}

return MySql
}
2 changes: 1 addition & 1 deletion lib/db/patch.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@

// The expected patch level of the database. Update if you add a new
// patch in the ./schema/ directory.
module.exports.level = 41
module.exports.level = 42
62 changes: 62 additions & 0 deletions lib/db/schema/patch-041-042.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
CREATE TABLE IF NOT EXISTS accountPreferences (
uid BINARY(16) PRIMARY KEY NOT NULL,
signinConfirmation TINYINT NOT NULL DEFAULT 0
) ENGINE=InnoDB;

CREATE PROCEDURE `setAccountPreferences_1` (
IN inUid BINARY(16),
IN inSigninConfirmation TINYINT
)
BEGIN
INSERT INTO accountPreferences(
uid,
signinConfirmation
)
VALUES(
inUid,
inSigninConfirmation
)
ON DUPLICATE KEY UPDATE
signinConfirmation = inSigninConfirmation
;
END;

CREATE PROCEDURE `getAccountPreferences_1` (
IN inUid BINARY(16)
)
BEGIN
INSERT IGNORE INTO accountPreferences (uid) VALUES (inUid);
SELECT
signinConfirmation
FROM accountPreferences
WHERE uid = inUid
LIMIT 1;
END;

CREATE PROCEDURE `deleteAccount_12` (
IN `uidArg` BINARY(16)
)
BEGIN
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
ROLLBACK;
RESIGNAL;
END;

START TRANSACTION;

DELETE FROM sessionTokens WHERE uid = uidArg;
DELETE FROM keyFetchTokens WHERE uid = uidArg;
DELETE FROM accountResetTokens WHERE uid = uidArg;
DELETE FROM passwordChangeTokens WHERE uid = uidArg;
DELETE FROM passwordForgotTokens WHERE uid = uidArg;
DELETE FROM accounts WHERE uid = uidArg;
DELETE FROM devices WHERE uid = uidArg;
DELETE FROM unverifiedTokens WHERE uid = uidArg;
DELETE FROM unblockCodes WHERE uid = uidArg;
DELETE FROM accountPreferences WHERE uid = uidArg;

COMMIT;
END;

UPDATE dbMetadata SET value = '42' WHERE name = 'schema-patch-level';
9 changes: 9 additions & 0 deletions lib/db/schema/patch-042-041.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
-- Rollback; commented out to prevent accidental running
-- in production.

-- DROP TABLE `accountPreferences`;
-- DROP PROCEDURE `getAccountPreferences_1`;
-- DROP PROCEDURE `setAccountPreferences_1`;
-- DROP PROCEDURE `deleteAccount_12`;

-- UPDATE dbMetadata SET value = '41' WHERE name = 'schema-patch-level';