From 096c4bc87b8dffd63615ece9b5774ea4cb99ae5a Mon Sep 17 00:00:00 2001 From: Cesar <26280794+csrapr@users.noreply.github.com> Date: Fri, 4 Dec 2020 19:58:17 +0000 Subject: [PATCH] Feat: save highVolumeTxs on DB and plugins code refactor Fix: remove unused module and add space before '(' Chore: add jest tests for transactionNotify --- lib/notifier/email.js | 4 + lib/notifier/test/notifier.test.js | 318 ++++++++++---------- lib/notifier/utils.js | 12 + lib/plugins.js | 463 +++++++++++++++++++---------- 4 files changed, 479 insertions(+), 318 deletions(-) diff --git a/lib/notifier/email.js b/lib/notifier/email.js index 289180c0..174b17ec 100644 --- a/lib/notifier/email.js +++ b/lib/notifier/email.js @@ -84,4 +84,8 @@ function emailAlert (alert) { const sendMessage = email.sendMessage +<<<<<<< HEAD +======= + +>>>>>>> 1706b2c... Feat: save highVolumeTxs on DB and plugins code refactor module.exports = { alertSubject, printEmailAlerts, sendMessage } diff --git a/lib/notifier/test/notifier.test.js b/lib/notifier/test/notifier.test.js index 77d973d1..f7314af8 100644 --- a/lib/notifier/test/notifier.test.js +++ b/lib/notifier/test/notifier.test.js @@ -2,6 +2,8 @@ const BigNumber = require('../../../lib/bn') const notifier = require('..') const utils = require('../utils') +const queries = require("../queries") +const emailFuncs = require('../email') const smsFuncs = require('../sms') afterEach(() => { @@ -81,79 +83,76 @@ const notifSettings = { email_errors: false, sms_errors: true, sms_transactions: true, - highValueTransaction: Infinity, // this will make highValueTx always false + highValueTransaction: Infinity, //this will make highValueTx always false sms: { active: true, errors: true, - transactions: false // force early return + transactions: false // force early return }, email: { active: false, errors: false, - transactions: false // force early return + transactions: false // force early return } } -describe('checkNotifications', () => { - test('Exits checkNotifications with Promise.resolve() if SMS and Email are disabled', async () => { - expect.assertions(1) - await expect( - notifier.checkNotification({ - getNotificationConfig: () => ({ - sms: { active: false, errors: false }, - email: { active: false, errors: false } - }) +test('Exits checkNotifications with Promise.resolve() if SMS and Email are disabled', async () => { + expect.assertions(1) + await expect( + notifier.checkNotification({ + getNotificationConfig: () => ({ + sms: { active: false, errors: false }, + email: { active: false, errors: false } }) - ).resolves.toBe(undefined) - }) - - test('Exits checkNotifications with Promise.resolve() if SMS and Email are disabled even if errors or balance are defined to something', async () => { - expect.assertions(1) - await expect( - notifier.checkNotification({ - getNotificationConfig: () => ({ - sms: { active: false, errors: true, balance: true }, - email: { active: false, errors: true, balance: true } - }) + }) + ).resolves.toBe(undefined) +}) + +test('Exits checkNotifications with Promise.resolve() if SMS and Email are disabled even if errors or balance are defined to something', async () => { + expect.assertions(1) + await expect( + notifier.checkNotification({ + getNotificationConfig: () => ({ + sms: { active: false, errors: true, balance: true }, + email: { active: false, errors: true, balance: true } }) - ).resolves.toBe(undefined) + }) + ).resolves.toBe(undefined) +}) + +test("Check Pings should return code PING for devices that haven't been pinged recently", () => { + expect( + notifier.checkPings([ + { + deviceId: + '7e531a2666987aa27b9917ca17df7998f72771c57fdb21c90bc033999edd17e4', + lastPing: '2020-11-16T13:11:03.169Z', + name: 'Abc123' + } + ]) + ).toMatchObject({ + '7e531a2666987aa27b9917ca17df7998f72771c57fdb21c90bc033999edd17e4': [ + { code: 'PING', machineName: 'Abc123' } + ] }) }) -describe('checkPings', () => { - test("Check Pings should return code PING for devices that haven't been pinged recently", () => { - expect( - notifier.checkPings([ - { - deviceId: - '7e531a2666987aa27b9917ca17df7998f72771c57fdb21c90bc033999edd17e4', - lastPing: '2020-11-16T13:11:03.169Z', - name: 'Abc123' - } - ]) - ).toMatchObject({ - '7e531a2666987aa27b9917ca17df7998f72771c57fdb21c90bc033999edd17e4': [ - { code: 'PING', machineName: 'Abc123' } - ] - }) - }) - - test('Checkpings returns empty array as the value for the id prop, if the lastPing is more recent than 60 seconds', () => { - expect( - notifier.checkPings([ - { - deviceId: - '7a531a2666987aa27b9917ca17df7998f72771c57fdb21c90bc033999edd17e4', - lastPing: new Date(), - name: 'Abc123' - } - ]) - ).toMatchObject({ - '7a531a2666987aa27b9917ca17df7998f72771c57fdb21c90bc033999edd17e4': [] - }) +test('Checkpings returns empty array as the value for the id prop, if the lastPing is more recent than 60 seconds', () => { + expect( + notifier.checkPings([ + { + deviceId: + '7a531a2666987aa27b9917ca17df7998f72771c57fdb21c90bc033999edd17e4', + lastPing: new Date(), + name: 'Abc123' + } + ]) + ).toMatchObject({ + '7a531a2666987aa27b9917ca17df7998f72771c57fdb21c90bc033999edd17e4': [] }) }) + test('Check notification resolves to undefined if shouldNotAlert is called and is true', async () => { const mockShouldNotAlert = jest.spyOn(utils, 'shouldNotAlert') mockShouldNotAlert.mockReturnValue(true) @@ -191,42 +190,25 @@ test('If no alert fingerprint and inAlert is true, exits on call to sendNoAlerts expect(mockSendNoAlerts).toHaveBeenCalledTimes(1) }) -describe('checkStuckScreen', () => { - test('checkStuckScreen returns [] when no events are found', () => { - expect(notifier.checkStuckScreen([], 'Abc123')).toEqual([]) - }) +// vvv tests for checkstuckscreen... +test('checkStuckScreen returns [] when no events are found', () => { + expect(notifier.checkStuckScreen([], 'Abc123')).toEqual([]) +}) - test('checkStuckScreen returns [] if most recent event is idle', () => { - // device_time is what matters for the sorting of the events by recency - expect( - notifier.checkStuckScreen([ - { - id: '48ae51c6-c5b4-485e-b81d-aa337fc025e2', - device_id: - 'f02af604ca9010bd9ae04c427a24da90130da10d355f0a9b235886a89008fc05', - event_type: 'stateChange', - note: '{"state":"chooseCoin","isIdle":false}', - created: '2020-11-23T19:30:29.209Z', - device_time: '1999-11-23T19:30:29.177Z', - age: 157352628.123 - }, - { - id: '48ae51c6-c5b4-485e-b81d-aa337fc025e2', - device_id: - 'f02af604ca9010bd9ae04c427a24da90130da10d355f0a9b235886a89008fc05', - event_type: 'stateChange', - note: '{"state":"chooseCoin","isIdle":true}', - created: '2020-11-23T19:30:29.209Z', - device_time: '2020-11-23T19:30:29.177Z', - age: 157352628.123 - } - ]) - ).toEqual([]) - }) - - test('checkStuckScreen returns object array of length 1 with prop code: "STALE" if age > STALE_STATE', () => { - // there is an age 0 and an isIdle true in the first object but it will be below the second one in the sorting order and thus ignored - const result = notifier.checkStuckScreen([ +test('checkStuckScreen returns [] if most recent event is idle', () => { + // device_time is what matters for the sorting of the events by recency + expect( + notifier.checkStuckScreen([ + { + id: '48ae51c6-c5b4-485e-b81d-aa337fc025e2', + device_id: + 'f02af604ca9010bd9ae04c427a24da90130da10d355f0a9b235886a89008fc05', + event_type: 'stateChange', + note: '{"state":"chooseCoin","isIdle":false}', + created: '2020-11-23T19:30:29.209Z', + device_time: '1999-11-23T19:30:29.177Z', + age: 157352628.123 + }, { id: '48ae51c6-c5b4-485e-b81d-aa337fc025e2', device_id: @@ -234,106 +216,122 @@ describe('checkStuckScreen', () => { event_type: 'stateChange', note: '{"state":"chooseCoin","isIdle":true}', created: '2020-11-23T19:30:29.209Z', - device_time: '1999-11-23T19:30:29.177Z', - age: 0 - }, - { - id: '48ae51c6-c5b4-485e-b81d-aa337fc025e2', - device_id: - 'f02af604ca9010bd9ae04c427a24da90130da10d355f0a9b235886a89008fc05', - event_type: 'stateChange', - note: '{"state":"chooseCoin","isIdle":false}', - created: '2020-11-23T19:30:29.209Z', device_time: '2020-11-23T19:30:29.177Z', age: 157352628.123 } ]) - expect(result[0]).toMatchObject({ code: 'STALE' }) - }) - - test('checkStuckScreen returns empty array if age < STALE_STATE', () => { - const STALE_STATE = require('../codes').STALE_STATE - const result1 = notifier.checkStuckScreen([ - { - id: '48ae51c6-c5b4-485e-b81d-aa337fc025e2', - device_id: - 'f02af604ca9010bd9ae04c427a24da90130da10d355f0a9b235886a89008fc05', - event_type: 'stateChange', - note: '{"state":"chooseCoin","isIdle":false}', - created: '2020-11-23T19:30:29.209Z', - device_time: '2020-11-23T19:30:29.177Z', - age: 0 - } - ]) - const result2 = notifier.checkStuckScreen([ - { - id: '48ae51c6-c5b4-485e-b81d-aa337fc025e2', - device_id: - 'f02af604ca9010bd9ae04c427a24da90130da10d355f0a9b235886a89008fc05', - event_type: 'stateChange', - note: '{"state":"chooseCoin","isIdle":false}', - created: '2020-11-23T19:30:29.209Z', - device_time: '2020-11-23T19:30:29.177Z', - age: STALE_STATE - } - ]) - expect(result1).toEqual([]) - expect(result2).toEqual([]) - }) + ).toEqual([]) }) -test('calls sendRedemptionMessage if !zeroConf and rec.isRedemption', () => { +test('checkStuckScreen returns object array of length 1 with prop code: "STALE" if age > STALE_STATE', () => { + // there is an age 0 and an isIdle true in the first object but it will be below the second one in the sorting order and thus ignored + const result = notifier.checkStuckScreen([ + { + id: '48ae51c6-c5b4-485e-b81d-aa337fc025e2', + device_id: + 'f02af604ca9010bd9ae04c427a24da90130da10d355f0a9b235886a89008fc05', + event_type: 'stateChange', + note: '{"state":"chooseCoin","isIdle":true}', + created: '2020-11-23T19:30:29.209Z', + device_time: '1999-11-23T19:30:29.177Z', + age: 0 + }, + { + id: '48ae51c6-c5b4-485e-b81d-aa337fc025e2', + device_id: + 'f02af604ca9010bd9ae04c427a24da90130da10d355f0a9b235886a89008fc05', + event_type: 'stateChange', + note: '{"state":"chooseCoin","isIdle":false}', + created: '2020-11-23T19:30:29.209Z', + device_time: '2020-11-23T19:30:29.177Z', + age: 157352628.123 + } + ]) + expect(result[0]).toMatchObject({ code: 'STALE' }) +}) + +test('checkStuckScreen returns empty array if age < STALE_STATE', () => { + const STALE_STATE = require('../codes').STALE_STATE + const result1 = notifier.checkStuckScreen([ + { + id: '48ae51c6-c5b4-485e-b81d-aa337fc025e2', + device_id: + 'f02af604ca9010bd9ae04c427a24da90130da10d355f0a9b235886a89008fc05', + event_type: 'stateChange', + note: '{"state":"chooseCoin","isIdle":false}', + created: '2020-11-23T19:30:29.209Z', + device_time: '2020-11-23T19:30:29.177Z', + age: 0 + } + ]) + const result2 = notifier.checkStuckScreen([ + { + id: '48ae51c6-c5b4-485e-b81d-aa337fc025e2', + device_id: + 'f02af604ca9010bd9ae04c427a24da90130da10d355f0a9b235886a89008fc05', + event_type: 'stateChange', + note: '{"state":"chooseCoin","isIdle":false}', + created: '2020-11-23T19:30:29.209Z', + device_time: '2020-11-23T19:30:29.177Z', + age: STALE_STATE + } + ]) + expect(result1).toEqual([]) + expect(result2).toEqual([]) +}) + +test("calls sendRedemptionMessage if !zeroConf and rec.isRedemption", async () => { const configManager = require('../../new-config-manager') const settingsLoader = require('../../new-settings-loader') - const loadLatest = jest.spyOn(settingsLoader, 'loadLatest') + const loadLatest = jest.spyOn(settingsLoader, 'loadLatest') const getGlobalNotifications = jest.spyOn(configManager, 'getGlobalNotifications') const getCashOut = jest.spyOn(configManager, 'getCashOut') // sendRedemptionMessage will cause this func to be called jest.spyOn(smsFuncs, 'sendMessage').mockImplementation((_, rec) => rec) - getCashOut.mockReturnValue({ zeroConfLimit: -Infinity }) - loadLatest.mockReturnValue(Promise.resolve({})) - getGlobalNotifications.mockReturnValue({ ...notifSettings, sms: { active: true, errors: true, transactions: true } }) + getCashOut.mockReturnValue({zeroConfLimit: -Infinity}) + loadLatest.mockReturnValue({}) + getGlobalNotifications.mockReturnValue({... notifSettings, sms: { active: true, errors: true, transactions: true }}) - return notifier.transactionNotify(tx, { isRedemption: true }).then(response => { - // this type of response implies sendRedemptionMessage was called - expect(response[0]).toMatchObject({ - sms: { - body: "Here's an update on transaction bec8d452-9ea2-4846-841b-55a9df8bbd00 - It was just dispensed successfully" - }, - email: { - subject: "Here's an update on transaction bec8d452-9ea2-4846-841b-55a9df8bbd00", - body: 'It was just dispensed successfully' - } - }) + const response = await notifier.transactionNotify(tx, {isRedemption: true}) + + // this type of response implies sendRedemptionMessage was called + expect(response[0]).toMatchObject({ + sms: { + body: "Here's an update on transaction bec8d452-9ea2-4846-841b-55a9df8bbd00 - It was just dispensed successfully" + }, + email: { + subject: "Here's an update on transaction bec8d452-9ea2-4846-841b-55a9df8bbd00", + body: 'It was just dispensed successfully' + } }) }) -test('calls sendTransactionMessage if !zeroConf and !rec.isRedemption', async () => { +test("calls sendTransactionMessage if !zeroConf and !rec.isRedemption", async () => { const configManager = require('../../new-config-manager') const settingsLoader = require('../../new-settings-loader') const machineLoader = require('../../machine-loader') - const loadLatest = jest.spyOn(settingsLoader, 'loadLatest') + const loadLatest = jest.spyOn(settingsLoader, 'loadLatest') const getGlobalNotifications = jest.spyOn(configManager, 'getGlobalNotifications') const getCashOut = jest.spyOn(configManager, 'getCashOut') const getMachineName = jest.spyOn(machineLoader, 'getMachineName') const buildTransactionMessage = jest.spyOn(utils, 'buildTransactionMessage') // sendMessage on emailFuncs isn't called because it is disabled in getGlobalNotifications.mockReturnValue - jest.spyOn(smsFuncs, 'sendMessage').mockImplementation((_, rec) => ({ prop: rec })) - buildTransactionMessage.mockImplementation(() => ['mock message', false]) + jest.spyOn(smsFuncs, 'sendMessage').mockImplementation((_, rec) => ({prop: rec})) + buildTransactionMessage.mockImplementation(() => ["mock message", false]) - getMachineName.mockReturnValue('mockMachineName') - getCashOut.mockReturnValue({ zeroConfLimit: -Infinity }) - loadLatest.mockReturnValue(Promise.resolve({})) - getGlobalNotifications.mockReturnValue({ ...notifSettings, sms: { active: true, errors: true, transactions: true } }) + getMachineName.mockReturnValue("mockMachineName") + getCashOut.mockReturnValue({zeroConfLimit: -Infinity}) + loadLatest.mockReturnValue({}) + getGlobalNotifications.mockReturnValue({... notifSettings, sms: { active: true, errors: true, transactions: true }}) - const response = await notifier.transactionNotify(tx, { isRedemption: false }) + const response = await notifier.transactionNotify(tx, {isRedemption: false}) - // If the return object is this, it means the code went through all the functions expected to go through if + // If the return object is this, it means the code went through all the functions expected to go through if // getMachineName, buildTransactionMessage and sendTransactionMessage were called, in this order - expect(response).toEqual([{ prop: 'mock message' }]) -}) + expect(response).toEqual([{prop: 'mock message'}]) +}) \ No newline at end of file diff --git a/lib/notifier/utils.js b/lib/notifier/utils.js index 15465d7a..774712d4 100644 --- a/lib/notifier/utils.js +++ b/lib/notifier/utils.js @@ -108,8 +108,13 @@ const buildTransactionMessage = (tx, rec, highValueTx, machineName, customer) => status = !isCashOut ? 'Successful' : !rec.isRedemption +<<<<<<< HEAD ? 'Successful & awaiting redemption' : 'Successful & dispensed' +======= + ? 'Successful & awaiting redemption' + : 'Successful & dispensed' +>>>>>>> 1706b2c... Feat: save highVolumeTxs on DB and plugins code refactor } const body = ` @@ -136,6 +141,7 @@ const buildTransactionMessage = (tx, rec, highValueTx, machineName, customer) => }, highValueTx] } +<<<<<<< HEAD function formatCurrency (num, code) { return numeral(num).format('0,0.00') + ' ' + code } @@ -180,6 +186,8 @@ function getAlertTypes (alertRec, config) { return alerts } +======= +>>>>>>> 1706b2c... Feat: save highVolumeTxs on DB and plugins code refactor module.exports = { codeDisplay, parseEventNote, @@ -192,9 +200,13 @@ module.exports = { shouldNotAlert, buildAlertFingerprint, sendNoAlerts, +<<<<<<< HEAD buildTransactionMessage, formatCurrency, formatAge, buildDetail, deviceAlerts +======= + buildTransactionMessage +>>>>>>> 1706b2c... Feat: save highVolumeTxs on DB and plugins code refactor } diff --git a/lib/plugins.js b/lib/plugins.js index b86f76b5..3e13f650 100644 --- a/lib/plugins.js +++ b/lib/plugins.js @@ -25,6 +25,8 @@ const promoCodes = require('./promo-codes') const notifier = require('./notifier') +const notifier = require('./notifier/index') + const mapValuesWithKey = _.mapValues.convert({ cap: false }) @@ -55,7 +57,8 @@ function plugins (settings, deviceId) { ? undefined : BN(1).add(BN(commissions.cashOut).div(100)) - if (Date.now() - rateRec.timestamp > STALE_TICKER) return logger.warn('Stale rate for ' + cryptoCode) + if (Date.now() - rateRec.timestamp > STALE_TICKER) + return logger.warn('Stale rate for ' + cryptoCode) const rate = rateRec.rates withCommission ? rates[cryptoCode] = { @@ -89,8 +92,10 @@ function plugins (settings, deviceId) { cryptoCodes.forEach((cryptoCode, i) => { const balanceRec = balanceRecs[i] - if (!balanceRec) return logger.warn('No balance for ' + cryptoCode + ' yet') - if (Date.now() - balanceRec.timestamp > STALE_BALANCE) return logger.warn('Stale balance for ' + cryptoCode) + if (!balanceRec) + return logger.warn('No balance for ' + cryptoCode + ' yet') + if (Date.now() - balanceRec.timestamp > STALE_BALANCE) + return logger.warn('Stale balance for ' + cryptoCode) balances[cryptoCode] = balanceRec.balance }) @@ -110,10 +115,13 @@ function plugins (settings, deviceId) { const sumTxs = (sum, tx) => { const bills = tx.bills const sameDenominations = a => a[0].denomination === a[1].denomination - const doDenominationsMatch = _.every(sameDenominations, _.zip(cassettes, bills)) + const doDenominationsMatch = _.every( + sameDenominations, + _.zip(cassettes, bills) + ) if (!doDenominationsMatch) { - throw new Error('Denominations don\'t add up, cassettes were changed.') + throw new Error("Denominations don't add up, cassettes were changed.") } return _.map(r => r[0] + r[1].provisioned, _.zip(sum, tx.bills)) @@ -139,6 +147,21 @@ function plugins (settings, deviceId) { ] } +<<<<<<< HEAD +======= + function getLcmOrBigx2 (n1, n2) { + let big = Math.max(n1, n2) + let small = Math.min(n1, n2) + + let i = big * 2 + while (i % small !== 0) { + i += lar + } + + return i + } + +>>>>>>> 1706b2c... Feat: save highVolumeTxs on DB and plugins code refactor function buildAvailableCassettes (excludeTxId) { const cashOutConfig = configManager.getCashOut(deviceId, settings.config) @@ -146,6 +169,7 @@ function plugins (settings, deviceId) { const denominations = [cashOutConfig.top, cashOutConfig.bottom] +<<<<<<< HEAD const virtualCassettes = [Math.max(cashOutConfig.top, cashOutConfig.bottom) * 2] return Promise.all([dbm.cassetteCounts(deviceId), cashOutHelper.redeemableTxs(deviceId, excludeTxId)]) @@ -155,31 +179,47 @@ function plugins (settings, deviceId) { const counts = argv.cassettes ? argv.cassettes.split(',') : rec.counts +======= + const virtualCassettes = [ + getLcmOrBigx2(cashOutConfig.top, cashOutConfig.bottom) + ] +>>>>>>> 1706b2c... Feat: save highVolumeTxs on DB and plugins code refactor - const cassettes = [ - { - denomination: parseInt(denominations[0], 10), - count: parseInt(counts[0], 10) - }, - { - denomination: parseInt(denominations[1], 10), - count: parseInt(counts[1], 10) - } - ] + return Promise.all([ + dbm.cassetteCounts(deviceId), + cashOutHelper.redeemableTxs(deviceId, excludeTxId) + ]).then(([rec, _redeemableTxs]) => { + const redeemableTxs = _.reject( + _.matchesProperty('id', excludeTxId), + _redeemableTxs + ) - try { - return { - cassettes: computeAvailableCassettes(cassettes, redeemableTxs), - virtualCassettes - } - } catch (err) { - logger.error(err) - return { - cassettes, - virtualCassettes - } + const counts = argv.cassettes ? argv.cassettes.split(',') : rec.counts + + const cassettes = [ + { + denomination: parseInt(denominations[0], 10), + count: parseInt(counts[0], 10) + }, + { + denomination: parseInt(denominations[1], 10), + count: parseInt(counts[1], 10) } - }) + ] + + try { + return { + cassettes: computeAvailableCassettes(cassettes, redeemableTxs), + virtualCassettes + } + } catch (err) { + logger.error(err) + return { + cassettes, + virtualCassettes + } + } + }) } function fetchCurrentConfigVersion () { @@ -189,18 +229,23 @@ function plugins (settings, deviceId) { order by id desc limit 1` - return db.one(sql, ['config']) - .then(row => row.id) + return db.one(sql, ['config']).then(row => row.id) } function mapCoinSettings (coinParams) { const cryptoCode = coinParams[0] const cryptoNetwork = coinParams[1] - const commissions = configManager.getCommissions(cryptoCode, deviceId, settings.config) + const commissions = configManager.getCommissions( + cryptoCode, + deviceId, + settings.config + ) const minimumTx = BN(commissions.minimumTx) const cashInFee = BN(commissions.fixedFee) const cashInCommission = BN(commissions.cashIn) - const cashOutCommission = _.isNumber(commissions.cashOut) ? BN(commissions.cashOut) : null + const cashOutCommission = _.isNumber(commissions.cashOut) + ? BN(commissions.cashOut) + : null const cryptoRec = coinUtils.getCryptoCurrency(cryptoCode) return { @@ -214,15 +259,25 @@ function plugins (settings, deviceId) { } } - function pollQueries (serialNumber, deviceTime, deviceRec, machineVersion, machineModel) { + function pollQueries ( + serialNumber, + deviceTime, + deviceRec, + machineVersion, + machineModel + ) { const localeConfig = configManager.getLocale(deviceId, settings.config) const fiatCode = localeConfig.fiatCurrency const cryptoCodes = localeConfig.cryptoCurrencies - const tickerPromises = cryptoCodes.map(c => ticker.getRates(settings, fiatCode, c)) + const tickerPromises = cryptoCodes.map(c => + ticker.getRates(settings, fiatCode, c) + ) const balancePromises = cryptoCodes.map(c => fiatBalance(fiatCode, c)) - const testnetPromises = cryptoCodes.map(c => wallet.cryptoNetwork(settings, c)) + const testnetPromises = cryptoCodes.map(c => + wallet.cryptoNetwork(settings, c) + ) const pingPromise = recordPing(deviceTime, machineVersion, machineModel) const currentConfigVersionPromise = fetchCurrentConfigVersion() const currentAvailablePromoCodes = promoCodes.getNumberOfAvailablePromoCodes() @@ -233,6 +288,7 @@ function plugins (settings, deviceId) { currentConfigVersionPromise ].concat(tickerPromises, balancePromises, testnetPromises, currentAvailablePromoCodes) +<<<<<<< HEAD return Promise.all(promises) .then(arr => { const cassettes = arr[0] @@ -254,10 +310,35 @@ function plugins (settings, deviceId) { areThereAvailablePromoCodes } }) +======= + return Promise.all(promises).then(arr => { + const cassettes = arr[0] + const configVersion = arr[2] + const cryptoCodesCount = cryptoCodes.length + const tickers = arr.slice(3, cryptoCodesCount + 3) + const balances = arr.slice(cryptoCodesCount + 3, 2 * cryptoCodesCount + 3) + const testNets = arr.slice(2 * cryptoCodesCount + 3) + const coinParams = _.zip(cryptoCodes, testNets) + const coinsWithoutRate = _.map(mapCoinSettings, coinParams) + + return { + cassettes, + rates: buildRates(tickers), + balances: buildBalances(balances), + coins: _.zipWith(_.assign, coinsWithoutRate, tickers), + configVersion + } + }) +>>>>>>> 1706b2c... Feat: save highVolumeTxs on DB and plugins code refactor } function sendCoins (tx) { - return wallet.sendCoins(settings, tx.toAddress, tx.cryptoAtoms, tx.cryptoCode) + return wallet.sendCoins( + settings, + tx.toAddress, + tx.cryptoAtoms, + tx.cryptoCode + ) } function recordPing (deviceTime, version, model) { @@ -268,11 +349,18 @@ function plugins (settings, deviceId) { } return Promise.all([ - db.none(`insert into machine_pings(device_id, device_time) values($1, $2) - ON CONFLICT (device_id) DO UPDATE SET device_time = $2, updated = now()`, [deviceId, deviceTime]), - db.none(pgp.helpers.update(devices, null, 'devices') + 'WHERE device_id = ${deviceId}', { - deviceId - }) + db.none( + `insert into machine_pings(device_id, device_time) values($1, $2) + ON CONFLICT (device_id) DO UPDATE SET device_time = $2, updated = now()`, + [deviceId, deviceTime] + ), + db.none( + pgp.helpers.update(devices, null, 'devices') + + 'WHERE device_id = ${deviceId}', + { + deviceId + } + ) ]) } @@ -304,34 +392,37 @@ function plugins (settings, deviceId) { } function fiatBalance (fiatCode, cryptoCode) { - const commissions = configManager.getCommissions(cryptoCode, deviceId, settings.config) + const commissions = configManager.getCommissions( + cryptoCode, + deviceId, + settings.config + ) return Promise.all([ ticker.getRates(settings, fiatCode, cryptoCode), wallet.balance(settings, cryptoCode) - ]) - .then(([rates, balanceRec]) => { - if (!rates || !balanceRec) return null + ]).then(([rates, balanceRec]) => { + if (!rates || !balanceRec) return null - const rawRate = rates.rates.ask - const cashInCommission = BN(1).minus(BN(commissions.cashIn).div(100)) - const balance = balanceRec.balance + const rawRate = rates.rates.ask + const cashInCommission = BN(1).minus(BN(commissions.cashIn).div(100)) + const balance = balanceRec.balance - if (!rawRate || !balance) return null + if (!rawRate || !balance) return null - const rate = rawRate.div(cashInCommission) + const rate = rawRate.div(cashInCommission) - const lowBalanceMargin = BN(1.03) + const lowBalanceMargin = BN(1.03) - const cryptoRec = coinUtils.getCryptoCurrency(cryptoCode) - const unitScale = cryptoRec.unitScale - const shiftedRate = rate.shift(-unitScale) - const fiatTransferBalance = balance.mul(shiftedRate).div(lowBalanceMargin) + const cryptoRec = coinUtils.getCryptoCurrency(cryptoCode) + const unitScale = cryptoRec.unitScale + const shiftedRate = rate.shift(-unitScale) + const fiatTransferBalance = balance.mul(shiftedRate).div(lowBalanceMargin) - return { - timestamp: balanceRec.timestamp, - balance: fiatTransferBalance.truncated().toString() - } - }) + return { + timestamp: balanceRec.timestamp, + balance: fiatTransferBalance.truncated().toString() + } + }) } function notifyConfirmation (tx) { @@ -346,13 +437,12 @@ function plugins (settings, deviceId) { } } - return sms.sendMessage(settings, rec) - .then(() => { - const sql = 'update cash_out_txs set notified=$1 where id=$2' - const values = [true, tx.id] + return sms.sendMessage(settings, rec).then(() => { + const sql = 'update cash_out_txs set notified=$1 where id=$2' + const values = [true, tx.id] - return db.none(sql, values) - }) + return db.none(sql, values) + }) } function notifyOperator (tx, rec) { @@ -361,14 +451,17 @@ function plugins (settings, deviceId) { } function clearOldLogs () { - return logs.clearOldLogs() - .catch(logger.error) + return logs.clearOldLogs().catch(logger.error) } function pong () { - return db.none(`UPDATE server_events SET created=now() WHERE event_type=$1; + return db + .none( + `UPDATE server_events SET created=now() WHERE event_type=$1; INSERT INTO server_events (event_type) SELECT $1 - WHERE NOT EXISTS (SELECT 1 FROM server_events WHERE event_type=$1);`, ['ping']) + WHERE NOT EXISTS (SELECT 1 FROM server_events WHERE event_type=$1);`, + ['ping'] + ) .catch(logger.error) } @@ -409,15 +502,18 @@ function plugins (settings, deviceId) { const marketTradesQueues = tradesQueues[market] if (!marketTradesQueues || marketTradesQueues.length === 0) return null - logger.debug('[%s] tradesQueues size: %d', market, marketTradesQueues.length) + logger.debug( + '[%s] tradesQueues size: %d', + market, + marketTradesQueues.length + ) logger.debug('[%s] tradesQueues head: %j', market, marketTradesQueues[0]) const t1 = Date.now() - const filtered = marketTradesQueues - .filter(tradeEntry => { - return t1 - tradeEntry.timestamp < TRADE_TTL - }) + const filtered = marketTradesQueues.filter(tradeEntry => { + return t1 - tradeEntry.timestamp < TRADE_TTL + }) const filteredCount = marketTradesQueues.length - filtered.length @@ -428,10 +524,14 @@ function plugins (settings, deviceId) { if (filtered.length === 0) return null - const cryptoAtoms = filtered - .reduce((prev, current) => prev.plus(current.cryptoAtoms), BN(0)) + const cryptoAtoms = filtered.reduce( + (prev, current) => prev.plus(current.cryptoAtoms), + BN(0) + ) - const timestamp = filtered.map(r => r.timestamp).reduce((acc, r) => Math.max(acc, r), 0) + const timestamp = filtered + .map(r => r.timestamp) + .reduce((acc, r) => Math.max(acc, r), 0) const consolidatedTrade = { fiatCode, @@ -447,11 +547,15 @@ function plugins (settings, deviceId) { } function executeTrades () { - return machineLoader.getMachines() + return machineLoader + .getMachines() .then(devices => { const deviceIds = devices.map(device => device.deviceId) const lists = deviceIds.map(deviceId => { - const localeConfig = configManager.getLocale(deviceId, settings.config) + const localeConfig = configManager.getLocale( + deviceId, + settings.config + ) const fiatCode = localeConfig.fiatCurrency const cryptoCodes = localeConfig.cryptoCurrencies @@ -461,8 +565,9 @@ function plugins (settings, deviceId) { })) }) - const tradesPromises = _.uniq(_.flatten(lists)) - .map(r => executeTradesForMarket(settings, r.fiatCode, r.cryptoCode)) + const tradesPromises = _.uniq(_.flatten(lists)).map(r => + executeTradesForMarket(settings, r.fiatCode, r.cryptoCode) + ) return Promise.all(tradesPromises) }) @@ -477,41 +582,43 @@ function plugins (settings, deviceId) { if (tradeEntry === null || tradeEntry.cryptoAtoms.eq(0)) return - return executeTradeForType(tradeEntry) - .catch(err => { - tradesQueues[market].push(tradeEntry) - if (err.name === 'orderTooSmall') return logger.debug(err.message) - logger.error(err) - }) + return executeTradeForType(tradeEntry).catch(err => { + tradesQueues[market].push(tradeEntry) + if (err.name === 'orderTooSmall') return logger.debug(err.message) + logger.error(err) + }) } function executeTradeForType (_tradeEntry) { - const expand = te => _.assign(te, { - cryptoAtoms: te.cryptoAtoms.abs(), - type: te.cryptoAtoms.gte(0) ? 'buy' : 'sell' - }) + const expand = te => + _.assign(te, { + cryptoAtoms: te.cryptoAtoms.abs(), + type: te.cryptoAtoms.gte(0) ? 'buy' : 'sell' + }) const tradeEntry = expand(_tradeEntry) const execute = tradeEntry.type === 'buy' ? exchange.buy : exchange.sell - return execute(settings, tradeEntry.cryptoAtoms, tradeEntry.fiatCode, tradeEntry.cryptoCode) + return execute( + settings, + tradeEntry.cryptoAtoms, + tradeEntry.fiatCode, + tradeEntry.cryptoCode + ) .then(() => recordTrade(tradeEntry)) .catch(err => { - return recordTrade(tradeEntry, err) - .then(() => { - throw err - }) + return recordTrade(tradeEntry, err).then(() => { + throw err + }) }) } function convertBigNumFields (obj) { - const convert = (value, key) => _.includes(key, ['cryptoAtoms', 'fiat']) - ? value.toString() - : value + const convert = (value, key) => + _.includes(key, ['cryptoAtoms', 'fiat']) ? value.toString() : value - const convertKey = key => _.includes(key, ['cryptoAtoms', 'fiat']) - ? key + '#' - : key + const convertKey = key => + _.includes(key, ['cryptoAtoms', 'fiat']) ? key + '#' : key return _.mapKeys(convertKey, mapValuesWithKey(convert, obj)) } @@ -541,8 +648,15 @@ function plugins (settings, deviceId) { const notifications = configManager.getGlobalNotifications(settings.config) let promises = [] +<<<<<<< HEAD if (notifications.email.active && rec.email) promises.push(email.sendMessage(settings, rec)) if (notifications.sms.active && rec.sms) promises.push(sms.sendMessage(settings, rec)) +======= + if (notifications.email.active && rec.email) + promises.push(email.sendMessage(settings, rec)) + if (notifications.sms.active && rec.sms) + promises.push(sms.sendMessage(settings, rec)) +>>>>>>> 1706b2c... Feat: save highVolumeTxs on DB and plugins code refactor return Promise.all(promises) } @@ -552,53 +666,64 @@ function plugins (settings, deviceId) { } function checkDeviceCashBalances (fiatCode, device) { - const cashOutConfig = configManager.getCashOut(device.deviceId, settings.config) + const cashOutConfig = configManager.getCashOut( + device.deviceId, + settings.config + ) const denomination1 = cashOutConfig.top const denomination2 = cashOutConfig.bottom const cashOutEnabled = cashOutConfig.active - const notifications = configManager.getNotifications(null, device.deviceId, settings.config) + const notifications = configManager.getNotifications( + null, + device.deviceId, + settings.config + ) const machineName = device.name - const cashInAlert = device.cashbox > notifications.cashInAlertThreshold - ? { - code: 'CASH_BOX_FULL', - machineName, - deviceId: device.deviceId, - notes: device.cashbox - } - : null + const cashInAlert = + device.cashbox > notifications.cashInAlertThreshold + ? { + code: 'CASH_BOX_FULL', + machineName, + deviceId: device.deviceId, + notes: device.cashbox + } + : null - const cassette1Alert = cashOutEnabled && device.cassette1 < notifications.fiatBalanceCassette1 - ? { - code: 'LOW_CASH_OUT', - cassette: 1, - machineName, - deviceId: device.deviceId, - notes: device.cassette1, - denomination: denomination1, - fiatCode - } - : null + const cassette1Alert = + cashOutEnabled && device.cassette1 < notifications.fiatBalanceCassette1 + ? { + code: 'LOW_CASH_OUT', + cassette: 1, + machineName, + deviceId: device.deviceId, + notes: device.cassette1, + denomination: denomination1, + fiatCode + } + : null - const cassette2Alert = cashOutEnabled && device.cassette2 < notifications.fiatBalanceCassette2 - ? { - code: 'LOW_CASH_OUT', - cassette: 2, - machineName, - deviceId: device.deviceId, - notes: device.cassette2, - denomination: denomination2, - fiatCode - } - : null + const cassette2Alert = + cashOutEnabled && device.cassette2 < notifications.fiatBalanceCassette2 + ? { + code: 'LOW_CASH_OUT', + cassette: 2, + machineName, + deviceId: device.deviceId, + notes: device.cassette2, + denomination: denomination2, + fiatCode + } + : null return _.compact([cashInAlert, cassette1Alert, cassette2Alert]) } function checkCryptoBalances (fiatCode, devices) { - const fiatBalancePromises = cryptoCodes => _.map(c => fiatBalance(fiatCode, c), cryptoCodes) + const fiatBalancePromises = cryptoCodes => + _.map(c => fiatBalance(fiatCode, c), cryptoCodes) const fetchCryptoCodes = _deviceId => { const localeConfig = configManager.getLocale(_deviceId, settings.config) @@ -609,15 +734,20 @@ function plugins (settings, deviceId) { const cryptoCodes = union(devices) const checkCryptoBalanceWithFiat = _.partial(checkCryptoBalance, [fiatCode]) - return Promise.all(fiatBalancePromises(cryptoCodes)) - .then(balances => _.map(checkCryptoBalanceWithFiat, _.zip(cryptoCodes, balances))) + return Promise.all(fiatBalancePromises(cryptoCodes)).then(balances => + _.map(checkCryptoBalanceWithFiat, _.zip(cryptoCodes, balances)) + ) } function checkCryptoBalance (fiatCode, rec) { const [cryptoCode, fiatBalance] = rec if (!fiatBalance) return null - const notifications = configManager.getNotifications(cryptoCode, null, settings.config) + const notifications = configManager.getNotifications( + cryptoCode, + null, + settings.config + ) const lowAlertThreshold = notifications.cryptoLowBalance const highAlertThreshold = notifications.cryptoHighBalance @@ -627,11 +757,25 @@ function plugins (settings, deviceId) { fiatCode } +<<<<<<< HEAD if (_.isFinite(lowAlertThreshold) && BN(fiatBalance.balance).lt(lowAlertThreshold)) { +======= + if ( + _.isFinite(lowAlertThreshold) && + BN(fiatBalance.balance).lt(lowAlertThreshold) + ) +>>>>>>> 1706b2c... Feat: save highVolumeTxs on DB and plugins code refactor return _.set('code')('LOW_CRYPTO_BALANCE')(req) } +<<<<<<< HEAD if (_.isFinite(highAlertThreshold) && BN(fiatBalance.balance).gt(highAlertThreshold)) { +======= + if ( + _.isFinite(highAlertThreshold) && + BN(fiatBalance.balance).gt(highAlertThreshold) + ) +>>>>>>> 1706b2c... Feat: save highVolumeTxs on DB and plugins code refactor return _.set('code')('HIGH_CRYPTO_BALANCE')(req) } @@ -642,24 +786,23 @@ function plugins (settings, deviceId) { const localeConfig = configManager.getGlobalLocale(settings.config) const fiatCode = localeConfig.fiatCurrency - return machineLoader.getMachines() - .then(devices => { - return Promise.all([ - checkCryptoBalances(fiatCode, devices), - checkDevicesCashBalances(fiatCode, devices) - ]) - .then(_.flow(_.flattenDeep, _.compact)) - }) + return machineLoader.getMachines().then(devices => { + return Promise.all([ + checkCryptoBalances(fiatCode, devices), + checkDevicesCashBalances(fiatCode, devices) + ]).then(_.flow(_.flattenDeep, _.compact)) + }) } function randomCode () { - return BN(crypto.randomBytes(3).toString('hex'), 16).shift(-6).toFixed(6).slice(-6) + return BN(crypto.randomBytes(3).toString('hex'), 16) + .shift(-6) + .toFixed(6) + .slice(-6) } function getPhoneCode (phone) { - const code = argv.mockSms - ? '123' - : randomCode() + const code = argv.mockSms ? '123' : randomCode() const rec = { sms: { @@ -668,14 +811,14 @@ function plugins (settings, deviceId) { } } - return sms.sendMessage(settings, rec) - .then(() => code) + return sms.sendMessage(settings, rec).then(() => code) } function sweepHdRow (row) { const cryptoCode = row.crypto_code - return wallet.sweep(settings, cryptoCode, row.hd_index) + return wallet + .sweep(settings, cryptoCode, row.hd_index) .then(txHash => { if (txHash) { logger.debug('[%s] Swept address with tx: %s', cryptoCode, txHash) @@ -686,14 +829,17 @@ function plugins (settings, deviceId) { return db.none(sql, row.id) } }) - .catch(err => logger.error('[%s] Sweep error: %s', cryptoCode, err.message)) + .catch(err => + logger.error('[%s] Sweep error: %s', cryptoCode, err.message) + ) } function sweepHd () { const sql = `select id, crypto_code, hd_index from cash_out_txs where hd_index is not null and not swept and status in ('confirmed', 'instant')` - return db.any(sql) + return db + .any(sql) .then(rows => Promise.all(rows.map(sweepHdRow))) .catch(err => logger.error(err)) } @@ -707,14 +853,15 @@ function plugins (settings, deviceId) { const fiatCode = localeConfig.fiatCurrency const cryptoCodes = configManager.getAllCryptoCurrencies(settings.config) - const tickerPromises = cryptoCodes.map(c => ticker.getRates(settings, fiatCode, c)) + const tickerPromises = cryptoCodes.map(c => + ticker.getRates(settings, fiatCode, c) + ) return Promise.all(tickerPromises) } function getRates () { - return getRawRates() - .then(buildRates) + return getRawRates().then(buildRates) } return {