161 lines
3.8 KiB
JavaScript
161 lines
3.8 KiB
JavaScript
const path = require('path')
|
|
const fs = require('fs')
|
|
|
|
const _ = require('lodash/fp')
|
|
const argv = require('minimist')(process.argv.slice(2))
|
|
const pify = require('pify')
|
|
|
|
const db = require('./db')
|
|
const options = require('./options')
|
|
const logger = require('./logger')
|
|
|
|
const schemaPath = path.resolve(options.lamassuServerPath, 'lamassu-schema.json')
|
|
const schema = require(schemaPath)
|
|
|
|
let settingsCache
|
|
|
|
function loadFixture () {
|
|
const fixture = argv.fixture
|
|
const machine = argv.machine
|
|
|
|
if (fixture && !machine) 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([])
|
|
|
|
return promise
|
|
.then(values => _.map(v => {
|
|
return (v.fieldLocator.fieldScope.machine === 'machine')
|
|
? _.set('fieldLocator.fieldScope.machine', machine, v)
|
|
: v
|
|
}, values))
|
|
}
|
|
|
|
function isEquivalentField (a, b) {
|
|
return _.isEqual(
|
|
[a.fieldLocator.code, a.fieldLocator.fieldScope],
|
|
[b.fieldLocator.code, b.fieldLocator.fieldScope]
|
|
)
|
|
}
|
|
|
|
// b overrides a
|
|
function mergeValues (a, b) {
|
|
return _.unionWith(isEquivalentField, b, a)
|
|
}
|
|
|
|
function load (versionId) {
|
|
if (!versionId) throw new Error('versionId is required')
|
|
|
|
return Promise.all([loadConfig(versionId), loadAccounts()])
|
|
.then(([config, accounts]) => ({
|
|
config,
|
|
accounts
|
|
}))
|
|
}
|
|
|
|
function loadLatest () {
|
|
return Promise.all([loadLatestConfig(), loadAccounts()])
|
|
.then(([config, accounts]) => ({
|
|
config,
|
|
accounts
|
|
}))
|
|
}
|
|
|
|
function loadConfig (versionId) {
|
|
if (argv.fixture) return loadFixture()
|
|
|
|
const sql = `select data
|
|
from user_config
|
|
where id=$1 and type=$2`
|
|
|
|
return db.oneOrNone(sql, [versionId, 'config'])
|
|
.then(row => row ? row.data.config : [])
|
|
.then(validate)
|
|
}
|
|
|
|
function loadLatestConfig () {
|
|
if (argv.fixture) return loadFixture()
|
|
|
|
const sql = `select data
|
|
from user_config
|
|
where type=$1
|
|
and valid
|
|
order by id desc
|
|
limit 1`
|
|
|
|
return db.one(sql, ['config'])
|
|
.then(row => row.data.config)
|
|
.then(validate)
|
|
.catch(err => {
|
|
if (err.name === 'QueryResultError') {
|
|
throw new Error('lamassu-server is not configured')
|
|
}
|
|
|
|
throw err
|
|
})
|
|
}
|
|
|
|
function checkConstraint (entry, constraint) {
|
|
switch (constraint.code) {
|
|
case 'min':
|
|
return entry.fieldValue.value >= constraint.min
|
|
default:
|
|
return true
|
|
}
|
|
}
|
|
|
|
function validateConstraint (entry, constraint) {
|
|
const isValid = checkConstraint(entry, constraint)
|
|
if (!isValid) logger.error(`Validation error: ${entry.fieldLocator.code} [${constraint.code}]`)
|
|
return isValid
|
|
}
|
|
|
|
function validateEntry (entry) {
|
|
const fieldCode = entry.fieldLocator.code
|
|
const schemaEntry = _.find(_.matchesProperty('code', fieldCode), schema.fields)
|
|
if (!schemaEntry) throw new Error(`Unsupported field: ${fieldCode}`)
|
|
|
|
const validations = schemaEntry.fieldValidation
|
|
return _.every(constraint => validateConstraint(entry, constraint), validations)
|
|
}
|
|
|
|
function isValid (config) {
|
|
return _.every(validateEntry, config)
|
|
}
|
|
function validate (config) {
|
|
if (!isValid(config)) throw new Error('Invalid config')
|
|
return config
|
|
}
|
|
|
|
function loadAccounts () {
|
|
const toFields = fieldArr => _.fromPairs(_.map(r => [r.code, r.value], fieldArr))
|
|
const toPairs = r => [r.code, toFields(r.fields)]
|
|
|
|
return db.oneOrNone('select data from user_config where type=$1', 'accounts')
|
|
.then(function (data) {
|
|
if (!data) return {}
|
|
return _.fromPairs(_.map(toPairs, data.data.accounts))
|
|
})
|
|
}
|
|
|
|
function settings () {
|
|
return settingsCache
|
|
}
|
|
|
|
function save (config) {
|
|
const sql = 'insert into user_config (type, data, valid) values ($1, $2, $3)'
|
|
return db.none(sql, ['config', {config}, isValid(config)])
|
|
}
|
|
|
|
module.exports = {
|
|
settings,
|
|
loadConfig,
|
|
load,
|
|
loadLatest,
|
|
save,
|
|
loadFixture,
|
|
mergeValues
|
|
}
|