chore: deprecate old migrations
This commit is contained in:
parent
f5ba3dbf4e
commit
ca68fdd0a2
13 changed files with 15 additions and 2293 deletions
|
|
@ -1,67 +0,0 @@
|
|||
const _ = require('lodash/fp')
|
||||
|
||||
module.exports = {
|
||||
unscoped,
|
||||
cryptoScoped,
|
||||
machineScoped,
|
||||
scoped,
|
||||
scopedValue,
|
||||
all
|
||||
}
|
||||
|
||||
function matchesValue (crypto, machine, instance) {
|
||||
return instance.fieldLocator.fieldScope.crypto === crypto &&
|
||||
instance.fieldLocator.fieldScope.machine === machine
|
||||
}
|
||||
|
||||
function permutations (crypto, machine) {
|
||||
return _.uniq([
|
||||
[crypto, machine],
|
||||
[crypto, 'global'],
|
||||
['global', machine],
|
||||
['global', 'global']
|
||||
])
|
||||
}
|
||||
|
||||
function fallbackValue (crypto, machine, instances) {
|
||||
const notNil = _.negate(_.isNil)
|
||||
const pickValue = arr => _.find(instance => matchesValue(arr[0], arr[1], instance), instances)
|
||||
const fallbackRec = _.find(notNil, _.map(pickValue, permutations(crypto, machine)))
|
||||
return fallbackRec && fallbackRec.fieldValue.value
|
||||
}
|
||||
|
||||
function scopedValue (crypto, machine, fieldCode, config) {
|
||||
const allScopes = config.filter(_.pathEq(['fieldLocator', 'code'], fieldCode))
|
||||
|
||||
return fallbackValue(crypto, machine, allScopes)
|
||||
}
|
||||
|
||||
function generalScoped (crypto, machine, config) {
|
||||
const localScopedValue = key =>
|
||||
scopedValue(crypto, machine, key, config)
|
||||
|
||||
const keys = _.uniq(_.map(r => r.fieldLocator.code, config))
|
||||
const keyedValues = keys.map(localScopedValue)
|
||||
|
||||
return _.zipObject(keys, keyedValues)
|
||||
}
|
||||
|
||||
function machineScoped (machine, config) {
|
||||
return generalScoped('global', machine, config)
|
||||
}
|
||||
|
||||
function unscoped (config) {
|
||||
return generalScoped('global', 'global', config)
|
||||
}
|
||||
|
||||
function cryptoScoped (crypto, config) {
|
||||
return generalScoped(crypto, 'global', config)
|
||||
}
|
||||
|
||||
function scoped (crypto, machine, config) {
|
||||
return generalScoped(crypto, machine, config)
|
||||
}
|
||||
|
||||
function all (code, config) {
|
||||
return _.uniq(_.map('fieldValue.value', _.filter(i => i.fieldLocator.code === code, config)))
|
||||
}
|
||||
|
|
@ -1,191 +0,0 @@
|
|||
const _ = require('lodash/fp')
|
||||
|
||||
const db = require('../db')
|
||||
const configManager = require('./config-manager')
|
||||
const logger = require('../logger')
|
||||
const schema = require('./lamassu-schema.json')
|
||||
|
||||
const REMOVED_FIELDS = ['crossRefVerificationActive', 'crossRefVerificationThreshold']
|
||||
|
||||
const SETTINGS_LOADER_SCHEMA_VERSION = 1
|
||||
|
||||
function allScopes (cryptoScopes, machineScopes) {
|
||||
const scopes = []
|
||||
cryptoScopes.forEach(c => {
|
||||
machineScopes.forEach(m => scopes.push([c, m]))
|
||||
})
|
||||
|
||||
return scopes
|
||||
}
|
||||
|
||||
function allCryptoScopes (cryptos, cryptoScope) {
|
||||
const cryptoScopes = []
|
||||
|
||||
if (cryptoScope === 'global' || cryptoScope === 'both') cryptoScopes.push('global')
|
||||
if (cryptoScope === 'specific' || cryptoScope === 'both') cryptos.forEach(r => cryptoScopes.push(r))
|
||||
|
||||
return cryptoScopes
|
||||
}
|
||||
|
||||
function allMachineScopes (machineList, machineScope) {
|
||||
const machineScopes = []
|
||||
|
||||
if (machineScope === 'global' || machineScope === 'both') machineScopes.push('global')
|
||||
if (machineScope === 'specific' || machineScope === 'both') machineList.forEach(r => machineScopes.push(r))
|
||||
|
||||
return machineScopes
|
||||
}
|
||||
|
||||
function satisfiesRequire (config, cryptos, machineList, field, anyFields, allFields) {
|
||||
const fieldCode = field.code
|
||||
|
||||
const scopes = allScopes(
|
||||
allCryptoScopes(cryptos, field.cryptoScope),
|
||||
allMachineScopes(machineList, field.machineScope)
|
||||
)
|
||||
|
||||
return scopes.every(scope => {
|
||||
const isAnyEnabled = () => _.some(refField => {
|
||||
return isScopeEnabled(config, cryptos, machineList, refField, scope)
|
||||
}, anyFields)
|
||||
|
||||
const areAllEnabled = () => _.every(refField => {
|
||||
return isScopeEnabled(config, cryptos, machineList, refField, scope)
|
||||
}, allFields)
|
||||
|
||||
const isBlank = _.isNil(configManager.scopedValue(scope[0], scope[1], fieldCode, config))
|
||||
const isRequired = (_.isEmpty(anyFields) || isAnyEnabled()) &&
|
||||
(_.isEmpty(allFields) || areAllEnabled())
|
||||
const hasDefault = !_.isNil(_.get('default', field))
|
||||
|
||||
const isValid = !isRequired || !isBlank || hasDefault
|
||||
|
||||
return isValid
|
||||
})
|
||||
}
|
||||
|
||||
function isScopeEnabled (config, cryptos, machineList, refField, scope) {
|
||||
const [cryptoScope, machineScope] = scope
|
||||
const candidateCryptoScopes = cryptoScope === 'global'
|
||||
? allCryptoScopes(cryptos, refField.cryptoScope)
|
||||
: [cryptoScope]
|
||||
|
||||
const candidateMachineScopes = machineScope === 'global'
|
||||
? allMachineScopes(machineList, refField.machineScope)
|
||||
: [ machineScope ]
|
||||
|
||||
const allRefCandidateScopes = allScopes(candidateCryptoScopes, candidateMachineScopes)
|
||||
const getFallbackValue = scope => configManager.scopedValue(scope[0], scope[1], refField.code, config)
|
||||
const values = allRefCandidateScopes.map(getFallbackValue)
|
||||
|
||||
return values.some(r => r)
|
||||
}
|
||||
|
||||
function getCryptos (config, machineList) {
|
||||
const scopes = allScopes(['global'], allMachineScopes(machineList, 'both'))
|
||||
const scoped = scope => configManager.scopedValue(scope[0], scope[1], 'cryptoCurrencies', config)
|
||||
return scopes.reduce((acc, scope) => _.union(acc, scoped(scope)), [])
|
||||
}
|
||||
|
||||
function getGroup (fieldCode) {
|
||||
return _.find(group => _.includes(fieldCode, group.fields), schema.groups)
|
||||
}
|
||||
|
||||
function getField (fieldCode) {
|
||||
const group = getGroup(fieldCode)
|
||||
return getGroupField(group, fieldCode)
|
||||
}
|
||||
|
||||
function getGroupField (group, fieldCode) {
|
||||
const field = _.find(_.matchesProperty('code', fieldCode), schema.fields)
|
||||
return _.merge(_.pick(['cryptoScope', 'machineScope'], group), field)
|
||||
}
|
||||
|
||||
// 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) {
|
||||
case 'required':
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
function ensureConstraints (config) {
|
||||
const pickField = fieldCode => schema.fields.find(r => r.code === fieldCode)
|
||||
|
||||
return Promise.resolve()
|
||||
.then(() => {
|
||||
config.every(fieldInstance => {
|
||||
const fieldCode = fieldInstance.fieldLocator.code
|
||||
if (_.includes(fieldCode, REMOVED_FIELDS)) return
|
||||
|
||||
const field = pickField(fieldCode)
|
||||
if (!field) {
|
||||
logger.warn('No such field: %s, %j', fieldCode, fieldInstance.fieldLocator.fieldScope)
|
||||
return
|
||||
}
|
||||
|
||||
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 validateRequires (config) {
|
||||
return fetchMachines()
|
||||
.then(machineList => {
|
||||
const cryptos = getCryptos(config, machineList)
|
||||
|
||||
return schema.groups.filter(group => {
|
||||
return group.fields.some(fieldCode => {
|
||||
const field = getGroupField(group, fieldCode)
|
||||
|
||||
if (!field.fieldValidation.find(r => r.code === 'required')) return false
|
||||
|
||||
const refFieldsAny = _.map(_.partial(getField, group), field.enabledIfAny)
|
||||
const refFieldsAll = _.map(_.partial(getField, group), field.enabledIfAll)
|
||||
const isInvalid = !satisfiesRequire(config, cryptos, machineList, field, refFieldsAny, refFieldsAll)
|
||||
|
||||
return isInvalid
|
||||
})
|
||||
})
|
||||
})
|
||||
.then(arr => arr.map(r => r.code))
|
||||
}
|
||||
|
||||
function validate (config) {
|
||||
return Promise.resolve()
|
||||
.then(() => ensureConstraints(config))
|
||||
.then(() => validateRequires(config))
|
||||
.then(arr => {
|
||||
if (arr.length === 0) return config
|
||||
throw new Error('Invalid configuration:' + arr)
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
SETTINGS_LOADER_SCHEMA_VERSION,
|
||||
validate,
|
||||
ensureConstraints,
|
||||
validateRequires
|
||||
}
|
||||
|
|
@ -1,230 +0,0 @@
|
|||
const _ = require('lodash/fp')
|
||||
const devMode = require('minimist')(process.argv.slice(2)).dev
|
||||
|
||||
const currencies = require('../new-admin/config/data/currencies.json')
|
||||
const languageRec = require('../new-admin/config/data/languages.json')
|
||||
const countries = require('../new-admin/config/data/countries.json')
|
||||
const machineLoader = require('../machine-loader')
|
||||
|
||||
const configManager = require('./config-manager')
|
||||
|
||||
const db = require('../db')
|
||||
const settingsLoader = require('./settings-loader')
|
||||
const configValidate = require('./config-validate')
|
||||
const jsonSchema = require('./lamassu-schema.json')
|
||||
|
||||
|
||||
function fetchSchema () {
|
||||
return _.cloneDeep(jsonSchema)
|
||||
}
|
||||
|
||||
function fetchConfig () {
|
||||
const sql = `select data from user_config where type=$1 and schema_version=$2
|
||||
order by id desc limit 1`
|
||||
|
||||
return db.oneOrNone(sql, ['config', configValidate.SETTINGS_LOADER_SCHEMA_VERSION])
|
||||
.then(row => row ? row.data.config : [])
|
||||
}
|
||||
|
||||
function allScopes (cryptoScopes, machineScopes) {
|
||||
const scopes = []
|
||||
cryptoScopes.forEach(c => {
|
||||
machineScopes.forEach(m => scopes.push([c, m]))
|
||||
})
|
||||
|
||||
return scopes
|
||||
}
|
||||
|
||||
function allMachineScopes (machineList, machineScope) {
|
||||
const machineScopes = []
|
||||
|
||||
if (machineScope === 'global' || machineScope === 'both') machineScopes.push('global')
|
||||
if (machineScope === 'specific' || machineScope === 'both') machineList.forEach(r => machineScopes.push(r))
|
||||
|
||||
return machineScopes
|
||||
}
|
||||
|
||||
function getCryptos (config, machineList) {
|
||||
const scopes = allScopes(['global'], allMachineScopes(machineList, 'both'))
|
||||
const scoped = scope => configManager.scopedValue(scope[0], scope[1], 'cryptoCurrencies', config)
|
||||
return scopes.reduce((acc, scope) => _.union(acc, scoped(scope)), [])
|
||||
}
|
||||
|
||||
function getGroup (schema, fieldCode) {
|
||||
return schema.groups.find(group => group.fields.find(_.isEqual(fieldCode)))
|
||||
}
|
||||
|
||||
function getField (schema, group, fieldCode) {
|
||||
if (!group) group = getGroup(schema, fieldCode)
|
||||
const field = schema.fields.find(r => r.code === fieldCode)
|
||||
return _.merge(_.pick(['cryptoScope', 'machineScope'], group), field)
|
||||
}
|
||||
|
||||
const fetchMachines = () => machineLoader.getMachines()
|
||||
.then(machineList => machineList.map(r => r.deviceId))
|
||||
|
||||
function validateCurrentConfig () {
|
||||
return fetchConfig()
|
||||
.then(configValidate.validateRequires)
|
||||
}
|
||||
|
||||
const decorateEnabledIf = _.curry((schemaFields, schemaField) => {
|
||||
const code = schemaField.fieldLocator.code
|
||||
const field = _.find(f => f.code === code, schemaFields)
|
||||
|
||||
return _.assign(schemaField, {
|
||||
fieldEnabledIfAny: field.enabledIfAny || [],
|
||||
fieldEnabledIfAll: field.enabledIfAll || []
|
||||
})
|
||||
})
|
||||
|
||||
function fetchConfigGroup (code) {
|
||||
const fieldLocatorCodeEq = _.matchesProperty(['fieldLocator', 'code'])
|
||||
return Promise.all([fetchSchema(), fetchData(), fetchConfig(), fetchMachines()])
|
||||
.then(([schema, data, config, machineList]) => {
|
||||
const groupSchema = schema.groups.find(r => r.code === code)
|
||||
|
||||
if (!groupSchema) throw new Error('No such group schema: ' + code)
|
||||
|
||||
const schemaFields = groupSchema.fields
|
||||
.map(_.curry(getField)(schema, groupSchema))
|
||||
.map(f => _.assign(f, {
|
||||
fieldEnabledIfAny: f.enabledIfAny || [],
|
||||
fieldEnabledIfAll: f.enabledIfAll || []
|
||||
}))
|
||||
|
||||
const candidateFields = [
|
||||
schemaFields.map(_.get('requiredIf')),
|
||||
schemaFields.map(_.get('enabledIfAny')),
|
||||
schemaFields.map(_.get('enabledIfAll')),
|
||||
groupSchema.fields,
|
||||
'fiatCurrency'
|
||||
]
|
||||
|
||||
const smush = _.flow(_.flattenDeep, _.compact, _.uniq)
|
||||
const configFields = smush(candidateFields)
|
||||
|
||||
// Expand this to check against full schema
|
||||
const fieldValidator = field => !_.isNil(_.get('fieldLocator.fieldScope.crypto', field))
|
||||
|
||||
const reducer = (acc, configField) => {
|
||||
return acc.concat(config.filter(fieldLocatorCodeEq(configField)))
|
||||
}
|
||||
|
||||
const reducedFields = _.filter(fieldValidator, configFields.reduce(reducer, []))
|
||||
const values = _.map(decorateEnabledIf(schema.fields), reducedFields)
|
||||
|
||||
groupSchema.fields = undefined
|
||||
groupSchema.entries = schemaFields
|
||||
|
||||
const selectedCryptos = _.defaultTo([], getCryptos(config, machineList))
|
||||
|
||||
return {
|
||||
schema: groupSchema,
|
||||
values,
|
||||
selectedCryptos,
|
||||
data
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function massageCurrencies (currencies) {
|
||||
const convert = r => ({
|
||||
code: r['Alphabetic Code'],
|
||||
display: r['Currency']
|
||||
})
|
||||
const top5Codes = ['USD', 'EUR', 'GBP', 'CAD', 'AUD']
|
||||
const mapped = _.map(convert, currencies)
|
||||
const codeToRec = code => _.find(_.matchesProperty('code', code), mapped)
|
||||
const top5 = _.map(codeToRec, top5Codes)
|
||||
const raw = _.uniqBy(_.get('code'), _.concat(top5, mapped))
|
||||
return raw.filter(r => r.code !== '' && r.code[0] !== 'X' && r.display.indexOf('(') === -1)
|
||||
}
|
||||
|
||||
const mapLanguage = lang => {
|
||||
const arr = lang.split('-')
|
||||
const code = arr[0]
|
||||
const country = arr[1]
|
||||
const langNameArr = languageRec.lang[code]
|
||||
if (!langNameArr) return null
|
||||
const langName = langNameArr[0]
|
||||
if (!country) return {code: lang, display: langName}
|
||||
return {code: lang, display: `${langName} [${country}]`}
|
||||
}
|
||||
|
||||
const supportedLanguages = languageRec.supported
|
||||
const languages = supportedLanguages.map(mapLanguage).filter(r => r)
|
||||
const ALL_CRYPTOS = ['BTC', 'ETH', 'LTC', 'DASH', 'ZEC', 'BCH']
|
||||
|
||||
const filterAccounts = (data, isDevMode) => {
|
||||
const notAllowed = ['mock-ticker', 'mock-wallet', 'mock-exchange', 'mock-sms', 'mock-id-verify', 'mock-zero-conf']
|
||||
const filterOut = o => _.includes(o.code, notAllowed)
|
||||
return isDevMode ? data : {...data, accounts: _.filter(a => !filterOut(a), data.accounts)}
|
||||
}
|
||||
|
||||
function fetchData () {
|
||||
return machineLoader.getMachineNames()
|
||||
.then(machineList => ({
|
||||
currencies: massageCurrencies(currencies),
|
||||
cryptoCurrencies: [
|
||||
{crypto: 'BTC', display: 'Bitcoin'},
|
||||
{crypto: 'ETH', display: 'Ethereum'},
|
||||
{crypto: 'LTC', display: 'Litecoin'},
|
||||
{crypto: 'DASH', display: 'Dash'},
|
||||
{crypto: 'ZEC', display: 'Zcash'},
|
||||
{crypto: 'BCH', display: 'Bitcoin Cash'}
|
||||
],
|
||||
languages: languages,
|
||||
countries,
|
||||
accounts: [
|
||||
{code: 'bitpay', display: 'Bitpay', class: 'ticker', cryptos: ['BTC', 'BCH']},
|
||||
{code: 'kraken', display: 'Kraken', class: 'ticker', cryptos: ['BTC', 'ETH', 'LTC', 'DASH', 'ZEC', 'BCH']},
|
||||
{code: 'bitstamp', display: 'Bitstamp', class: 'ticker', cryptos: ['BTC', 'ETH', 'LTC', 'BCH']},
|
||||
{code: 'coinbase', display: 'Coinbase', class: 'ticker', cryptos: ['BTC', 'ETH', 'LTC', 'BCH', 'ZEC', 'DASH']},
|
||||
{code: 'itbit', display: 'itBit', class: 'ticker', cryptos: ['BTC', 'ETH']},
|
||||
{code: 'mock-ticker', display: 'Mock (Caution!)', class: 'ticker', cryptos: ALL_CRYPTOS},
|
||||
{code: 'bitcoind', display: 'bitcoind', class: 'wallet', cryptos: ['BTC']},
|
||||
{code: 'no-layer2', display: 'No Layer 2', class: 'layer2', cryptos: ALL_CRYPTOS},
|
||||
{code: 'infura', display: 'Infura', class: 'wallet', cryptos: ['ETH']},
|
||||
{code: 'geth', display: 'geth', class: 'wallet', cryptos: ['ETH']},
|
||||
{code: 'zcashd', display: 'zcashd', class: 'wallet', cryptos: ['ZEC']},
|
||||
{code: 'litecoind', display: 'litecoind', class: 'wallet', cryptos: ['LTC']},
|
||||
{code: 'dashd', display: 'dashd', class: 'wallet', cryptos: ['DASH']},
|
||||
{code: 'bitcoincashd', display: 'bitcoincashd', class: 'wallet', cryptos: ['BCH']},
|
||||
{code: 'bitgo', display: 'BitGo', class: 'wallet', cryptos: ['BTC', 'ZEC', 'LTC', 'BCH', 'DASH']},
|
||||
{code: 'bitstamp', display: 'Bitstamp', class: 'exchange', cryptos: ['BTC', 'ETH', 'LTC', 'BCH']},
|
||||
{code: 'itbit', display: 'itBit', class: 'exchange', cryptos: ['BTC', 'ETH']},
|
||||
{code: 'kraken', display: 'Kraken', class: 'exchange', cryptos: ['BTC', 'ETH', 'LTC', 'DASH', 'ZEC', 'BCH']},
|
||||
{code: 'mock-wallet', display: 'Mock (Caution!)', class: 'wallet', cryptos: ALL_CRYPTOS},
|
||||
{code: 'no-exchange', display: 'No exchange', class: 'exchange', cryptos: ALL_CRYPTOS},
|
||||
{code: 'mock-exchange', display: 'Mock exchange', class: 'exchange', cryptos: ALL_CRYPTOS},
|
||||
{code: 'mock-sms', display: 'Mock SMS', class: 'sms'},
|
||||
{code: 'mock-id-verify', display: 'Mock ID verifier', class: 'idVerifier'},
|
||||
{code: 'twilio', display: 'Twilio', class: 'sms'},
|
||||
{code: 'mailgun', display: 'Mailgun', class: 'email'},
|
||||
{code: 'all-zero-conf', display: 'Always 0-conf', class: 'zeroConf', cryptos: ['BTC', 'ZEC', 'LTC', 'DASH', 'BCH']},
|
||||
{code: 'no-zero-conf', display: 'Always 1-conf', class: 'zeroConf', cryptos: ALL_CRYPTOS},
|
||||
{code: 'blockcypher', display: 'Blockcypher', class: 'zeroConf', cryptos: ['BTC']},
|
||||
{code: 'mock-zero-conf', display: 'Mock 0-conf', class: 'zeroConf', cryptos: ['BTC', 'ZEC', 'LTC', 'DASH', 'BCH', 'ETH']}
|
||||
],
|
||||
machines: machineList.map(machine => ({machine: machine.deviceId, display: machine.name}))
|
||||
}))
|
||||
.then((data) => {
|
||||
return filterAccounts(data, devMode)
|
||||
})
|
||||
}
|
||||
|
||||
function saveConfigGroup (results) {
|
||||
if (results.values.length === 0) return fetchConfigGroup(results.groupCode)
|
||||
|
||||
return settingsLoader.modifyConfig(results.values)
|
||||
.then(() => fetchConfigGroup(results.groupCode))
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
fetchConfigGroup,
|
||||
saveConfigGroup,
|
||||
validateCurrentConfig,
|
||||
fetchConfig,
|
||||
filterAccounts
|
||||
}
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,250 +0,0 @@
|
|||
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 pgp = require('pg-promise')()
|
||||
const db = require('../db')
|
||||
const configValidate = require('./config-validate')
|
||||
const schema = require('./lamassu-schema.json')
|
||||
|
||||
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 _.reject(r => _.isNil(r.fieldValue), _.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 (filterSchemaVersion = true) {
|
||||
return Promise.all([loadLatestConfig(filterSchemaVersion), loadAccounts(filterSchemaVersion)])
|
||||
.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 and schema_version=$3
|
||||
and valid`
|
||||
|
||||
return db.one(sql, [versionId, 'config', configValidate.SETTINGS_LOADER_SCHEMA_VERSION])
|
||||
.then(row => row.data.config)
|
||||
.then(configValidate.validate)
|
||||
.catch(err => {
|
||||
if (err.name === 'QueryResultError') {
|
||||
throw new Error('No such config version: ' + versionId)
|
||||
}
|
||||
|
||||
throw err
|
||||
})
|
||||
}
|
||||
|
||||
function loadLatestConfig (filterSchemaVersion = true) {
|
||||
if (argv.fixture) return loadFixture()
|
||||
|
||||
const sql = `select id, valid, data
|
||||
from user_config
|
||||
where type=$1 ${filterSchemaVersion ? 'and schema_version=$2' : ''}
|
||||
and valid
|
||||
order by id desc
|
||||
limit 1`
|
||||
|
||||
return db.oneOrNone(sql, ['config', configValidate.SETTINGS_LOADER_SCHEMA_VERSION])
|
||||
.then(row => row.data.config)
|
||||
.then(configValidate.validate)
|
||||
.catch(err => {
|
||||
if (err.name === 'QueryResultError') {
|
||||
throw new Error('lamassu-server is not configured')
|
||||
}
|
||||
|
||||
throw err
|
||||
})
|
||||
}
|
||||
|
||||
function loadRecentConfig () {
|
||||
if (argv.fixture) return loadFixture()
|
||||
|
||||
const sql = `select id, data
|
||||
from user_config
|
||||
where type=$1 and schema_version=$2
|
||||
order by id desc
|
||||
limit 1`
|
||||
|
||||
return db.one(sql, ['config', configValidate.SETTINGS_LOADER_SCHEMA_VERSION])
|
||||
.then(row => row.data.config)
|
||||
}
|
||||
|
||||
function loadAccounts (filterSchemaVersion = true) {
|
||||
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 ${filterSchemaVersion ? 'and schema_version=$2' : ''}`, ['accounts', configValidate.SETTINGS_LOADER_SCHEMA_VERSION])
|
||||
.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 configValidate.validate(config)
|
||||
.then(() => db.none(sql, ['config', {config}, true]))
|
||||
.catch(() => db.none(sql, ['config', {config}, false]))
|
||||
}
|
||||
|
||||
function configAddField (scope, fieldCode, fieldType, fieldClass, value) {
|
||||
return {
|
||||
fieldLocator: {
|
||||
fieldScope: {
|
||||
crypto: scope.crypto,
|
||||
machine: scope.machine
|
||||
},
|
||||
code: fieldCode,
|
||||
fieldType,
|
||||
fieldClass
|
||||
},
|
||||
fieldValue: {fieldType, value}
|
||||
}
|
||||
}
|
||||
|
||||
function configDeleteField (scope, fieldCode) {
|
||||
return {
|
||||
fieldLocator: {
|
||||
fieldScope: {
|
||||
crypto: scope.crypto,
|
||||
machine: scope.machine
|
||||
},
|
||||
code: fieldCode
|
||||
},
|
||||
fieldValue: null
|
||||
}
|
||||
}
|
||||
|
||||
function populateScopes (schema) {
|
||||
const scopeLookup = {}
|
||||
_.forEach(r => {
|
||||
const scope = {
|
||||
cryptoScope: r.cryptoScope,
|
||||
machineScope: r.machineScope
|
||||
}
|
||||
|
||||
_.forEach(field => { scopeLookup[field] = scope }, r.fields)
|
||||
}, schema.groups)
|
||||
|
||||
return _.map(r => _.assign(scopeLookup[r.code], r), schema.fields)
|
||||
}
|
||||
|
||||
function cryptoDefaultOverride (cryptoCode, code, defaultValue) {
|
||||
if (cryptoCode === 'ETH' && code === 'zeroConf') {
|
||||
return 'no-zero-conf'
|
||||
}
|
||||
|
||||
return defaultValue
|
||||
}
|
||||
|
||||
function cryptoCodeDefaults (schema, cryptoCode) {
|
||||
const scope = {crypto: cryptoCode, machine: 'global'}
|
||||
|
||||
const schemaEntries = populateScopes(schema)
|
||||
const hasCryptoSpecificDefault = r => r.cryptoScope === 'specific' && !_.isNil(r.default)
|
||||
const cryptoSpecificFields = _.filter(hasCryptoSpecificDefault, schemaEntries)
|
||||
|
||||
return _.map(r => {
|
||||
const defaultValue = cryptoDefaultOverride(cryptoCode, r.code, r.default)
|
||||
|
||||
return configAddField(scope, r.code, r.fieldType, r.fieldClass, defaultValue)
|
||||
}, cryptoSpecificFields)
|
||||
}
|
||||
|
||||
const uniqCompact = _.flow(_.compact, _.uniq)
|
||||
|
||||
function addCryptoDefaults (oldConfig, newFields) {
|
||||
const cryptoCodeEntries = _.filter(v => v.fieldLocator.code === 'cryptoCurrencies', newFields)
|
||||
const cryptoCodes = _.flatMap(_.get('fieldValue.value'), cryptoCodeEntries)
|
||||
const uniqueCryptoCodes = uniqCompact(cryptoCodes)
|
||||
|
||||
const mapDefaults = cryptoCode => cryptoCodeDefaults(schema, cryptoCode)
|
||||
const defaults = _.flatMap(mapDefaults, uniqueCryptoCodes)
|
||||
|
||||
return mergeValues(defaults, oldConfig)
|
||||
}
|
||||
|
||||
function modifyConfig (newFields) {
|
||||
const TransactionMode = pgp.txMode.TransactionMode
|
||||
const isolationLevel = pgp.txMode.isolationLevel
|
||||
const mode = new TransactionMode({ tiLevel: isolationLevel.serializable })
|
||||
|
||||
function transaction (t) {
|
||||
return loadRecentConfig()
|
||||
.then(oldConfig => {
|
||||
const oldConfigWithDefaults = addCryptoDefaults(oldConfig, newFields)
|
||||
const doSave = _.flow(mergeValues, save)
|
||||
return doSave(oldConfigWithDefaults, newFields)
|
||||
})
|
||||
}
|
||||
|
||||
return db.tx({ mode }, transaction)
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
settings,
|
||||
loadConfig,
|
||||
loadRecentConfig,
|
||||
load,
|
||||
loadLatest,
|
||||
loadLatestConfig,
|
||||
save,
|
||||
loadFixture,
|
||||
mergeValues,
|
||||
modifyConfig,
|
||||
configAddField,
|
||||
configDeleteField
|
||||
}
|
||||
|
|
@ -1,477 +0,0 @@
|
|||
const _ = require('lodash/fp')
|
||||
const uuid = require('uuid')
|
||||
const { COINS } = require('@lamassu/coins')
|
||||
const { scopedValue } = require('./admin/config-manager')
|
||||
|
||||
const GLOBAL = 'global'
|
||||
const ALL_CRYPTOS = _.values(COINS).sort()
|
||||
const ALL_CRYPTOS_STRING = 'ALL_COINS'
|
||||
const ALL_MACHINES = 'ALL_MACHINES'
|
||||
|
||||
const GLOBAL_SCOPE = {
|
||||
crypto: ALL_CRYPTOS,
|
||||
machine: GLOBAL
|
||||
}
|
||||
|
||||
function getConfigFields (codes, config) {
|
||||
const stringfiedGlobalScope = JSON.stringify(GLOBAL_SCOPE)
|
||||
|
||||
const fields = config
|
||||
.filter(i => codes.includes(i.fieldLocator.code))
|
||||
.map(f => {
|
||||
const crypto = Array.isArray(f.fieldLocator.fieldScope.crypto)
|
||||
? f.fieldLocator.fieldScope.crypto.sort()
|
||||
: f.fieldLocator.fieldScope.crypto === GLOBAL
|
||||
? ALL_CRYPTOS
|
||||
: [f.fieldLocator.fieldScope.crypto]
|
||||
const machine = f.fieldLocator.fieldScope.machine
|
||||
|
||||
return {
|
||||
code: f.fieldLocator.code,
|
||||
scope: {
|
||||
crypto,
|
||||
machine
|
||||
},
|
||||
value: f.fieldValue.value
|
||||
}
|
||||
})
|
||||
.filter(f => f.value != null)
|
||||
|
||||
const grouped = _.chain(fields)
|
||||
.groupBy(f => JSON.stringify(f.scope))
|
||||
.value()
|
||||
|
||||
return {
|
||||
global: grouped[stringfiedGlobalScope] || [],
|
||||
scoped:
|
||||
_.entries(
|
||||
_.chain(grouped)
|
||||
.omit([stringfiedGlobalScope])
|
||||
.value()
|
||||
).map(f => {
|
||||
const fallbackValues =
|
||||
_.difference(codes, f[1].map(v => v.code))
|
||||
.map(v => ({
|
||||
code: v,
|
||||
scope: JSON.parse(f[0]),
|
||||
value: scopedValue(f[0].crypto, f[0].machine, v, config)
|
||||
}))
|
||||
.filter(f => f.value != null)
|
||||
|
||||
return {
|
||||
scope: JSON.parse(f[0]),
|
||||
values: f[1].concat(fallbackValues)
|
||||
}
|
||||
}) || []
|
||||
}
|
||||
}
|
||||
|
||||
function migrateCommissions (config) {
|
||||
const areArraysEquals = (arr1, arr2) => Array.isArray(arr1) && Array.isArray(arr2) && _.isEmpty(_.xor(arr1, arr2))
|
||||
const getMachine = _.get('scope.machine')
|
||||
const getCrypto = _.get('scope.crypto')
|
||||
const flattenCoins = _.compose(_.flatten, _.map(getCrypto))
|
||||
const diffAllCryptos = _.compose(_.difference(ALL_CRYPTOS))
|
||||
|
||||
const codes = {
|
||||
minimumTx: 'minimumTx',
|
||||
cashInFee: 'fixedFee',
|
||||
cashInCommission: 'cashIn',
|
||||
cashOutCommission: 'cashOut'
|
||||
}
|
||||
|
||||
const { global, scoped } = getConfigFields(_.keys(codes), config)
|
||||
const defaultCashOutCommissions = { code: 'cashOutCommission', value: 0, scope: global[0].scope }
|
||||
const isCashOutDisabled =
|
||||
_.isEmpty(_.filter(commissionElement => commissionElement.code === 'cashOutCommission', global))
|
||||
const globalWithDefaults =
|
||||
isCashOutDisabled ? _.concat(global, defaultCashOutCommissions) : global
|
||||
|
||||
const machineAndCryptoScoped = scoped.filter(
|
||||
f => f.scope.machine !== GLOBAL_SCOPE.machine && f.scope.crypto.length === 1
|
||||
)
|
||||
const cryptoScoped = scoped.filter(
|
||||
f =>
|
||||
f.scope.machine === GLOBAL_SCOPE.machine &&
|
||||
!areArraysEquals(f.scope.crypto, GLOBAL_SCOPE.crypto)
|
||||
)
|
||||
const machineScoped = scoped.filter(
|
||||
f =>
|
||||
f.scope.machine !== GLOBAL_SCOPE.machine &&
|
||||
areArraysEquals(f.scope.crypto, GLOBAL_SCOPE.crypto)
|
||||
)
|
||||
|
||||
const withCryptoScoped = machineAndCryptoScoped.concat(cryptoScoped)
|
||||
|
||||
const filteredMachineScoped = _.map(it => {
|
||||
const filterByMachine = _.filter(_.includes(getMachine(it)))
|
||||
const unrepeatedCryptos = _.compose(
|
||||
diffAllCryptos,
|
||||
flattenCoins,
|
||||
filterByMachine
|
||||
)(withCryptoScoped)
|
||||
|
||||
return _.set('scope.crypto', unrepeatedCryptos)(it)
|
||||
})(machineScoped)
|
||||
|
||||
const allCommissionsOverrides = withCryptoScoped.concat(filteredMachineScoped)
|
||||
|
||||
return {
|
||||
..._.fromPairs(globalWithDefaults.map(f => [`commissions_${codes[f.code]}`, f.value])),
|
||||
...(allCommissionsOverrides.length > 0 && {
|
||||
commissions_overrides: allCommissionsOverrides.map(s => ({
|
||||
..._.fromPairs(s.values.map(f => [codes[f.code], f.value])),
|
||||
machine: s.scope.machine === GLOBAL ? ALL_MACHINES : s.scope.machine,
|
||||
cryptoCurrencies: areArraysEquals(s.scope.crypto, ALL_CRYPTOS) ? [ALL_CRYPTOS_STRING] : s.scope.crypto,
|
||||
id: uuid.v4()
|
||||
}))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function migrateLocales (config) {
|
||||
const codes = {
|
||||
country: 'country',
|
||||
fiatCurrency: 'fiatCurrency',
|
||||
machineLanguages: 'languages',
|
||||
cryptoCurrencies: 'cryptoCurrencies',
|
||||
timezone: 'timezone'
|
||||
}
|
||||
|
||||
const { global, scoped } = getConfigFields(_.keys(codes), config)
|
||||
|
||||
return {
|
||||
..._.fromPairs(global.map(f => [`locale_${codes[f.code]}`, f.value])),
|
||||
...(scoped.length > 0 && {
|
||||
locale_overrides: scoped.map(s => ({
|
||||
..._.fromPairs(s.values.map(f => [codes[f.code], f.value])),
|
||||
machine: s.scope.machine,
|
||||
id: uuid.v4()
|
||||
}))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function migrateCashOut (config) {
|
||||
const globalCodes = {
|
||||
fudgeFactorActive: 'fudgeFactorActive'
|
||||
}
|
||||
|
||||
const scopedCodes = {
|
||||
cashOutEnabled: 'active',
|
||||
topCashOutDenomination: 'top',
|
||||
bottomCashOutDenomination: 'bottom',
|
||||
zeroConfLimit: 'zeroConfLimit'
|
||||
}
|
||||
|
||||
const { global } = getConfigFields(_.keys(globalCodes), config)
|
||||
const { scoped } = getConfigFields(_.keys(scopedCodes), config)
|
||||
|
||||
return {
|
||||
..._.fromPairs(
|
||||
global.map(f => [`cashOut_${globalCodes[f.code]}`, f.value])
|
||||
),
|
||||
..._.fromPairs(
|
||||
_.flatten(
|
||||
scoped.map(s => {
|
||||
const fields = s.values.map(f => [
|
||||
`cashOut_${f.scope.machine}_${scopedCodes[f.code]}`,
|
||||
f.value
|
||||
])
|
||||
|
||||
fields.push([`cashOut_${s.scope.machine}_id`, s.scope.machine])
|
||||
|
||||
return fields
|
||||
})
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
function migrateNotifications (config) {
|
||||
const globalCodes = {
|
||||
notificationsEmailEnabled: 'email_active',
|
||||
notificationsSMSEnabled: 'sms_active',
|
||||
cashOutCassette1AlertThreshold: 'fiatBalanceCassette1',
|
||||
cashOutCassette2AlertThreshold: 'fiatBalanceCassette2',
|
||||
cryptoAlertThreshold: 'cryptoLowBalance'
|
||||
}
|
||||
|
||||
const machineScopedCodes = {
|
||||
cashOutCassette1AlertThreshold: 'cassette1',
|
||||
cashOutCassette2AlertThreshold: 'cassette2'
|
||||
}
|
||||
|
||||
const cryptoScopedCodes = {
|
||||
cryptoAlertThreshold: 'lowBalance'
|
||||
}
|
||||
|
||||
const { global } = getConfigFields(_.keys(globalCodes), config)
|
||||
const machineScoped = getConfigFields(
|
||||
_.keys(machineScopedCodes),
|
||||
config
|
||||
).scoped.filter(f => f.scope.crypto === GLOBAL && f.scope.machine !== GLOBAL)
|
||||
const cryptoScoped = getConfigFields(
|
||||
_.keys(cryptoScopedCodes),
|
||||
config
|
||||
).scoped.filter(f => f.scope.crypto !== GLOBAL && f.scope.machine === GLOBAL)
|
||||
|
||||
return {
|
||||
..._.fromPairs(
|
||||
global.map(f => [`notifications_${globalCodes[f.code]}`, f.value])
|
||||
),
|
||||
notifications_email_balance: true,
|
||||
notifications_email_transactions: true,
|
||||
notifications_email_compliance: true,
|
||||
notifications_email_errors: true,
|
||||
notifications_sms_balance: true,
|
||||
notifications_sms_transactions: true,
|
||||
notifications_sms_compliance: true,
|
||||
notifications_sms_errors: true,
|
||||
...(machineScoped.length > 0 && {
|
||||
notifications_fiatBalanceOverrides: machineScoped.map(s => ({
|
||||
..._.fromPairs(
|
||||
s.values.map(f => [machineScopedCodes[f.code], f.value])
|
||||
),
|
||||
machine: s.scope.machine,
|
||||
id: uuid.v4()
|
||||
}))
|
||||
}),
|
||||
...(cryptoScoped.length > 0 && {
|
||||
notifications_cryptoBalanceOverrides: cryptoScoped.map(s => ({
|
||||
..._.fromPairs(s.values.map(f => [cryptoScopedCodes[f.code], f.value])),
|
||||
cryptoCurrency: s.scope.crypto,
|
||||
id: uuid.v4()
|
||||
}))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function migrateWallet (config) {
|
||||
const codes = {
|
||||
ticker: 'ticker',
|
||||
wallet: 'wallet',
|
||||
exchange: 'exchange',
|
||||
zeroConf: 'zeroConf'
|
||||
}
|
||||
|
||||
const { scoped } = getConfigFields(_.keys(codes), config)
|
||||
|
||||
return {
|
||||
...(scoped.length > 0 &&
|
||||
_.fromPairs(
|
||||
_.flatten(
|
||||
scoped.map(s =>
|
||||
s.values.map(f => [
|
||||
`wallets_${f.scope.crypto}_${codes[f.code]}`,
|
||||
f.value
|
||||
])
|
||||
)
|
||||
)
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
function migrateOperatorInfo (config) {
|
||||
const codes = {
|
||||
operatorInfoActive: 'active',
|
||||
operatorInfoEmail: 'email',
|
||||
operatorInfoName: 'name',
|
||||
operatorInfoPhone: 'phone',
|
||||
operatorInfoWebsite: 'website',
|
||||
operatorInfoCompanyNumber: 'companyNumber'
|
||||
}
|
||||
|
||||
const { global } = getConfigFields(_.keys(codes), config)
|
||||
|
||||
return {
|
||||
..._.fromPairs(global.map(f => [`operatorInfo_${codes[f.code]}`, f.value]))
|
||||
}
|
||||
}
|
||||
|
||||
function migrateReceiptPrinting (config) {
|
||||
const codes = {
|
||||
receiptPrintingActive: 'active'
|
||||
}
|
||||
|
||||
const { global } = getConfigFields(_.keys(codes), config)
|
||||
|
||||
return {
|
||||
..._.fromPairs(global.map(f => [`receipt_${codes[f.code]}`, f.value])),
|
||||
receipt_operatorWebsite: true,
|
||||
receipt_operatorEmail: true,
|
||||
receipt_operatorPhone: true,
|
||||
receipt_companyRegistration: true,
|
||||
receipt_machineLocation: true,
|
||||
receipt_customerNameOrPhoneNumber: true,
|
||||
receipt_exchangeRate: true,
|
||||
receipt_addressQRCode: true
|
||||
}
|
||||
}
|
||||
|
||||
function migrateCoinATMRadar (config) {
|
||||
const codes = ['coinAtmRadarActive', 'coinAtmRadarShowRates']
|
||||
|
||||
const { global } = getConfigFields(codes, config)
|
||||
const coinAtmRadar = _.fromPairs(global.map(f => [f.code, f.value]))
|
||||
|
||||
return {
|
||||
coinAtmRadar_active: coinAtmRadar.coinAtmRadarActive,
|
||||
coinAtmRadar_commissions: coinAtmRadar.coinAtmRadarShowRates,
|
||||
coinAtmRadar_limitsAndVerification: coinAtmRadar.coinAtmRadarShowRates
|
||||
}
|
||||
}
|
||||
|
||||
function migrateTermsAndConditions (config) {
|
||||
const codes = {
|
||||
termsScreenActive: 'active',
|
||||
termsScreenTitle: 'title',
|
||||
termsScreenText: 'text',
|
||||
termsAcceptButtonText: 'acceptButtonText',
|
||||
termsCancelButtonText: 'cancelButtonText'
|
||||
}
|
||||
|
||||
const { global } = getConfigFields(_.keys(codes), config)
|
||||
|
||||
return {
|
||||
..._.fromPairs(
|
||||
global.map(f => [`termsConditions_${codes[f.code]}`, f.value])
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
function migrateComplianceTriggers (config) {
|
||||
|
||||
const suspensionDays = 1
|
||||
|
||||
const triggerTypes = {
|
||||
amount: 'txAmount',
|
||||
velocity: 'txVelocity',
|
||||
volume: 'txVolume',
|
||||
consecutiveDays: 'consecutiveDays'
|
||||
}
|
||||
|
||||
const requirements = {
|
||||
sms: 'sms',
|
||||
idData: 'idCardData',
|
||||
idPhoto: 'idCardPhoto',
|
||||
facePhoto: 'facephoto',
|
||||
sanctions: 'sanctions',
|
||||
suspend: 'suspend'
|
||||
}
|
||||
|
||||
function createTrigger (
|
||||
requirement,
|
||||
threshold,
|
||||
suspensionDays
|
||||
) {
|
||||
const triggerConfig = {
|
||||
id: uuid.v4(),
|
||||
direction: 'both',
|
||||
threshold,
|
||||
thresholdDays: 1,
|
||||
triggerType: triggerTypes.volume,
|
||||
requirement
|
||||
}
|
||||
if (!requirement === 'suspend') return triggerConfig
|
||||
return _.assign(triggerConfig, { suspensionDays })
|
||||
}
|
||||
|
||||
const codes = [
|
||||
'smsVerificationActive',
|
||||
'smsVerificationThreshold',
|
||||
'idCardDataVerificationActive',
|
||||
'idCardDataVerificationThreshold',
|
||||
'idCardPhotoVerificationActive',
|
||||
'idCardPhotoVerificationThreshold',
|
||||
'frontCameraVerificationActive',
|
||||
'frontCameraVerificationThreshold',
|
||||
'sanctionsVerificationActive',
|
||||
'sanctionsVerificationThreshold',
|
||||
'hardLimitVerificationActive',
|
||||
'hardLimitVerificationThreshold',
|
||||
'rejectAddressReuseActive'
|
||||
]
|
||||
|
||||
const global = _.fromPairs(
|
||||
getConfigFields(codes, config).global.map(f => [f.code, f.value])
|
||||
)
|
||||
|
||||
const triggers = []
|
||||
if (global.smsVerificationActive && _.isNumber(global.smsVerificationThreshold)) {
|
||||
triggers.push(
|
||||
createTrigger(requirements.sms, global.smsVerificationThreshold)
|
||||
)
|
||||
}
|
||||
if (global.idCardDataVerificationActive && _.isNumber(global.idCardDataVerificationThreshold)) {
|
||||
triggers.push(
|
||||
createTrigger(requirements.idData, global.idCardDataVerificationThreshold)
|
||||
)
|
||||
}
|
||||
if (global.idCardPhotoVerificationActive && _.isNumber(global.idCardPhotoVerificationThreshold)) {
|
||||
triggers.push(
|
||||
createTrigger(requirements.idPhoto, global.idCardPhotoVerificationThreshold)
|
||||
)
|
||||
}
|
||||
if (global.frontCameraVerificationActive && _.isNumber(global.frontCameraVerificationThreshold)) {
|
||||
triggers.push(
|
||||
createTrigger(requirements.facePhoto, global.frontCameraVerificationThreshold)
|
||||
)
|
||||
}
|
||||
if (global.sanctionsVerificationActive && _.isNumber(global.sanctionsVerificationThreshold)) {
|
||||
triggers.push(
|
||||
createTrigger(requirements.sanctions, global.sanctionsVerificationThreshold)
|
||||
)
|
||||
}
|
||||
if (global.hardLimitVerificationActive && _.isNumber(global.hardLimitVerificationThreshold)) {
|
||||
triggers.push(
|
||||
createTrigger(requirements.suspend, global.hardLimitVerificationThreshold, suspensionDays)
|
||||
)
|
||||
}
|
||||
return {
|
||||
triggers,
|
||||
['compliance_rejectAddressReuse']: global.rejectAddressReuseActive
|
||||
}
|
||||
}
|
||||
|
||||
function migrateConfig (config) {
|
||||
return {
|
||||
...migrateCommissions(config),
|
||||
...migrateLocales(config),
|
||||
...migrateCashOut(config),
|
||||
...migrateNotifications(config),
|
||||
...migrateWallet(config),
|
||||
...migrateOperatorInfo(config),
|
||||
...migrateReceiptPrinting(config),
|
||||
...migrateCoinATMRadar(config),
|
||||
...migrateTermsAndConditions(config),
|
||||
...migrateComplianceTriggers(config)
|
||||
}
|
||||
}
|
||||
|
||||
function migrateAccounts (accounts) {
|
||||
const accountArray = [
|
||||
'bitgo',
|
||||
'bitstamp',
|
||||
'blockcypher',
|
||||
'infura',
|
||||
'itbit',
|
||||
'kraken',
|
||||
'mailgun',
|
||||
'twilio'
|
||||
]
|
||||
|
||||
const services = _.keyBy('code', accounts)
|
||||
const serviceFields = _.mapValues(({ fields }) => _.keyBy('code', fields))(services)
|
||||
const allAccounts = _.mapValues(_.mapValues(_.get('value')))(serviceFields)
|
||||
return _.pick(accountArray)(allAccounts)
|
||||
}
|
||||
|
||||
function migrate (config, accounts) {
|
||||
return {
|
||||
config: migrateConfig(config),
|
||||
accounts: migrateAccounts(accounts)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { migrate }
|
||||
|
|
@ -129,6 +129,8 @@ function getMachineNames (config) {
|
|||
.then(([rawMachines, pings, events, config, heartbeat, performance]) => {
|
||||
const mergeByDeviceId = (x, y) => _.values(_.merge(_.keyBy('deviceId', x), _.keyBy('deviceId', y)))
|
||||
const machines = mergeByDeviceId(mergeByDeviceId(rawMachines, heartbeat), performance)
|
||||
console.log('machines', machines)
|
||||
console.log(machines.map(addName(pings, events, config)))
|
||||
|
||||
return machines.map(addName(pings, events, config))
|
||||
})
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
const { AuthenticationError } = require('apollo-server-express')
|
||||
const base64 = require('base-64')
|
||||
const users = require('../../users')
|
||||
|
||||
const buildApolloContext = async ({ req, res }) => {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue