This commit is contained in:
Josh Harvey 2017-03-20 16:43:40 +02:00
parent a35e9d2d44
commit 340ad2b518
8 changed files with 129 additions and 38 deletions

View file

@ -11,10 +11,13 @@ function machinesLastPing () {
const sql = `select name, min(extract(epoch from (now() - machine_events.created))) as age const sql = `select name, min(extract(epoch from (now() - machine_events.created))) as age
from machine_events, devices from machine_events, devices
where machine_events.device_id = devices.device_id where machine_events.device_id = devices.device_id
and devices.paired
group by name` group by name`
return db.any(sql) return db.any(sql)
.then(r => { .then(r => {
if (r.length === 0) return 'No paired machines'
const downRows = r.filter(row => row.age > CONSIDERED_UP_SECS) const downRows = r.filter(row => row.age > CONSIDERED_UP_SECS)
if (downRows.length === 0) return 'All machines are up' if (downRows.length === 0) return 'All machines are up'
@ -54,6 +57,7 @@ function status () {
}] }]
return {up, lastPing, rates, machineStatus} return {up, lastPing, rates, machineStatus}
}) })
.catch(() => ({up, lastPing, rates: [], machineStatus}))
}) })
}) })
} }

View file

@ -48,7 +48,7 @@ function runOnce () {
? http.createServer(routes.app) ? http.createServer(routes.app)
: https.createServer(httpsServerOptions, routes.app) : https.createServer(httpsServerOptions, routes.app)
const port = 3000 const port = argv.port || 3000
const localPort = 3030 const localPort = 3030
const localServer = http.createServer(routes.localApp) const localServer = http.createServer(routes.localApp)

View file

@ -75,6 +75,9 @@ function plugins (settings, deviceId) {
function buildCartridges () { function buildCartridges () {
const config = configManager.machineScoped(deviceId, settings.config) const config = configManager.machineScoped(deviceId, settings.config)
if (!config.cashOutEnabled) return Promise.resolve()
const cartridges = [ config.topCashOutDenomination, const cartridges = [ config.topCashOutDenomination,
config.bottomCashOutDenomination ] config.bottomCashOutDenomination ]
const virtualCartridges = [config.virtualCashOutDenomination] const virtualCartridges = [config.virtualCashOutDenomination]

View file

@ -5,6 +5,7 @@ const db = require('./db')
const dbm = require('./postgresql_interface') const dbm = require('./postgresql_interface')
const T = require('./time') const T = require('./time')
const BN = require('./bn') const BN = require('./bn')
const settingsLoader = require('./settings-loader')
const TRANSACTION_EXPIRATION = 2 * T.days const TRANSACTION_EXPIRATION = 2 * T.days
@ -89,4 +90,27 @@ function updateDeviceConfigVersion (versionId) {
return db.none('update devices set user_config_id=$1', [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}

View file

@ -150,7 +150,11 @@ function pair (req, res, next) {
return pairing.pair(token, deviceId) return pairing.pair(token, deviceId)
.then(valid => { .then(valid => {
if (valid) return res.end() if (valid) {
return helpers.updateMachineDefaults(deviceId)
.then(() => res.json({status: 'paired'}))
}
throw httpError('Pairing failed') throw httpError('Pairing failed')
}) })
.catch(next) .catch(next)

View file

@ -6,27 +6,68 @@ const argv = require('minimist')(process.argv.slice(2))
const pify = require('pify') const pify = require('pify')
const db = require('./db') const db = require('./db')
const schema = require('../lamassu-schema.json')
const mapWithKey = _.map.convert({cap: false})
let settingsCache 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 () { function loadFixture () {
const fixture = argv.fixture 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 fixturePath = fixture => path.resolve(__dirname, '..', 'test', 'fixtures', fixture + '.json')
const promise = fixture const promise = fixture
? pify(fs.readFile)(fixturePath(fixture)).then(JSON.parse) ? pify(fs.readFile)(fixturePath(fixture)).then(JSON.parse)
: Promise.resolve([]) : Promise.resolve({})
return promise return promise
.then(values => _.map(v => { .then(expandFixture)
return (v.fieldLocator.fieldScope.machine === 'machine')
? _.set('fieldLocator.fieldScope.machine', machine, v)
: v
}, values))
} }
function isEquivalentField (a, b) { function isEquivalentField (a, b) {
@ -60,15 +101,14 @@ function loadLatest () {
} }
function loadConfig (versionId) { function loadConfig (versionId) {
if (argv.fixture) return loadFixture()
const sql = `select data const sql = `select data
from user_config from user_config
where id=$1 and type=$2` where id=$1 and type=$2`
return Promise.all([db.oneOrNone(sql, [versionId, 'config']), loadFixture()]) return db.oneOrNone(sql, [versionId, 'config'])
.then(([row, fixture]) => { .then(row => row ? row.data.config : [])
const config = row ? row.data.config : []
return mergeValues(config, fixture)
})
} }
function loadLatestConfig () { function loadLatestConfig () {
@ -78,11 +118,8 @@ function loadLatestConfig () {
order by id desc order by id desc
limit 1` limit 1`
return Promise.all([db.oneOrNone(sql, ['config']), loadFixture()]) return db.oneOrNone(sql, ['config'])
.then(([row, fixture]) => { .then(row => row ? row.data.config : [])
const config = row ? row.data.config : []
return mergeValues(config, fixture)
})
} }
function loadAccounts () { function loadAccounts () {

View file

@ -24292,7 +24292,7 @@ var _user$project$TransactionTypes$CashInTxRec = function (a) {
return function (i) { return function (i) {
return function (j) { return function (j) {
return function (k) { 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 (n) {
return function (o) { return function (o) {
return function (p) { 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), _elm_lang$core$Json_Decode$nullable(_elm_lang$core$Json_Decode$string),
A3( A3(
_NoRedInk$elm_decode_pipeline$Json_Decode_Pipeline$required, _NoRedInk$elm_decode_pipeline$Json_Decode_Pipeline$required,
'currencyCode', 'fiatCode',
_elm_lang$core$Json_Decode$string, _elm_lang$core$Json_Decode$string,
A3( A3(
_NoRedInk$elm_decode_pipeline$Json_Decode_Pipeline$required, _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), _elm_lang$core$Json_Decode$nullable(_elm_lang$core$Json_Decode$string),
A3( A3(
_NoRedInk$elm_decode_pipeline$Json_Decode_Pipeline$required, _NoRedInk$elm_decode_pipeline$Json_Decode_Pipeline$required,
'currencyCode', 'fiatCode',
_elm_lang$core$Json_Decode$string, _elm_lang$core$Json_Decode$string,
A3( A3(
_NoRedInk$elm_decode_pipeline$Json_Decode_Pipeline$required, _NoRedInk$elm_decode_pipeline$Json_Decode_Pipeline$required,

View file

@ -1,5 +1,5 @@
body { body {
font-family: Brandon Text; font-family: Nunito, sans-serif;
margin: 0; margin: 0;
} }
@ -45,14 +45,15 @@ p {
border-radius: 3px; border-radius: 3px;
padding: 6px; padding: 6px;
text-align: left; text-align: left;
font-family: Fira Code; font-family: Inconsolata, monospace;
font-size: 14px;
font-weight: 600; font-weight: 600;
width: 90%; width: 90%;
outline: none; outline: none;
} }
.lamassuAdminButtonRow { .lamassuAdminButtonRow {
text-align: left; text-align: right;
} }
.lamassuAdminButton { .lamassuAdminButton {
@ -95,10 +96,9 @@ p {
} }
.lamassuAdminContent { .lamassuAdminContent {
padding: 20px; margin: 20px;
background-color: #f6f6f4; background-color: #ffffff;
border-radius: 5px; border-radius: 5px;
width: 100%;
} }
.lamassuAdminCryptoTabs { .lamassuAdminCryptoTabs {
@ -140,6 +140,24 @@ p {
margin-bottom: 10px; 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 { .lamassuAdminTxTable {
border-radius: 7px; border-radius: 7px;
margin: 20px 0; margin: 20px 0;
@ -161,7 +179,7 @@ p {
} }
.lamassuAdminTxTable tbody { .lamassuAdminTxTable tbody {
font-family: Fira Code; font-family: Inconsolata, monospace;
color: #5f5f56; color: #5f5f56;
} }
@ -218,7 +236,7 @@ p {
.lamassuAdminConfigTable .lamassuAdminSelectizeContainer .lamassuAdminNoOptions { .lamassuAdminConfigTable .lamassuAdminSelectizeContainer .lamassuAdminNoOptions {
background-color: #fcfcfa; background-color: #fcfcfa;
font-size: 11px; font-size: 14px;
font-weight: 500; font-weight: 500;
color: #5f5f56; color: #5f5f56;
padding: 5px; padding: 5px;
@ -274,7 +292,7 @@ p {
color: #ffffff; color: #ffffff;
padding: 4px 4px 3px; padding: 4px 4px 3px;
margin: 0 1px; margin: 0 1px;
font-family: Fira Code; font-family: Inconsolata, monospace;
font-size: 70%; font-size: 70%;
font-weight: normal; font-weight: normal;
border-radius: 3px; border-radius: 3px;
@ -285,8 +303,8 @@ p {
} }
.lamassuAdminConfigTable .lamassuAdminSelectizeContainer .lamassuAdminSingleItemContainer .lamassuAdminSelectedItem { .lamassuAdminConfigTable .lamassuAdminSelectizeContainer .lamassuAdminSingleItemContainer .lamassuAdminSelectedItem {
font-family: Fira Code; font-family: Inconsolata, monospace;
font-size: 11px; font-size: 14px;
padding: 0; padding: 0;
border-radius: 0; border-radius: 0;
} }
@ -324,8 +342,9 @@ p {
padding: 6px; padding: 6px;
text-align: right; text-align: right;
width: 100%; width: 100%;
font-family: Fira Code; font-family: Inconsolata, monospace;
font-weight: 600; font-weight: 600;
font-size: 14px;
outline: none; outline: none;
background-color: #ffffff; background-color: #ffffff;
} }
@ -334,7 +353,7 @@ p {
background-color: #fcfcfa; background-color: #fcfcfa;
height: 25px; height: 25px;
line-height: 25px; line-height: 25px;
font-size: 11px; font-size: 14px;
font-weight: 500; font-weight: 500;
color: #5f5f56; color: #5f5f56;
text-align: center; text-align: center;