new admin structure
This commit is contained in:
parent
7d82874916
commit
c2282e61b4
17 changed files with 5768 additions and 1204 deletions
|
|
@ -14,15 +14,16 @@ const got = require('got')
|
|||
const morgan = require('morgan')
|
||||
const helmet = require('helmet')
|
||||
|
||||
const machineLoader = require('../lib/machine-loader')
|
||||
const T = require('../lib/time')
|
||||
const logger = require('../lib/logger')
|
||||
|
||||
const accounts = require('../lib/admin/accounts')
|
||||
const machines = require('../lib/admin/machines')
|
||||
const config = require('../lib/admin/config')
|
||||
const login = require('../lib/admin/login')
|
||||
const pairing = require('../lib/admin/pairing')
|
||||
const server = require('../lib/admin/server')
|
||||
const transactions = require('../lib/admin/transactions')
|
||||
const T = require('../lib/time')
|
||||
const logger = require('../lib/logger')
|
||||
|
||||
const NEVER = new Date(Date.now() + 100 * T.years)
|
||||
|
||||
|
|
@ -118,19 +119,18 @@ app.get('/api/accounts/account/:account', (req, res) => {
|
|||
})
|
||||
|
||||
app.get('/api/machines', (req, res) => {
|
||||
machines.getMachines()
|
||||
machineLoader.getMachineNames()
|
||||
.then(r => res.send({machines: r}))
|
||||
})
|
||||
|
||||
app.post('/api/machines', (req, res) => {
|
||||
machines.setMachine(req.body)
|
||||
.then(() => machines.getMachines())
|
||||
machineLoader.setMachine(req.body)
|
||||
.then(() => machineLoader.getMachineNames())
|
||||
.then(r => res.send({machines: r}))
|
||||
.then(() => dbNotify())
|
||||
})
|
||||
|
||||
app.get('/api/status', (req, res, next) => {
|
||||
console.log('DEBUG100')
|
||||
return Promise.all([server.status(), config.validateCurrentConfig()])
|
||||
.then(([serverStatus, invalidConfigGroups]) => res.send({
|
||||
server: serverStatus,
|
||||
|
|
|
|||
|
|
@ -1,18 +1,26 @@
|
|||
{
|
||||
"groups": [
|
||||
{
|
||||
"code": "definition",
|
||||
"display": "Definition",
|
||||
"cryptoScope": "global",
|
||||
"machineScope": "specific",
|
||||
"fields": [
|
||||
"machineName",
|
||||
"machineModel",
|
||||
"machineLocation"
|
||||
]
|
||||
},
|
||||
{
|
||||
"code": "setup",
|
||||
"display": "Setup",
|
||||
"cryptoScope": "global",
|
||||
"machineScope": "both",
|
||||
"fields": [
|
||||
"machineName",
|
||||
"machineModel",
|
||||
"fiatCurrency",
|
||||
"country",
|
||||
"machineLanguages",
|
||||
"cryptoCurrencies",
|
||||
"machineLocation"
|
||||
"cryptoCurrencies"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -35,8 +43,8 @@
|
|||
"machineScope": "both",
|
||||
"fields": [
|
||||
"cashInCommission",
|
||||
"cashInFee",
|
||||
"cashOutCommission",
|
||||
"cashInFee",
|
||||
"cashOutFee"
|
||||
]
|
||||
},
|
||||
|
|
@ -76,7 +84,7 @@
|
|||
"notificationsSMSEnabled",
|
||||
"sms",
|
||||
"email",
|
||||
"balanceThreshold"
|
||||
"balancesThreshold"
|
||||
]
|
||||
}
|
||||
],
|
||||
|
|
@ -163,17 +171,6 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"code": "lowBalanceMargin",
|
||||
"displayTop": "Low balance",
|
||||
"displayBottom": "Margin",
|
||||
"fieldType": "percentage",
|
||||
"fieldClass": null,
|
||||
"cryptoScope": "both",
|
||||
"machineScope": "both",
|
||||
"fieldValidation": [{"code": "required"}],
|
||||
"default": 5
|
||||
},
|
||||
{
|
||||
"code": "zeroConfLimit",
|
||||
"displayTop": "0-conf",
|
||||
|
|
@ -220,8 +217,8 @@
|
|||
"code": "fiatCurrency",
|
||||
"displayBottom": "Fiat Currency",
|
||||
"fieldType": "fiatCurrency",
|
||||
"cryptoScope": "both",
|
||||
"machineScope": "both",
|
||||
"cryptoScope": "global",
|
||||
"machineScope": "global",
|
||||
"fieldClass": null,
|
||||
"fieldValidation": [
|
||||
{
|
||||
|
|
@ -398,6 +395,8 @@
|
|||
},
|
||||
{
|
||||
"code": "machineName",
|
||||
"cryptoScope": "global",
|
||||
"machineScope": "specific",
|
||||
"displayBottom": "Name",
|
||||
"fieldType": "string",
|
||||
"fieldClass": null,
|
||||
|
|
@ -405,6 +404,8 @@
|
|||
},
|
||||
{
|
||||
"code": "machineModel",
|
||||
"cryptoScope": "global",
|
||||
"machineScope": "specific",
|
||||
"displayBottom": "Model",
|
||||
"fieldType": "string",
|
||||
"fieldClass": null,
|
||||
|
|
@ -489,10 +490,10 @@
|
|||
"fieldValidation": [{"code": "required"}]
|
||||
},
|
||||
{
|
||||
"code": "lowBalanceThreshold",
|
||||
"displayTop": "Low balance",
|
||||
"code": "balancesThreshold",
|
||||
"displayTop": "Balances",
|
||||
"displayBottom": "Threshold",
|
||||
"fieldType": "integer",
|
||||
"fieldType": "percentage",
|
||||
"fieldClass": null,
|
||||
"enabledIf": [
|
||||
"notificationsEnabled"
|
||||
|
|
|
|||
|
|
@ -12,8 +12,7 @@ const db = require('../db')
|
|||
const options = require('../options')
|
||||
const configManager = require('../config-manager')
|
||||
const configValidate = require('../config-validate')
|
||||
|
||||
const machines = require('./machines')
|
||||
const machineLoader = require('../machine-loader')
|
||||
|
||||
function fetchSchema () {
|
||||
const schemaPath = path.resolve(options.lamassuServerPath, 'lamassu-schema.json')
|
||||
|
|
@ -64,7 +63,7 @@ function getField (schema, group, fieldCode) {
|
|||
return R.merge(R.pick(['cryptoScope', 'machineScope'], group), field)
|
||||
}
|
||||
|
||||
const fetchMachines = () => machines.getMachines()
|
||||
const fetchMachines = () => machineLoader.getMachines()
|
||||
.then(machineList => machineList.map(r => r.deviceId))
|
||||
|
||||
function validateCurrentConfig () {
|
||||
|
|
@ -134,7 +133,7 @@ const supportedLanguages = languageRec.supported
|
|||
const languages = supportedLanguages.map(mapLanguage).filter(r => r)
|
||||
|
||||
function fetchData () {
|
||||
return machines.getMachines()
|
||||
return machineLoader.getMachineNames()
|
||||
.then(machineList => ({
|
||||
currencies: massageCurrencies(currencies),
|
||||
cryptoCurrencies: [{crypto: 'BTC', display: 'Bitcoin'}, {crypto: 'ETH', display: 'Ethereum'}],
|
||||
|
|
@ -163,36 +162,8 @@ function fetchData () {
|
|||
function saveConfigGroup (results) {
|
||||
if (results.values.length === 0) return fetchConfigGroup(results.groupCode)
|
||||
|
||||
return configValidate.ensureConstraints(results.values)
|
||||
.then(fetchConfig)
|
||||
.then(oldValues => {
|
||||
results.values.forEach(newValue => {
|
||||
const oldValueIndex = oldValues
|
||||
.findIndex(old => old.fieldLocator.code === newValue.fieldLocator.code &&
|
||||
old.fieldLocator.fieldScope.crypto === newValue.fieldLocator.fieldScope.crypto &&
|
||||
old.fieldLocator.fieldScope.machine === newValue.fieldLocator.fieldScope.machine
|
||||
)
|
||||
|
||||
const existingValue = oldValueIndex > -1 &&
|
||||
oldValues[oldValueIndex]
|
||||
|
||||
if (existingValue) {
|
||||
// Delete value record
|
||||
if (R.isNil(newValue.fieldValue)) {
|
||||
oldValues.splice(oldValueIndex, 1)
|
||||
return
|
||||
}
|
||||
|
||||
existingValue.fieldValue = newValue.fieldValue
|
||||
return
|
||||
}
|
||||
|
||||
if (!R.isNil(newValue.fieldValue)) oldValues.push(newValue)
|
||||
})
|
||||
|
||||
return settingsLoader.save(oldValues)
|
||||
return settingsLoader.modifyConfig(results.values)
|
||||
.then(() => fetchConfigGroup(results.groupCode))
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
|
|
|
|||
|
|
@ -1,33 +0,0 @@
|
|||
const db = require('../db')
|
||||
const pairing = require('./pairing')
|
||||
|
||||
function getMachines () {
|
||||
return db.any('select * from devices where display=TRUE order by name')
|
||||
.then(rr => rr.map(r => ({
|
||||
deviceId: r.device_id,
|
||||
name: r.name,
|
||||
cashbox: r.cashbox,
|
||||
cassette1: r.cassette1,
|
||||
cassette2: r.cassette2,
|
||||
paired: r.paired
|
||||
})))
|
||||
}
|
||||
|
||||
function resetCashOutBills (rec) {
|
||||
const sql = 'update devices set cassette1=$1, cassette2=$2 where device_id=$3'
|
||||
return db.none(sql, [rec.cassettes[0], rec.cassettes[1], rec.deviceId])
|
||||
}
|
||||
|
||||
function unpair (rec) {
|
||||
return pairing.unpair(rec.deviceId)
|
||||
}
|
||||
|
||||
function setMachine (rec) {
|
||||
switch (rec.action) {
|
||||
case 'resetCashOutBills': return resetCashOutBills(rec)
|
||||
case 'unpair': return unpair(rec)
|
||||
default: throw new Error('No such action: ' + rec.action)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {getMachines, setMachine}
|
||||
|
|
@ -1,24 +1,32 @@
|
|||
const _ = require('lodash/fp')
|
||||
const moment = require('moment')
|
||||
|
||||
const ticker = require('../ticker')
|
||||
const settingsLoader = require('../settings-loader')
|
||||
|
||||
const db = require('../db')
|
||||
const machineLoader = require('../machine-loader')
|
||||
|
||||
const CONSIDERED_UP_SECS = 30
|
||||
|
||||
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`
|
||||
const sql = `select min(extract(epoch from (now() - created))) as age
|
||||
from machine_events
|
||||
group by device_id`
|
||||
|
||||
return db.any(sql)
|
||||
.then(r => {
|
||||
if (r.length === 0) return 'No paired machines'
|
||||
return Promise.all([machineLoader.getMachineNames(), db.any(sql)])
|
||||
.then(([machines, events]) => {
|
||||
if (machines.length === 0) return 'No paired machines'
|
||||
|
||||
const addName = event => {
|
||||
const machine = _.find(['deviceId', event.deviceId], machines)
|
||||
if (!machine) return null
|
||||
return _.set('name', machine.name, event)
|
||||
}
|
||||
|
||||
const mapper = _.flow(_.filter(row => row.age > CONSIDERED_UP_SECS), _.map(addName), _.compact)
|
||||
const downRows = mapper(events)
|
||||
|
||||
const downRows = r.filter(row => row.age > CONSIDERED_UP_SECS)
|
||||
if (downRows.length === 0) return 'All machines are up'
|
||||
|
||||
if (downRows.length === 1) {
|
||||
|
|
|
|||
|
|
@ -1,21 +1,34 @@
|
|||
const _ = require('lodash/fp')
|
||||
|
||||
const db = require('../db')
|
||||
const machineLoader = require('../machine-loader')
|
||||
|
||||
const NUM_RESULTS = 20
|
||||
|
||||
function addNames (txs) {
|
||||
return machineLoader.getMachineNames()
|
||||
.then(machines => {
|
||||
const addName = tx => {
|
||||
const machine = _.find(['deviceId', tx.deviceId], machines)
|
||||
const name = machine ? machine.name : 'Unpaired'
|
||||
return _.set('machineName', name, tx)
|
||||
}
|
||||
|
||||
return _.map(addName, txs)
|
||||
})
|
||||
}
|
||||
|
||||
function batch () {
|
||||
const camelize = _.mapKeys(_.camelCase)
|
||||
const packager = _.flow(_.flatten, _.orderBy(_.property('created'), ['desc']), _.take(NUM_RESULTS), _.map(camelize))
|
||||
const packager = _.flow(_.flatten, _.orderBy(_.property('created'), ['desc']),
|
||||
_.take(NUM_RESULTS), _.map(camelize), addNames)
|
||||
|
||||
const cashInSql = `select 'cashIn' as tx_class, devices.name as machine_name, cash_in_txs.*
|
||||
from cash_in_txs, devices
|
||||
where devices.device_id=cash_in_txs.device_id
|
||||
const cashInSql = `select 'cashIn' as tx_class, cash_in_txs.*
|
||||
from cash_in_txs
|
||||
order by created desc limit $1`
|
||||
|
||||
const cashOutSql = `select 'cashOut' as tx_class, devices.name as machine_name, cash_out_txs.*
|
||||
from cash_out_txs, devices
|
||||
where devices.device_id=cash_out_txs.device_id
|
||||
const cashOutSql = `select 'cashOut' as tx_class, cash_out_txs.*
|
||||
from cash_out_txs
|
||||
order by created desc limit $1`
|
||||
|
||||
return Promise.all([db.any(cashInSql, [NUM_RESULTS]), db.any(cashOutSql, [NUM_RESULTS])])
|
||||
|
|
|
|||
|
|
@ -1,9 +1,8 @@
|
|||
const _ = require('lodash/fp')
|
||||
|
||||
const db = require('./db')
|
||||
const configManager = require('./config-manager')
|
||||
const machines = require('./admin/machines')
|
||||
const schema = require('../lamassu-schema.json')
|
||||
const logger = require('./logger')
|
||||
|
||||
function allScopes (cryptoScopes, machineScopes) {
|
||||
const scopes = []
|
||||
|
|
@ -91,8 +90,16 @@ function getGroupField (group, fieldCode) {
|
|||
return _.merge(_.pick(['cryptoScope', 'machineScope'], group), field)
|
||||
}
|
||||
|
||||
const fetchMachines = () => machines.getMachines()
|
||||
.then(machineList => machineList.map(r => r.deviceId))
|
||||
// Note: We can't use machine-loader because it relies on settings-loader,
|
||||
// which relies on this
|
||||
function getMachines () {
|
||||
return db.any('select device_id from devices')
|
||||
}
|
||||
|
||||
function fetchMachines () {
|
||||
return getMachines()
|
||||
.then(machineList => machineList.map(r => r.device_id))
|
||||
}
|
||||
|
||||
function validateFieldParameter (value, validator) {
|
||||
switch (validator.code) {
|
||||
|
|
@ -115,6 +122,8 @@ function ensureConstraints (config) {
|
|||
config.every(fieldInstance => {
|
||||
const fieldCode = fieldInstance.fieldLocator.code
|
||||
const field = pickField(fieldCode)
|
||||
if (!field) throw new Error('No such field: ' + fieldCode)
|
||||
|
||||
const fieldValue = fieldInstance.fieldValue
|
||||
|
||||
const isValid = field.fieldValidation
|
||||
|
|
|
|||
58
lib/machine-loader.js
Normal file
58
lib/machine-loader.js
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
const _ = require('lodash/fp')
|
||||
|
||||
const db = require('./db')
|
||||
const pairing = require('./pairing')
|
||||
const configManager = require('./config-manager')
|
||||
const settingsLoader = require('./settings-loader')
|
||||
|
||||
module.exports = {getMachines, getMachineNames, setMachine}
|
||||
|
||||
function getMachines () {
|
||||
return db.any('select * from devices where display=TRUE order by created')
|
||||
.then(rr => rr.map(r => ({
|
||||
deviceId: r.device_id,
|
||||
cashbox: r.cashbox,
|
||||
cassette1: r.cassette1,
|
||||
cassette2: r.cassette2,
|
||||
paired: r.paired
|
||||
})))
|
||||
}
|
||||
|
||||
function getConfig (defaultConfig) {
|
||||
if (defaultConfig) return Promise.resolve(defaultConfig)
|
||||
|
||||
return settingsLoader.loadRecentConfig()
|
||||
}
|
||||
|
||||
function getMachineNames (config) {
|
||||
return Promise.all([getMachines(), getConfig(config)])
|
||||
.then(([machines, config]) => {
|
||||
const addName = r => {
|
||||
const name = configManager.machineScoped(r.deviceId, config).machineName
|
||||
console.log('DEBUG200: %j', [name, r])
|
||||
console.log('DEBUG201: %j', configManager.machineScoped(r.deviceId, config))
|
||||
return _.set('name', name, r)
|
||||
}
|
||||
|
||||
return _.map(addName, machines)
|
||||
})
|
||||
}
|
||||
|
||||
function resetCashOutBills (rec) {
|
||||
const sql = 'update devices set cassette1=$1, cassette2=$2 where device_id=$3'
|
||||
return db.none(sql, [rec.cassettes[0], rec.cassettes[1], rec.deviceId])
|
||||
}
|
||||
|
||||
function unpair (rec) {
|
||||
return pairing.unpair(rec.deviceId)
|
||||
}
|
||||
|
||||
function setMachine (rec) {
|
||||
switch (rec.action) {
|
||||
case 'resetCashOutBills': return resetCashOutBills(rec)
|
||||
case 'unpair': return unpair(rec)
|
||||
default: throw new Error('No such action: ' + rec.action)
|
||||
}
|
||||
}
|
||||
|
||||
console.log('DEBUG101')
|
||||
|
|
@ -137,23 +137,15 @@ function checkStuckScreen (deviceEvents) {
|
|||
return []
|
||||
}
|
||||
|
||||
function devicesAndEvents () {
|
||||
return Promise.all([db.devices(), db.machineEvents()])
|
||||
.then(arr => ({devices: arr[0], events: arr[1]}))
|
||||
}
|
||||
|
||||
function checkStatus (plugins) {
|
||||
const alerts = {devices: {}, deviceNames: {}}
|
||||
|
||||
return Promise.all([plugins.checkBalances(), devicesAndEvents()])
|
||||
.then(([balances, rec]) => {
|
||||
const devices = rec.devices
|
||||
const events = rec.events
|
||||
|
||||
return Promise.all([plugins.checkBalances(), db.machineEvents(), plugins.getMachineNames()])
|
||||
.then(([balances, events, devices]) => {
|
||||
alerts.general = balances
|
||||
devices.forEach(function (deviceRow) {
|
||||
const deviceId = deviceRow.device_id
|
||||
const deviceName = deviceRow.name || deviceId
|
||||
devices.forEach(function (device) {
|
||||
const deviceId = device.deviceId
|
||||
const deviceName = device.name
|
||||
const deviceEvents = events.filter(function (eventRow) {
|
||||
return eventRow.device_id === deviceId
|
||||
})
|
||||
|
|
|
|||
|
|
@ -13,9 +13,13 @@ function pullToken (token) {
|
|||
return db.one(sql, [token])
|
||||
}
|
||||
|
||||
function configureNewDevice (deviceId) {
|
||||
function configureNewDevice (deviceId, machineName, machineModel) {
|
||||
const scope = {crypto: 'global', machine: deviceId}
|
||||
const newFields = [settingsLoader.configAddField(scope, 'cashOutEnabled', false)]
|
||||
const newFields = [
|
||||
settingsLoader.configAddField(scope, 'cashOutEnabled', false),
|
||||
settingsLoader.configAddField(scope, 'machineName', machineName),
|
||||
settingsLoader.configAddField(scope, 'machineModel', machineModel)
|
||||
]
|
||||
|
||||
return settingsLoader.modifyConfig(newFields)
|
||||
}
|
||||
|
|
@ -33,17 +37,17 @@ function unpair (deviceId) {
|
|||
.then(() => removeDeviceConfig(deviceId))
|
||||
}
|
||||
|
||||
function pair (token, deviceId) {
|
||||
function pair (token, deviceId, machineModel) {
|
||||
return pullToken(token)
|
||||
.then(r => {
|
||||
if (r.expired) return false
|
||||
|
||||
const insertSql = `insert into devices (device_id, name) values ($1, $2)
|
||||
const insertSql = `insert into devices (device_id) values ($1)
|
||||
on conflict (device_id)
|
||||
do update set name=$2, paired=TRUE, display=TRUE`
|
||||
do update set paired=TRUE, display=TRUE`
|
||||
|
||||
return configureNewDevice(deviceId)
|
||||
.then(() => db.none(insertSql, [deviceId, r.name]))
|
||||
return configureNewDevice(deviceId, r.name, machineModel)
|
||||
.then(() => db.none(insertSql, [deviceId]))
|
||||
.then(() => true)
|
||||
})
|
||||
.catch(err => {
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ const exchange = require('./exchange')
|
|||
const sms = require('./sms')
|
||||
const email = require('./email')
|
||||
const cashOutHelper = require('./cash-out-helper')
|
||||
const machineLoader = require('./machine-loader')
|
||||
|
||||
const mapValuesWithKey = _.mapValues.convert({cap: false})
|
||||
|
||||
|
|
@ -252,9 +253,7 @@ function plugins (settings, deviceId) {
|
|||
|
||||
const rate = rawRate.div(cashInCommission)
|
||||
|
||||
// `lowBalanceMargin` is our safety net. It's a number > 1, and we divide
|
||||
// all our balances by it to provide a safety margin.
|
||||
const lowBalanceMargin = (BN(config.lowBalanceMargin).div(100)).plus(1)
|
||||
const lowBalanceMargin = BN(1)
|
||||
|
||||
const unitScale = BN(10).pow(coins[cryptoCode].unitScale)
|
||||
const fiatTransferBalance = balance.mul(rate.div(unitScale)).div(lowBalanceMargin)
|
||||
|
|
@ -372,9 +371,9 @@ function plugins (settings, deviceId) {
|
|||
}
|
||||
|
||||
function executeTrades () {
|
||||
return dbm.devices()
|
||||
return machineLoader.getMachines()
|
||||
.then(devices => {
|
||||
const deviceIds = devices.map(device => device.device_id)
|
||||
const deviceIds = devices.map(device => device.deviceId)
|
||||
const lists = deviceIds.map(deviceId => {
|
||||
const config = configManager.machineScoped(deviceId, settings.config)
|
||||
const fiatCode = config.fiatCurrency
|
||||
|
|
@ -481,9 +480,9 @@ function plugins (settings, deviceId) {
|
|||
}
|
||||
|
||||
function checkBalances () {
|
||||
return dbm.devices()
|
||||
return machineLoader.getMachines()
|
||||
.then(devices => {
|
||||
const deviceIds = devices.map(r => r.device_id)
|
||||
const deviceIds = devices.map(r => r.deviceId)
|
||||
const deviceBalancePromises = deviceIds.map(deviceId => checkDeviceBalances(deviceId))
|
||||
|
||||
return Promise.all(deviceBalancePromises)
|
||||
|
|
@ -544,6 +543,10 @@ function plugins (settings, deviceId) {
|
|||
.catch(err => logger.error(err))
|
||||
}
|
||||
|
||||
function getMachineNames () {
|
||||
return machineLoader.getMachineNames(settings.config)
|
||||
}
|
||||
|
||||
return {
|
||||
pollQueries,
|
||||
sendCoins,
|
||||
|
|
@ -560,6 +563,7 @@ function plugins (settings, deviceId) {
|
|||
sweepHd,
|
||||
sendMessage,
|
||||
checkBalances,
|
||||
getMachineNames,
|
||||
buildAvailableCassettes,
|
||||
buy,
|
||||
sell
|
||||
|
|
|
|||
|
|
@ -50,12 +50,6 @@ exports.machineEvent = function machineEvent (rec) {
|
|||
.then(() => db.none(deleteSql, [rec.deviceId, rec.eventType]))
|
||||
}
|
||||
|
||||
exports.devices = function devices () {
|
||||
const sql = 'SELECT device_id, name FROM devices'
|
||||
|
||||
return db.any(sql)
|
||||
}
|
||||
|
||||
exports.machineEvents = function machineEvents () {
|
||||
const sql = 'SELECT *, (EXTRACT(EPOCH FROM (now() - created))) * 1000 AS age FROM machine_events'
|
||||
|
||||
|
|
|
|||
|
|
@ -147,8 +147,9 @@ function ca (req, res) {
|
|||
function pair (req, res, next) {
|
||||
const token = req.query.token
|
||||
const deviceId = req.deviceId
|
||||
const model = req.query.model
|
||||
|
||||
return pairing.pair(token, deviceId)
|
||||
return pairing.pair(token, deviceId, model)
|
||||
.then(valid => {
|
||||
if (valid) {
|
||||
return helpers.updateMachineDefaults(deviceId)
|
||||
|
|
|
|||
|
|
@ -103,6 +103,19 @@ function loadLatestConfig () {
|
|||
})
|
||||
}
|
||||
|
||||
function loadRecentConfig () {
|
||||
if (argv.fixture) return loadFixture()
|
||||
|
||||
const sql = `select id, data
|
||||
from user_config
|
||||
where type=$1
|
||||
order by id desc
|
||||
limit 1`
|
||||
|
||||
return db.one(sql, ['config'])
|
||||
.then(row => row.data.config)
|
||||
}
|
||||
|
||||
function loadAccounts () {
|
||||
const toFields = fieldArr => _.fromPairs(_.map(r => [r.code, r.value], fieldArr))
|
||||
const toPairs = r => [r.code, toFields(r.fields)]
|
||||
|
|
@ -152,16 +165,28 @@ function configDeleteField (scope, fieldCode) {
|
|||
}
|
||||
}
|
||||
|
||||
function addEdgeCases (config) {
|
||||
const isCashOutEnabled = r => r.fieldLocator.fieldScope.machine !== 'global' &&
|
||||
r.fieldLocator.code === 'cashOutEnabled' &&
|
||||
r.fieldValue.value
|
||||
|
||||
const cashOutEnabledExists = _.some(isCashOutEnabled, config)
|
||||
const scope = {crypto: 'global', machine: 'global'}
|
||||
const newField = configAddField(scope, 'cashOutEnabled', cashOutEnabledExists)
|
||||
|
||||
return mergeValues(config, newField)
|
||||
}
|
||||
|
||||
function modifyConfig (newFields) {
|
||||
const TransactionMode = pgp.txMode.TransactionMode
|
||||
const isolationLevel = pgp.txMode.isolationLevel
|
||||
const tmSRD = new TransactionMode({tiLevel: isolationLevel.serializable})
|
||||
|
||||
function transaction (t) {
|
||||
return loadLatest()
|
||||
.then(settings => {
|
||||
const oldConfig = settings.config
|
||||
return save(mergeValues(oldConfig, newFields))
|
||||
return loadRecentConfig()
|
||||
.then(oldConfig => {
|
||||
const doSave = _.flow(mergeValues, addEdgeCases, save)
|
||||
return doSave(oldConfig, newFields)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -173,6 +198,7 @@ function modifyConfig (newFields) {
|
|||
module.exports = {
|
||||
settings,
|
||||
loadConfig,
|
||||
loadRecentConfig,
|
||||
load,
|
||||
loadLatest,
|
||||
save,
|
||||
|
|
|
|||
12
migrations/031-remove_name_from_devices.js
Normal file
12
migrations/031-remove_name_from_devices.js
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
const db = require('./db')
|
||||
|
||||
exports.up = function (next) {
|
||||
const sql = [
|
||||
'alter table devices drop column name'
|
||||
]
|
||||
db.multi(sql, next)
|
||||
}
|
||||
|
||||
exports.down = function (next) {
|
||||
next()
|
||||
}
|
||||
6498
public/elm.js
6498
public/elm.js
File diff suppressed because one or more lines are too long
|
|
@ -366,14 +366,28 @@ p {
|
|||
}
|
||||
|
||||
.lamassuAdminConfigTable .lamassuAdminBasicInputDisabled {
|
||||
background-color: #fcfcfa;
|
||||
height: 25px;
|
||||
line-height: 25px;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: #5f5f56;
|
||||
text-align: center;
|
||||
text-align: left;
|
||||
padding: 0 1em;
|
||||
cursor: default;
|
||||
background: repeating-linear-gradient(45deg,#dfdfdc,#dfdfdc 2px,#e6e6e3 5px);
|
||||
}
|
||||
|
||||
.lamassuAdminConfigTable .lamassuAdminBasicInputReadOnly {
|
||||
height: 25px;
|
||||
line-height: 25px;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: #5f5f56;
|
||||
text-align: left;
|
||||
padding: 0 1em;
|
||||
cursor: default;
|
||||
background-color: #f6f6f4;
|
||||
border: 2px solid #E6E6E3;
|
||||
}
|
||||
|
||||
.lamassuAdminConfigTable td {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue