diff --git a/lib/blacklist.js b/lib/blacklist.js index 5e59107c..d6fa4f18 100644 --- a/lib/blacklist.js +++ b/lib/blacklist.js @@ -13,10 +13,11 @@ const getBlacklist = () => { // Delete row from blacklist table by crypto code and address const deleteFromBlacklist = (cryptoCode, address) => { - return db.none( - `DELETE FROM blacklist WHERE created_by_operator = 't' AND crypto_code = $1 AND address = $2`, - [cryptoCode, address] - ) + const sql = `DELETE FROM blacklist WHERE crypto_code = $1 AND address = $2; + UPDATE notifications SET valid = 'f', read = 't' WHERE valid = 't' AND detail IN ($3^)` + + const detail = `'${cryptoCode}_BLOCKED_${address}', '${cryptoCode}_REUSED_${address}'` + return db.none(sql, [cryptoCode, address, detail]) } const insertIntoBlacklist = (cryptoCode, address) => { @@ -27,12 +28,12 @@ const insertIntoBlacklist = (cryptoCode, address) => { ) } -function blocked(address, cryptoCode) { +function blocked (address, cryptoCode) { const sql = `select * from blacklist where address = $1 and crypto_code = $2` return db.any(sql, [address, cryptoCode]) } -function addToUsedAddresses(address, cryptoCode) { +function addToUsedAddresses (address, cryptoCode) { // ETH reuses addresses if (cryptoCode === 'ETH') return Promise.resolve() diff --git a/lib/cash-in/cash-in-tx.js b/lib/cash-in/cash-in-tx.js index 93d9acde..77e6276a 100644 --- a/lib/cash-in/cash-in-tx.js +++ b/lib/cash-in/cash-in-tx.js @@ -31,9 +31,9 @@ function post (machineTx, pi) { if (_.some(it => it.created_by_operator === true)(blacklistItems)) { blacklisted = true - notifier.addBlacklistNotification(r.tx, false) + notifier.blacklistNotify(r.tx, false) } else if (_.some(it => it.created_by_operator === false)(blacklistItems) && rejectAddressReuseActive) { - notifier.addBlacklistNotification(r.tx, true) + notifier.blacklistNotify(r.tx, true) addressReuse = true } return postProcess(r, pi, blacklisted, addressReuse) diff --git a/lib/customers.js b/lib/customers.js index 5c82ede0..0e3b535a 100644 --- a/lib/customers.js +++ b/lib/customers.js @@ -115,12 +115,22 @@ async function updateCustomer (id, data, userToken) { const sql = Pgp.helpers.update(updateData, _.keys(updateData), 'customers') + ' where id=$1' + invalidateCustomerNotifications(id, formattedData) await db.none(sql, [id]) return getCustomerById(id) } +const invalidateCustomerNotifications = (id, data) => { + let detail = ''; + if(data.authorized_override === 'verified') { + detail = `BLOCKED_${id}` + } + const sql = `UPDATE notifications SET valid = 'f', read = 't' WHERE valid = 't' AND detail = $1` + return db.none(sql, [detail]) +} + /** * Get customer by id * diff --git a/lib/machine-loader.js b/lib/machine-loader.js index 62351f06..e3b787f9 100644 --- a/lib/machine-loader.js +++ b/lib/machine-loader.js @@ -101,7 +101,7 @@ function renameMachine (rec) { function resetCashOutBills (rec) { const sql = ` update devices set cassette1=$1, cassette2=$2 where device_id=$3; - update notifications set read = 't', valid = 'f' where read = 'f' AND device_id = $3 AND type = 'fiatBalance'; + update notifications set read = 't', valid = 'f' where read = 'f' AND valid = 't' AND device_id = $3 AND type = 'fiatBalance'; ` return db.none(sql, [rec.cassettes[0], rec.cassettes[1], rec.deviceId]) } diff --git a/lib/notifier/index.js b/lib/notifier/index.js index 4f378288..4484d29f 100644 --- a/lib/notifier/index.js +++ b/lib/notifier/index.js @@ -225,11 +225,11 @@ const cashCassettesNotify = (cassettes, deviceId) => { Promise.all([queries.getUnreadCassetteNotifications(1, deviceId), queries.getUnreadCassetteNotifications(2, deviceId)]).then(res => { if(res[0].length === 0 && cassette1Count < cassette1Threshold) { console.log("Adding fiatBalance alert for cashbox 1 in database - count & threshold: ", cassette1Count, cassette1Threshold ) - queries.addCashCassetteWarning(1, deviceId) + return queries.addCashCassetteWarning(1, deviceId) } if(res[1].length === 0 && cassette2Count < cassette2Threshold) { console.log("Adding fiatBalance alert for cashbox 2 in database - count & threshold: ", cassette2Count, cassette2Threshold ) - queries.addCashCassetteWarning(2, deviceId) + return queries.addCashCassetteWarning(2, deviceId) } }) } @@ -269,7 +269,7 @@ const clearOldCryptoNotifications = (balances) => { return } // if the notification doesn't exist in the new balances object, then it is outdated and is not valid anymore - queries.invalidateNotification(notification.id) + return queries.invalidateNotification(notification.id) }, notifications) }) } @@ -289,7 +289,7 @@ const balancesNotify = (balances) => { } console.log("Adding high balance alert for " + warning.cryptoCode + " - " + warning.fiatBalance.balance) const balance = utils.formatCurrency(warning.fiatBalance.balance, warning.fiatCode) - queries.addCryptoBalanceWarning(`${warning.cryptoCode}_${warning.code}`, `High balance in ${warning.cryptoCode} [${balance}]`) + return queries.addCryptoBalanceWarning(`${warning.cryptoCode}_${warning.code}`, `High balance in ${warning.cryptoCode} [${balance}]`) }) }) lowWarnings.forEach(warning => { @@ -299,7 +299,7 @@ const balancesNotify = (balances) => { } console.log("Adding low balance alert for " + warning.cryptoCode + " - " + warning.fiatBalance.balance) const balance = utils.formatCurrency(warning.fiatBalance.balance, warning.fiatCode) - queries.addCryptoBalanceWarning(`${warning.cryptoCode}_${warning.code}`, `Low balance in ${warning.cryptoCode} [${balance}]`) + return queries.addCryptoBalanceWarning(`${warning.cryptoCode}_${warning.code}`, `Low balance in ${warning.cryptoCode} [${balance}]`) }) }) } @@ -314,7 +314,7 @@ const clearOldErrorNotifications = (alerts) => { return } // if the notification doesn't exist, then it is outdated and is not valid anymore - queries.invalidateNotification(notification.id) + return queries.invalidateNotification(notification.id) }, res) }) } @@ -346,7 +346,7 @@ const errorAlertsNotify = (alertRec) => { } console.log("Adding PING alert on database for " + alert.machineName) const message = `Machine down` - queries.addErrorNotification(`${PING}_${alert.age ? alert.age : '-1'}`, message, alert.deviceId) + return queries.addErrorNotification(`${PING}_${alert.age ? alert.age : '-1'}`, message, alert.deviceId) }) case STALE: return queries.getValidNotifications('error', STALE, alert.deviceId).then(res => { @@ -355,26 +355,51 @@ const errorAlertsNotify = (alertRec) => { } console.log("Adding STALE alert on database for " + alert.machineName) const message = `Machine is stuck on ${alert.state} screen` - queries.addErrorNotification(STALE, message, alert.deviceId) + return queries.addErrorNotification(STALE, message, alert.deviceId) }) default: - break + return } }, alerts) } -const addBlacklistNotification = (tx, isAddressReuse) => { +const blacklistNotify = (tx, isAddressReuse) => { let detail = '' let message = '' if(isAddressReuse) { detail = `${tx.cryptoCode}_REUSED_${tx.toAddress}` - message = `Blocked address reuse: ${tx.cryptoCode} ${tx.toAddress.substr(0,10)}...` + message = `Blocked reused address: ${tx.cryptoCode} ${tx.toAddress.substr(0,10)}...` } else { detail = `${tx.cryptoCode}_BLOCKED_${tx.toAddress}` message = `Blocked blacklisted address: ${tx.cryptoCode} ${tx.toAddress.substr(0,10)}...` } - queries.addComplianceNotification(tx.deviceId, detail, message) + return queries.addComplianceNotification(tx.deviceId, detail, message) +} + +const clearOldCustomerSuspendedNotifications = (customerId, deviceId) => { + const detail = `SUSPENDED_${customerId}` + return queries.invalidateNotification(null, detail, deviceId) +} + +const customerComplianceNotify = (customer, deviceId, prefix, days = null) => { + // prefix can be "BLOCKED", "SUSPENDED", etc + const detail = `${prefix}_${customer.id}` + const date = new Date() + if (days) { + date.setDate(date.getDate() + days) + } + const message = prefix === "SUSPENDED" ? `Customer suspended until ${date.toLocaleString()}` : `Customer blocked` + + // we have to clear every notification for this user where the suspension ended before the current date + clearOldCustomerSuspendedNotifications(customer.id, deviceId).then(() => { + return queries.getValidNotifications('compliance', detail, deviceId) + }).then(res => { + if (res.length > 0) { + return Promise.resolve() + } + return queries.addComplianceNotification(deviceId, detail, message) + }) } module.exports = { @@ -384,5 +409,6 @@ module.exports = { checkStuckScreen, sendRedemptionMessage, cashCassettesNotify, - addBlacklistNotification + blacklistNotify, + customerComplianceNotify, } diff --git a/lib/notifier/queries.js b/lib/notifier/queries.js index ad397cef..3b1fb1b6 100644 --- a/lib/notifier/queries.js +++ b/lib/notifier/queries.js @@ -55,9 +55,16 @@ const getValidNotifications = (type, detail, deviceId = null) => { return db.any(sql, [type, `%${detail}%`, deviceId]) } -const invalidateNotification = (id) => { - const sql = `UPDATE notifications SET valid = 'f', read = 't' WHERE id = $1` - return db.none(sql, [id]) +const invalidateNotification = (id, detail = null, deviceId = null) => { + let sql = '' + if(id) { + sql = `UPDATE notifications SET valid = 'f', read = 't' WHERE valid = 't' AND id = $1` + } + else { + sql = `UPDATE notifications SET valid = 'f', read = 't' WHERE valid = 't' AND detail LIKE $2` + sql = deviceId ? sql + ' AND device_id = $3' : sql + } + return db.none(sql, [id, `%${detail}%`, deviceId]) } const addComplianceNotification = (deviceId, detail, message) => { diff --git a/lib/routes.js b/lib/routes.js index 19777ebb..f604473f 100644 --- a/lib/routes.js +++ b/lib/routes.js @@ -28,6 +28,7 @@ const compliance = require('./compliance') const promoCodes = require('./promo-codes') const BN = require('./bn') const commissionMath = require('./commission-math') +const notifier = require('./notifier/index') const version = require('../package.json').version @@ -108,7 +109,6 @@ function poll (req, res, next) { operatorInfo, triggers } - // BACKWARDS_COMPATIBILITY 7.5 // machines before 7.5 expect old compliance if (!machineVersion || semver.lt(machineVersion, '7.5.0-beta.0')) { @@ -324,6 +324,7 @@ function updateCustomer (req, res, next) { } function triggerSanctions (req, res, next) { + console.log("SANCTIONS TRIGGERED") const id = req.params.id customers.getById(id) @@ -342,7 +343,10 @@ function triggerBlock (req, res, next) { const id = req.params.id customers.update(id, { authorizedOverride: 'blocked' }) - .then(customer => respond(req, res, { customer })) + .then(customer => { + notifier.customerComplianceNotify(customer, req.deviceId, 'BLOCKED') + return respond(req, res, { customer }) + }) .catch(next) } @@ -358,7 +362,10 @@ function triggerSuspend (req, res, next) { const date = new Date() date.setDate(date.getDate() + days); customers.update(id, { suspendedUntil: date }) - .then(customer => respond(req, res, { customer })) + .then(customer => { + notifier.customerComplianceNotify(customer, req.deviceId, 'SUSPENDED', days) + respond(req, res, { customer }) + }) .catch(next) } @@ -423,7 +430,6 @@ function errorHandler (err, req, res, next) { function respond (req, res, _body, _status) { const status = _status || 200 const body = _body || {} - return res.status(status).json(body) }