WIP
This commit is contained in:
parent
a35e9d2d44
commit
340ad2b518
8 changed files with 129 additions and 38 deletions
|
|
@ -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}))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
|
|
|||
|
|
@ -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}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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 () {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue