From 05373e83db70b5d6ef36e820a9e9a921ee1c201d Mon Sep 17 00:00:00 2001 From: Cesar <26280794+csrapr@users.noreply.github.com> Date: Thu, 21 Jan 2021 17:04:02 +0000 Subject: [PATCH] Feat: enable notify operator for OFAC matches Fix: fix lack of newline in some SVGs Chore: fix rebase issues --- lib/machine-loader.js | 3 +-- lib/notifier/index.js | 16 +++--------- lib/notifier/notificationCenter.js | 21 +++++++++++++++- lib/notifier/queries.js | 2 +- lib/notifier/test/notifier.test.js | 39 ++++++++++++------------------ lib/routes.js | 5 ++++ 6 files changed, 46 insertions(+), 40 deletions(-) diff --git a/lib/machine-loader.js b/lib/machine-loader.js index 3452440e..b449e68b 100644 --- a/lib/machine-loader.js +++ b/lib/machine-loader.js @@ -3,8 +3,7 @@ const axios = require('axios') const db = require('./db') const pairing = require('./pairing') -const checkPings = require('./notifier').checkPings -const checkStuckScreen = require('./notifier').checkStuckScreen +const { checkPings, checkStuckScreen } = require('./notifier') const dbm = require('./postgresql_interface') const configManager = require('./new-config-manager') const settingsLoader = require('./new-settings-loader') diff --git a/lib/notifier/index.js b/lib/notifier/index.js index 2e2aaf52..aa9ed492 100644 --- a/lib/notifier/index.js +++ b/lib/notifier/index.js @@ -136,8 +136,8 @@ function transactionNotify (tx, rec) { const isCashOut = tx.direction === 'cashOut' // for notification center - const directionDisplay = tx.direction === 'cashOut' ? 'cash-out' : 'cash-in' - const readyToNotify = tx.direction === 'cashIn' || (tx.direction === 'cashOut' && rec.isRedemption) + const directionDisplay = isCashOut ? 'cash-out' : 'cash-in' + const readyToNotify = !isCashOut || (tx.direction === 'cashOut' && rec.isRedemption) // awaiting for redesign. notification should not be sent if toggle in the settings table is disabled, // but currently we're sending notifications of high value tx even with the toggle disabled if (readyToNotify && !highValueTx) { @@ -204,21 +204,13 @@ function sendTransactionMessage (rec, isHighValueTx) { }) } -const notificationCenterFunctions = { - 'customerComplianceNotify': notificationCenter.customerComplianceNotify, - 'blacklistNotify': notificationCenter.blacklistNotify, - 'balancesNotify': notificationCenter.balancesNotify, - 'errorAlertsNotify': notificationCenter.errorAlertsNotify, - 'notifCenterTransactionNotify': notificationCenter.notifCenterTransactionNotify -} - // for notification center, check if type of notification is active before calling the respective notify function const notifyIfActive = (type, fnName, ...args) => { return settingsLoader.loadLatest().then(settings => { const notificationSettings = configManager.getGlobalNotifications(settings.config).notificationCenter - if (!notificationCenterFunctions[fnName]) return Promise.reject(new Error(`Notification function ${fnName} for type ${type} does not exist`)) + if (!notificationCenter[fnName]) return Promise.reject(new Error(`Notification function ${fnName} for type ${type} does not exist`)) if (!(notificationSettings.active && notificationSettings[type])) return Promise.resolve() - return notificationCenterFunctions[fnName](...args) + return notificationCenter[fnName](...args) }) } diff --git a/lib/notifier/notificationCenter.js b/lib/notifier/notificationCenter.js index e9eae580..d0488269 100644 --- a/lib/notifier/notificationCenter.js +++ b/lib/notifier/notificationCenter.js @@ -3,6 +3,7 @@ const _ = require('lodash/fp') const queries = require('./queries') const utils = require('./utils') const codes = require('./codes') +const customers = require('../customers') const { NOTIFICATION_TYPES: { COMPLIANCE, @@ -15,6 +16,17 @@ const { NOTIFICATION_TYPES: { const { STALE, PING } = codes +const sanctionsNotify = (customer, phone) => { + const code = 'SANCTIONS' + const detailB = utils.buildDetail({ customerId: customer.id, code }) + + // if it's a new customer then phone comes as undefined + if (phone) { + return queries.addNotification(COMPLIANCE, `Blocked customer with phone ${phone} for being on the OFAC sanctions list`, detailB) + } + return customers.getById(customer.id).then(c => queries.addNotification(COMPLIANCE, `Blocked customer with phone ${c.phone} for being on the OFAC sanctions list`, detailB)) +} + const clearOldCustomerSuspendedNotifications = (customerId, deviceId) => { const detailB = utils.buildDetail({ code: 'SUSPENDED', customerId, deviceId }) return queries.invalidateNotification(detailB, 'compliance') @@ -167,4 +179,11 @@ const blacklistNotify = (tx, isAddressReuse) => { return queries.addNotification(COMPLIANCE, message, detailB) } -module.exports = { customerComplianceNotify, balancesNotify, errorAlertsNotify, notifCenterTransactionNotify, blacklistNotify } +module.exports = { + sanctionsNotify, + customerComplianceNotify, + balancesNotify, + errorAlertsNotify, + notifCenterTransactionNotify, + blacklistNotify +} diff --git a/lib/notifier/queries.js b/lib/notifier/queries.js index c6ae67fb..f10c4547 100644 --- a/lib/notifier/queries.js +++ b/lib/notifier/queries.js @@ -21,7 +21,7 @@ function getMachineName (machineId) { } const addNotification = (type, message, detail) => { - const sql = `INSERT INTO notifications (id, type, message, detail) values ($1, $2, $3, $4)` + const sql = `INSERT INTO notifications (id, type, message, detail) VALUES ($1, $2, $3, $4)` return db.oneOrNone(sql, [uuidv4(), type, message, detail]) } diff --git a/lib/notifier/test/notifier.test.js b/lib/notifier/test/notifier.test.js index 47068779..797a1e77 100644 --- a/lib/notifier/test/notifier.test.js +++ b/lib/notifier/test/notifier.test.js @@ -2,8 +2,6 @@ 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(() => { @@ -83,16 +81,16 @@ 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 } } @@ -152,7 +150,6 @@ test('Checkpings returns empty array as the value for the id prop, if the lastPi }) }) - test('Check notification resolves to undefined if shouldNotAlert is called and is true', async () => { const mockShouldNotAlert = jest.spyOn(utils, 'shouldNotAlert') mockShouldNotAlert.mockReturnValue(true) @@ -280,29 +277,23 @@ test('checkStuckScreen returns empty array if age < STALE_STATE', () => { expect(result2).toEqual([]) }) -test("calls sendRedemptionMessage if !zeroConf and rec.isRedemption", async () => { +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) -<<<<<<< HEAD - getCashOut.mockReturnValue({zeroConfLimit: -Infinity}) - loadLatest.mockReturnValue({}) - getGlobalNotifications.mockReturnValue({... notifSettings, sms: { active: true, errors: true, transactions: true }}) -======= getCashOut.mockReturnValue({ zeroConfLimit: -Infinity }) loadLatest.mockReturnValue(Promise.resolve({})) - getGlobalNotifications.mockReturnValue({ ...notifSettings, sms: { active: true, errors: true, transactions: true }, notificationCenter: { active: true } }) ->>>>>>> a7a9fd3... Feat: move notif center fns to own file on the notifier module + getGlobalNotifications.mockReturnValue({ ...notifSettings, sms: { active: true, errors: true, transactions: true }, notificationCenter: { active: true } }) + + const response = await notifier.transactionNotify(tx, { isRedemption: true }) - const response = await notifier.transactionNotify(tx, {isRedemption: true}) - // this type of response implies sendRedemptionMessage was called expect(response[0]).toMatchObject({ sms: { @@ -315,29 +306,29 @@ test("calls sendRedemptionMessage if !zeroConf and rec.isRedemption", async () = }) }) -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 }, notificationCenter: { active: 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'}]) -}) \ No newline at end of file +}) diff --git a/lib/routes.js b/lib/routes.js index 3b454a95..fcf8ee4d 100644 --- a/lib/routes.js +++ b/lib/routes.js @@ -429,6 +429,11 @@ function errorHandler (err, req, res, next) { function respond (req, res, _body, _status) { const status = _status || 200 const body = _body || {} + const customer = _.getOr({ sanctions: true }, ['customer'], body) + // sanctions can be null for new customers so we can't use falsy checks + if (customer.sanctions === false) { + notifier.notifyIfActive('compliance', 'sanctionsNotify', customer, req.body.phone).catch(console.error) + } return res.status(status).json(body) }