From 340ad2b518d74e8a8627331d4ccaf2a0de352c71 Mon Sep 17 00:00:00 2001 From: Josh Harvey Date: Mon, 20 Mar 2017 16:43:40 +0200 Subject: [PATCH] WIP --- lib/admin/server.js | 4 +++ lib/app.js | 2 +- lib/plugins.js | 3 ++ lib/route-helpers.js | 26 ++++++++++++++- lib/routes.js | 6 +++- lib/settings-loader.js | 73 +++++++++++++++++++++++++++++++----------- public/elm.js | 8 ++--- public/styles.css | 45 ++++++++++++++++++-------- 8 files changed, 129 insertions(+), 38 deletions(-) diff --git a/lib/admin/server.js b/lib/admin/server.js index 9a70f0dc..0da87fd9 100644 --- a/lib/admin/server.js +++ b/lib/admin/server.js @@ -11,10 +11,13 @@ function machinesLastPing () { const sql = `select name, min(extract(epoch from (now() - machine_events.created))) as age from machine_events, devices where machine_events.device_id = devices.device_id + and devices.paired group by name` return db.any(sql) .then(r => { + if (r.length === 0) return 'No paired machines' + const downRows = r.filter(row => row.age > CONSIDERED_UP_SECS) if (downRows.length === 0) return 'All machines are up' @@ -54,6 +57,7 @@ function status () { }] return {up, lastPing, rates, machineStatus} }) + .catch(() => ({up, lastPing, rates: [], machineStatus})) }) }) } diff --git a/lib/app.js b/lib/app.js index 484d5c85..08be5368 100644 --- a/lib/app.js +++ b/lib/app.js @@ -48,7 +48,7 @@ function runOnce () { ? http.createServer(routes.app) : https.createServer(httpsServerOptions, routes.app) - const port = 3000 + const port = argv.port || 3000 const localPort = 3030 const localServer = http.createServer(routes.localApp) diff --git a/lib/plugins.js b/lib/plugins.js index a68684d0..16b8a9ff 100644 --- a/lib/plugins.js +++ b/lib/plugins.js @@ -75,6 +75,9 @@ function plugins (settings, deviceId) { function buildCartridges () { const config = configManager.machineScoped(deviceId, settings.config) + + if (!config.cashOutEnabled) return Promise.resolve() + const cartridges = [ config.topCashOutDenomination, config.bottomCashOutDenomination ] const virtualCartridges = [config.virtualCashOutDenomination] diff --git a/lib/route-helpers.js b/lib/route-helpers.js index 50a22d94..a298ef3a 100644 --- a/lib/route-helpers.js +++ b/lib/route-helpers.js @@ -5,6 +5,7 @@ const db = require('./db') const dbm = require('./postgresql_interface') const T = require('./time') const BN = require('./bn') +const settingsLoader = require('./settings-loader') const TRANSACTION_EXPIRATION = 2 * T.days @@ -89,4 +90,27 @@ function updateDeviceConfigVersion (versionId) { return db.none('update devices set user_config_id=$1', [versionId]) } -module.exports = {stateChange, fetchPhoneTx, fetchStatusTx, updateDeviceConfigVersion} +function updateMachineDefaults (deviceId) { + const newFields = [{ + fieldLocator: { + fieldScope: { + crypto: 'global', + machine: deviceId + }, + code: 'cashOutEnabled', + fieldType: 'onOff', + fieldClass: null + }, + fieldValue: { + fieldType: 'onOff', + value: false + } + }] + + return settingsLoader.loadLatest() + .then(settings => { + return settingsLoader.save({config: settingsLoader.mergeValues(settings.config, newFields)}) + }) +} + +module.exports = {stateChange, fetchPhoneTx, fetchStatusTx, updateDeviceConfigVersion, updateMachineDefaults} diff --git a/lib/routes.js b/lib/routes.js index 23cbb82f..5d4a2580 100644 --- a/lib/routes.js +++ b/lib/routes.js @@ -150,7 +150,11 @@ function pair (req, res, next) { return pairing.pair(token, deviceId) .then(valid => { - if (valid) return res.end() + if (valid) { + return helpers.updateMachineDefaults(deviceId) + .then(() => res.json({status: 'paired'})) + } + throw httpError('Pairing failed') }) .catch(next) diff --git a/lib/settings-loader.js b/lib/settings-loader.js index 3701b2ee..00cde6aa 100644 --- a/lib/settings-loader.js +++ b/lib/settings-loader.js @@ -6,27 +6,68 @@ const argv = require('minimist')(process.argv.slice(2)) const pify = require('pify') const db = require('./db') +const schema = require('../lamassu-schema.json') + +const mapWithKey = _.map.convert({cap: false}) let settingsCache +function expandFixture (fixture) { + const deviceId = argv.machine + + function findField (code) { + const field = _.find(_.matchesProperty('code', code), schema.fields) + const group = _.find(r => _.includes(code, r.fields), schema.groups) + + if (!field || !group) { + throw new Error('No such field from fixture: ' + code) + } + + return _.merge({cryptoScope: group.cryptoScope, machineScope: group.machineScope}, field) + } + + function expand (value, code) { + const field = findField(code) + + const machine = field.machineScope === 'specific' + ? deviceId + : 'global' + + const crypto = field.cryptoScope === 'specific' + ? 'BTC' + : 'global' + + return { + fieldLocator: { + fieldScope: {crypto, machine}, + code, + fieldType: field.fieldType, + fieldClass: field.fieldClass + }, + fieldValue: { + fieldType: field.fieldType, + value + } + } + } + + return mapWithKey(expand, fixture) +} + function loadFixture () { const fixture = argv.fixture - const machine = argv.machine + const deviceId = argv.machine - if (fixture && !machine) throw new Error('Missing --machine parameter for --fixture') + if (fixture && !deviceId) throw new Error('Missing --machine parameter for --fixture') const fixturePath = fixture => path.resolve(__dirname, '..', 'test', 'fixtures', fixture + '.json') const promise = fixture ? pify(fs.readFile)(fixturePath(fixture)).then(JSON.parse) - : Promise.resolve([]) + : Promise.resolve({}) return promise - .then(values => _.map(v => { - return (v.fieldLocator.fieldScope.machine === 'machine') - ? _.set('fieldLocator.fieldScope.machine', machine, v) - : v - }, values)) + .then(expandFixture) } function isEquivalentField (a, b) { @@ -60,15 +101,14 @@ function loadLatest () { } function loadConfig (versionId) { + if (argv.fixture) return loadFixture() + const sql = `select data from user_config where id=$1 and type=$2` - return Promise.all([db.oneOrNone(sql, [versionId, 'config']), loadFixture()]) - .then(([row, fixture]) => { - const config = row ? row.data.config : [] - return mergeValues(config, fixture) - }) + return db.oneOrNone(sql, [versionId, 'config']) + .then(row => row ? row.data.config : []) } function loadLatestConfig () { @@ -78,11 +118,8 @@ function loadLatestConfig () { order by id desc limit 1` - return Promise.all([db.oneOrNone(sql, ['config']), loadFixture()]) - .then(([row, fixture]) => { - const config = row ? row.data.config : [] - return mergeValues(config, fixture) - }) + return db.oneOrNone(sql, ['config']) + .then(row => row ? row.data.config : []) } function loadAccounts () { diff --git a/public/elm.js b/public/elm.js index 07879f8a..d04077d1 100644 --- a/public/elm.js +++ b/public/elm.js @@ -24292,7 +24292,7 @@ var _user$project$TransactionTypes$CashInTxRec = function (a) { return function (i) { return function (j) { return function (k) { - return {id: a, machineName: b, toAddress: c, cryptoAtoms: d, cryptoCode: e, fiat: f, currencyCode: g, txHash: h, phone: i, error: j, created: k}; + return {id: a, machineName: b, toAddress: c, cryptoAtoms: d, cryptoCode: e, fiat: f, fiatCode: g, txHash: h, phone: i, error: j, created: k}; }; }; }; @@ -24320,7 +24320,7 @@ var _user$project$TransactionTypes$CashOutTxRec = function (a) { return function (n) { return function (o) { return function (p) { - return {id: a, machineName: b, toAddress: c, cryptoAtoms: d, cryptoCode: e, fiat: f, currencyCode: g, txHash: h, status: i, dispensed: j, notified: k, redeemed: l, phone: m, error: n, created: o, confirmed: p}; + return {id: a, machineName: b, toAddress: c, cryptoAtoms: d, cryptoCode: e, fiat: f, fiatCode: g, txHash: h, status: i, dispensed: j, notified: k, redeemed: l, phone: m, error: n, created: o, confirmed: p}; }; }; }; @@ -24388,7 +24388,7 @@ var _user$project$TransactionDecoder$cashInTxDecoder = A3( _elm_lang$core$Json_Decode$nullable(_elm_lang$core$Json_Decode$string), A3( _NoRedInk$elm_decode_pipeline$Json_Decode_Pipeline$required, - 'currencyCode', + 'fiatCode', _elm_lang$core$Json_Decode$string, A3( _NoRedInk$elm_decode_pipeline$Json_Decode_Pipeline$required, @@ -24453,7 +24453,7 @@ var _user$project$TransactionDecoder$cashOutTxDecoder = A3( _elm_lang$core$Json_Decode$nullable(_elm_lang$core$Json_Decode$string), A3( _NoRedInk$elm_decode_pipeline$Json_Decode_Pipeline$required, - 'currencyCode', + 'fiatCode', _elm_lang$core$Json_Decode$string, A3( _NoRedInk$elm_decode_pipeline$Json_Decode_Pipeline$required, diff --git a/public/styles.css b/public/styles.css index 31afdad7..093f9660 100644 --- a/public/styles.css +++ b/public/styles.css @@ -1,5 +1,5 @@ body { - font-family: Brandon Text; + font-family: Nunito, sans-serif; margin: 0; } @@ -45,14 +45,15 @@ p { border-radius: 3px; padding: 6px; text-align: left; - font-family: Fira Code; + font-family: Inconsolata, monospace; + font-size: 14px; font-weight: 600; width: 90%; outline: none; } .lamassuAdminButtonRow { - text-align: left; + text-align: right; } .lamassuAdminButton { @@ -95,10 +96,9 @@ p { } .lamassuAdminContent { - padding: 20px; - background-color: #f6f6f4; + margin: 20px; + background-color: #ffffff; border-radius: 5px; - width: 100%; } .lamassuAdminCryptoTabs { @@ -140,6 +140,24 @@ p { margin-bottom: 10px; } +.lamassuAdminConfigContainer { + padding: 20px 60px; + border-radius: 0px 7px 7px 7px; + background-color: #f6f6f4; + margin: 0 0 10px; + animation: fadein 0.8s; + overflow: hidden; + min-height: 15em; + min-width: 20em; +} + +.lamassuAdminNoInput { + font-family: Inconsolata, monospace; + color: #5f5f56; + font-weight: normal; + text-align: left !important; +} + .lamassuAdminTxTable { border-radius: 7px; margin: 20px 0; @@ -161,7 +179,7 @@ p { } .lamassuAdminTxTable tbody { - font-family: Fira Code; + font-family: Inconsolata, monospace; color: #5f5f56; } @@ -218,7 +236,7 @@ p { .lamassuAdminConfigTable .lamassuAdminSelectizeContainer .lamassuAdminNoOptions { background-color: #fcfcfa; - font-size: 11px; + font-size: 14px; font-weight: 500; color: #5f5f56; padding: 5px; @@ -274,7 +292,7 @@ p { color: #ffffff; padding: 4px 4px 3px; margin: 0 1px; - font-family: Fira Code; + font-family: Inconsolata, monospace; font-size: 70%; font-weight: normal; border-radius: 3px; @@ -285,8 +303,8 @@ p { } .lamassuAdminConfigTable .lamassuAdminSelectizeContainer .lamassuAdminSingleItemContainer .lamassuAdminSelectedItem { - font-family: Fira Code; - font-size: 11px; + font-family: Inconsolata, monospace; + font-size: 14px; padding: 0; border-radius: 0; } @@ -324,8 +342,9 @@ p { padding: 6px; text-align: right; width: 100%; - font-family: Fira Code; + font-family: Inconsolata, monospace; font-weight: 600; + font-size: 14px; outline: none; background-color: #ffffff; } @@ -334,7 +353,7 @@ p { background-color: #fcfcfa; height: 25px; line-height: 25px; - font-size: 11px; + font-size: 14px; font-weight: 500; color: #5f5f56; text-align: center;