const path = require('path') const fs = require('fs') const _ = require('lodash/fp') const db = require('../db') const configValidate = require('./config-validate') const config = require('./config') function loadSchemas () { const schemasRoot = path.resolve(__dirname, 'schemas') const schemaFiles = fs.readdirSync(schemasRoot) const stripJson = fileName => fileName.slice(0, -5) const readSchema = fileName => JSON.parse(fs.readFileSync(path.resolve(schemasRoot, fileName))) return _.zipObject(_.map(stripJson, schemaFiles), _.map(readSchema, schemaFiles)) } const schemas = loadSchemas() function fetchAccounts () { return db.oneOrNone('select data from user_config where type=$1 and schema_version=$2', ['accounts', configValidate.SETTINGS_LOADER_SCHEMA_VERSION]) .then(row => { // Hard code this for now const accounts = [{ code: 'blockcypher', display: 'Blockcypher', fields: [ { code: 'confidenceFactor', display: 'Confidence Factor', fieldType: 'integer', required: true, value: 40 } ] }] return row ? Promise.resolve(row.data.accounts) : db.none('insert into user_config (type, data, valid) values ($1, $2, $3)', ['accounts', {accounts}, true]) .then(fetchAccounts) }) } function selectedAccounts () { const mapAccount = v => v.fieldLocator.fieldType === 'account' && v.fieldValue.value const mapSchema = code => schemas[code] return config.fetchConfig() .then(conf => { const accountCodes = _.uniq(conf.map(mapAccount) .filter(_.identity)) return _.sortBy(_.get('display'), accountCodes.map(mapSchema) .filter(_.identity)) }) } function fetchAccountSchema (account) { return schemas[account] } function mergeAccount (oldAccount, newAccount) { if (!newAccount) return oldAccount const newFields = newAccount.fields const updateWithData = oldField => { const newField = _.find(r => r.code === oldField.code, newFields) const newValue = _.isUndefined(newField) ? oldField.value : newField.value return _.set('value', newValue, oldField) } const updatedFields = oldAccount.fields.map(updateWithData) return _.set('fields', updatedFields, oldAccount) } function getAccounts (accountCode) { const schema = fetchAccountSchema(accountCode) if (!schema) return Promise.reject(new Error('No schema for: ' + accountCode)) return fetchAccounts() .then(accounts => { if (_.isEmpty(accounts)) return [schema] const account = _.find(r => r.code === accountCode, accounts) const mergedAccount = mergeAccount(schema, account) return updateAccounts(mergedAccount, accounts) }) } function elideSecrets (account) { const elideSecret = field => { return field.fieldType === 'password' ? _.set('value', !_.isEmpty(field.value), field) : field } return _.set('fields', account.fields.map(elideSecret), account) } function getAccount (accountCode) { return getAccounts(accountCode) .then(accounts => _.find(r => r.code === accountCode, accounts)) .then(elideSecrets) } function save (accounts) { return db.none('update user_config set data=$1 where type=$2 and schema_version=$3', [{accounts: accounts}, 'accounts', configValidate.SETTINGS_LOADER_SCHEMA_VERSION]) } function updateAccounts (newAccount, accounts) { const accountCode = newAccount.code const isPresent = _.some(_.matchesProperty('code', accountCode), accounts) const updateAccount = r => r.code === accountCode ? newAccount : r return isPresent ? _.map(updateAccount, accounts) : _.concat(accounts, newAccount) } function updateAccount (account) { return getAccounts(account.code) .then(accounts => { const merged = mergeAccount(_.find(_.matchesProperty('code', account.code), accounts), account) return save(updateAccounts(merged, accounts)) }) .then(() => getAccount(account.code)) } module.exports = { selectedAccounts, getAccount, updateAccount }