validate min/max values on save
This commit is contained in:
parent
3f3671f138
commit
124e35d153
5 changed files with 61 additions and 28 deletions
|
|
@ -87,10 +87,11 @@ app.post('/api/account', (req, res) => {
|
||||||
app.get('/api/config/:config', (req, res) =>
|
app.get('/api/config/:config', (req, res) =>
|
||||||
config.fetchConfigGroup(req.params.config).then(c => res.json(c)))
|
config.fetchConfigGroup(req.params.config).then(c => res.json(c)))
|
||||||
|
|
||||||
app.post('/api/config', (req, res) => {
|
app.post('/api/config', (req, res, next) => {
|
||||||
config.saveConfigGroup(req.body)
|
config.saveConfigGroup(req.body)
|
||||||
.then(c => res.json(c))
|
.then(c => res.json(c))
|
||||||
.then(() => dbNotify())
|
.then(() => dbNotify())
|
||||||
|
.catch(next)
|
||||||
})
|
})
|
||||||
|
|
||||||
app.get('/api/accounts/account/:account', (req, res) => {
|
app.get('/api/accounts/account/:account', (req, res) => {
|
||||||
|
|
@ -111,7 +112,7 @@ app.post('/api/machines', (req, res) => {
|
||||||
})
|
})
|
||||||
|
|
||||||
app.get('/api/status', (req, res, next) => {
|
app.get('/api/status', (req, res, next) => {
|
||||||
return Promise.all([server.status(), config.validateConfig()])
|
return Promise.all([server.status(), config.validateCurrentConfig()])
|
||||||
.then(([serverStatus, invalidConfigGroups]) => res.send({
|
.then(([serverStatus, invalidConfigGroups]) => res.send({
|
||||||
server: serverStatus,
|
server: serverStatus,
|
||||||
invalidConfigGroups
|
invalidConfigGroups
|
||||||
|
|
|
||||||
|
|
@ -101,7 +101,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"code": "min",
|
"code": "min",
|
||||||
"min": 0
|
"min": 10
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -39,10 +39,8 @@ function selectedAccounts () {
|
||||||
|
|
||||||
const mapSchema = code => schemas[code]
|
const mapSchema = code => schemas[code]
|
||||||
return config.fetchConfig()
|
return config.fetchConfig()
|
||||||
.then(data => {
|
.then(conf => {
|
||||||
if (!data) return []
|
const accountCodes = _.uniq(conf.map(mapAccount)
|
||||||
|
|
||||||
const accountCodes = _.uniq(data.config.map(mapAccount)
|
|
||||||
.filter(_.identity))
|
.filter(_.identity))
|
||||||
|
|
||||||
return _.sortBy(_.get('display'), accountCodes.map(mapSchema)
|
return _.sortBy(_.get('display'), accountCodes.map(mapSchema)
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ function fetchConfig () {
|
||||||
order by id desc limit 1`
|
order by id desc limit 1`
|
||||||
|
|
||||||
return db.oneOrNone(sql, ['config'])
|
return db.oneOrNone(sql, ['config'])
|
||||||
.then(row => row && row.data)
|
.then(row => row ? row.data.config : [])
|
||||||
}
|
}
|
||||||
|
|
||||||
function allScopes (cryptoScopes, machineScopes) {
|
function allScopes (cryptoScopes, machineScopes) {
|
||||||
|
|
@ -110,10 +110,43 @@ function getField (schema, group, fieldCode) {
|
||||||
const fetchMachines = () => machines.getMachines()
|
const fetchMachines = () => machines.getMachines()
|
||||||
.then(machineList => machineList.map(r => r.deviceId))
|
.then(machineList => machineList.map(r => r.deviceId))
|
||||||
|
|
||||||
function validateConfig () {
|
function validateFieldParameter (value, validator) {
|
||||||
return Promise.all([fetchSchema(), fetchConfig(), fetchMachines()])
|
switch (validator.code) {
|
||||||
.then(([schema, configRec, machineList]) => {
|
case 'required':
|
||||||
const config = configRec ? configRec.config : []
|
return true // We don't validate this here
|
||||||
|
case 'min':
|
||||||
|
return value >= validator.min
|
||||||
|
case 'max':
|
||||||
|
return value <= validator.max
|
||||||
|
default:
|
||||||
|
throw new Error('Unknown validation type: ' + validator.code)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validates specific field properties other than required property
|
||||||
|
function enforceValidConfigParameters (fieldInstances) {
|
||||||
|
return fetchSchema()
|
||||||
|
.then(schema => {
|
||||||
|
const pickField = fieldCode => schema.fields.find(r => r.code === fieldCode)
|
||||||
|
|
||||||
|
return fieldInstances.every(fieldInstance => {
|
||||||
|
const fieldCode = fieldInstance.fieldLocator.code
|
||||||
|
const field = pickField(fieldCode)
|
||||||
|
const fieldValue = fieldInstance.fieldValue
|
||||||
|
|
||||||
|
const isValid = field.fieldValidation
|
||||||
|
.every(validator => validateFieldParameter(fieldValue.value, validator))
|
||||||
|
|
||||||
|
if (isValid) return true
|
||||||
|
|
||||||
|
throw new Error('Invalid config value')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function validateConfig (config) {
|
||||||
|
return Promise.all([fetchSchema(), fetchMachines()])
|
||||||
|
.then(([schema, machineList]) => {
|
||||||
const cryptos = getCryptos(config, machineList)
|
const cryptos = getCryptos(config, machineList)
|
||||||
return schema.groups.filter(group => {
|
return schema.groups.filter(group => {
|
||||||
return group.fields.some(fieldCode => {
|
return group.fields.some(fieldCode => {
|
||||||
|
|
@ -128,11 +161,15 @@ function validateConfig () {
|
||||||
.then(arr => arr.map(r => r.code))
|
.then(arr => arr.map(r => r.code))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function validateCurrentConfig () {
|
||||||
|
return fetchConfig()
|
||||||
|
.then(validateConfig)
|
||||||
|
}
|
||||||
|
|
||||||
function fetchConfigGroup (code) {
|
function fetchConfigGroup (code) {
|
||||||
const fieldLocatorCodeEq = R.pathEq(['fieldLocator', 'code'])
|
const fieldLocatorCodeEq = R.pathEq(['fieldLocator', 'code'])
|
||||||
return Promise.all([fetchSchema(), fetchData(), fetchConfig(), fetchMachines()])
|
return Promise.all([fetchSchema(), fetchData(), fetchConfig(), fetchMachines()])
|
||||||
.then(([schema, data, config, machineList]) => {
|
.then(([schema, data, config, machineList]) => {
|
||||||
const configValues = config ? config.config : []
|
|
||||||
const groupSchema = schema.groups.find(r => r.code === code)
|
const groupSchema = schema.groups.find(r => r.code === code)
|
||||||
|
|
||||||
if (!groupSchema) throw new Error('No such group schema: ' + code)
|
if (!groupSchema) throw new Error('No such group schema: ' + code)
|
||||||
|
|
@ -149,7 +186,7 @@ function fetchConfigGroup (code) {
|
||||||
const configFields = R.uniq(R.flatten(candidateFields)).filter(R.identity)
|
const configFields = R.uniq(R.flatten(candidateFields)).filter(R.identity)
|
||||||
|
|
||||||
const values = configFields
|
const values = configFields
|
||||||
.reduce((acc, configField) => acc.concat(configValues.filter(fieldLocatorCodeEq(configField))), [])
|
.reduce((acc, configField) => acc.concat(config.filter(fieldLocatorCodeEq(configField))), [])
|
||||||
|
|
||||||
groupSchema.fields = undefined
|
groupSchema.fields = undefined
|
||||||
groupSchema.entries = schemaFields
|
groupSchema.entries = schemaFields
|
||||||
|
|
@ -157,7 +194,7 @@ function fetchConfigGroup (code) {
|
||||||
return {
|
return {
|
||||||
schema: groupSchema,
|
schema: groupSchema,
|
||||||
values: values,
|
values: values,
|
||||||
selectedCryptos: getCryptos(configValues, machineList),
|
selectedCryptos: getCryptos(config, machineList),
|
||||||
data: data
|
data: data
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
@ -216,17 +253,15 @@ function fetchData () {
|
||||||
|
|
||||||
function dbSaveConfig (config) {
|
function dbSaveConfig (config) {
|
||||||
const sql = 'insert into user_config (type, data) values ($1, $2)'
|
const sql = 'insert into user_config (type, data) values ($1, $2)'
|
||||||
return db.none(sql, ['config', config])
|
return db.none(sql, ['config', {config}])
|
||||||
}
|
}
|
||||||
|
|
||||||
function saveConfigGroup (results) {
|
function saveConfigGroup (results) {
|
||||||
if (results.values.length === 0) return fetchConfigGroup(results.groupCode)
|
if (results.values.length === 0) return fetchConfigGroup(results.groupCode)
|
||||||
|
|
||||||
return fetchConfig()
|
return enforceValidConfigParameters(results.values)
|
||||||
.then(config => {
|
.then(fetchConfig)
|
||||||
if (!config) config = {config: []}
|
.then(oldValues => {
|
||||||
const oldValues = config.config
|
|
||||||
|
|
||||||
results.values.forEach(newValue => {
|
results.values.forEach(newValue => {
|
||||||
const oldValueIndex = oldValues
|
const oldValueIndex = oldValues
|
||||||
.findIndex(old => old.fieldLocator.code === newValue.fieldLocator.code &&
|
.findIndex(old => old.fieldLocator.code === newValue.fieldLocator.code &&
|
||||||
|
|
@ -251,15 +286,14 @@ function saveConfigGroup (results) {
|
||||||
if (!R.isNil(newValue.fieldValue)) oldValues.push(newValue)
|
if (!R.isNil(newValue.fieldValue)) oldValues.push(newValue)
|
||||||
})
|
})
|
||||||
|
|
||||||
return dbSaveConfig(config)
|
return dbSaveConfig(oldValues)
|
||||||
.then(() => fetchConfigGroup(results.groupCode))
|
.then(() => fetchConfigGroup(results.groupCode))
|
||||||
})
|
})
|
||||||
.catch(e => console.error(e.stack))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
fetchConfigGroup,
|
fetchConfigGroup,
|
||||||
saveConfigGroup,
|
saveConfigGroup,
|
||||||
validateConfig,
|
validateCurrentConfig,
|
||||||
fetchConfig
|
fetchConfig
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25386,9 +25386,9 @@ var _user$project$Config$validateMax = F2(
|
||||||
case 'FieldPercentageValue':
|
case 'FieldPercentageValue':
|
||||||
return _elm_lang$core$Native_Utils.cmp(
|
return _elm_lang$core$Native_Utils.cmp(
|
||||||
_elm_lang$core$Basics$floor(_p6._0),
|
_elm_lang$core$Basics$floor(_p6._0),
|
||||||
max) < 0;
|
max) < 1;
|
||||||
case 'FieldIntegerValue':
|
case 'FieldIntegerValue':
|
||||||
return _elm_lang$core$Native_Utils.cmp(_p6._0, max) < 0;
|
return _elm_lang$core$Native_Utils.cmp(_p6._0, max) < 1;
|
||||||
default:
|
default:
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -25400,9 +25400,9 @@ var _user$project$Config$validateMin = F2(
|
||||||
case 'FieldPercentageValue':
|
case 'FieldPercentageValue':
|
||||||
return _elm_lang$core$Native_Utils.cmp(
|
return _elm_lang$core$Native_Utils.cmp(
|
||||||
_elm_lang$core$Basics$ceiling(_p7._0),
|
_elm_lang$core$Basics$ceiling(_p7._0),
|
||||||
min) > 0;
|
min) > -1;
|
||||||
case 'FieldIntegerValue':
|
case 'FieldIntegerValue':
|
||||||
return _elm_lang$core$Native_Utils.cmp(_p7._0, min) > 0;
|
return _elm_lang$core$Native_Utils.cmp(_p7._0, min) > -1;
|
||||||
default:
|
default:
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue