diff --git a/lib/cash-out/cash-out-atomic.js b/lib/cash-out/cash-out-atomic.js index ea65402f..5c74852a 100644 --- a/lib/cash-out/cash-out-atomic.js +++ b/lib/cash-out/cash-out-atomic.js @@ -125,7 +125,6 @@ function updateCassettes (t, tx) { ] return t.one(sql, values).then(r => { - notifier.cashCassettesNotify(r, tx.deviceId) return socket.emit(_.assign(r, {op: 'cassetteUpdate', deviceId: tx.deviceId})) }) } diff --git a/lib/notifier/index.js b/lib/notifier/index.js index e53128df..ce4af396 100644 --- a/lib/notifier/index.js +++ b/lib/notifier/index.js @@ -361,12 +361,12 @@ const clearOldCryptoNotifications = (balances) => { // first, for each DB notification, if it doesn't exist in balances then it is old and should not be valid anymore // if it exists in balances, add the index of it in balances to the array of duplicates // return the array of duplicates so that balancesNotify doesn't add them - return queries.getAllValidNotifications('cryptoBalance').then(res => { + return queries.getAllValidNotifications(CRYPTO_BALANCE).then(res => { const notifications = _.map(it => { return { id: it.id, - cryptoCode: it.detail.split('_')[0], - code: it.detail.split('_').splice(1).join('_') + cryptoCode: it.detail.cryptoCode, + code: it.detail.code } }, res) const duplicateIndexes = [] @@ -398,18 +398,19 @@ const cryptoBalancesNotify = (cryptoWarnings) => { const fiat = utils.formatCurrency(balance.fiatBalance.balance, balance.fiatCode) const message = `${balance.code === 'HIGH_CRYPTO_BALANCE' ? 'High' : 'Low'} balance in ${balance.cryptoCode} [${fiat}]` console.log(`Adding ${balance.code === 'HIGH_CRYPTO_BALANCE' ? 'high' : 'low'} balance notification for ${balance.cryptoCode}`) - return queries.addCryptoBalanceWarning(`${balance.cryptoCode}_${balance.code}`, message) + const detailB = utils.buildDetail({cryptoCode: balance.cryptoCode, code: balance.code}) + return queries.addNotification(CRYPTO_BALANCE, message, detailB) }) }) } const clearOldFiatNotifications = (balances) => { - return queries.getAllValidNotifications('fiatBalance').then(notifications => { + return queries.getAllValidNotifications(FIAT_BALANCE).then(notifications => { const duplicateIndexes = [] const idsToInvalidate = [] _.forEach(notification => { const idx = _.findIndex(balance => { - return notification.device_id === balance.deviceId && notification.detail === `${balance.cassette}` + return notification.detail.deviceId === balance.deviceId && notification.detail.cassette === balance.cassette }, balances) if (idx === -1) { @@ -433,7 +434,8 @@ const fiatBalancesNotify = (fiatWarnings) => { } console.log(`Adding low cash balance notification for cassette ${balance.cassette} at ${balance.machineName}`) const message = `Cash-out cassette ${balance.cassette} almost empty!` - return queries.addCashCassetteWarning(balance.cassette, balance.deviceId, message) + const detailB = utils.buildDetail({deviceId: balance.deviceId, cassette: balance.cassette}) + return queries.addNotification(FIAT_BALANCE, message, detailB) }) }) } @@ -446,19 +448,22 @@ const balancesNotify = (balances) => { return Promise.all([cryptoBalancesNotify(cryptoWarnings), fiatBalancesNotify(fiatWarnings)]).catch(console.error) } + const clearOldErrorNotifications = (alerts) => { - queries.getAllValidNotifications('error').then(res => { + return queries.getAllValidNotifications(ERROR).then(res => { + const indexesToInvalidate = [] _.forEach(notification => { const idx = _.findIndex(alert => { - return alert.code === notification.detail.split('_')[0] && alert.deviceId === notification.device_id + return alert.code === notification.detail.code && alert.deviceId === notification.detail.deviceId }, alerts) if(idx !== -1) { return } // if the notification doesn't exist, then it is outdated and is not valid anymore - return queries.invalidateNotification(notification.id) + indexesToInvalidate.push(notification.id) }, res) - }) + return indexesToInvalidate.length > 0 ? queries.batchInvalidate(indexesToInvalidate) : null + }).catch(console.log) } const errorAlertsNotify = (alertRec) => { @@ -477,71 +482,79 @@ const errorAlertsNotify = (alertRec) => { // that alert should be considered invalid // after that, for the alerts array, we have to see if there is a valid alert of // the sorts already on the DB - clearOldErrorNotifications(alerts) - - _.forEach(alert => { - switch(alert.code) { - case PING: - return queries.getValidNotifications('error', PING, alert.deviceId).then(res => { - if(res.length > 0) { - return Promise.resolve() - } - console.log("Adding PING alert on database for " + alert.machineName) - const message = `Machine down` - return queries.addErrorNotification(`${PING}_${alert.age ? alert.age : '-1'}`, message, alert.deviceId) - }) - case STALE: - return queries.getValidNotifications('error', STALE, alert.deviceId).then(res => { - if(res.length > 0) { - return Promise.resolve() - } - console.log("Adding STALE alert on database for " + alert.machineName) - const message = `Machine is stuck on ${alert.state} screen` - return queries.addErrorNotification(STALE, message, alert.deviceId) - }) - default: - return - } - }, alerts) + return clearOldErrorNotifications(alerts).then(() => { + _.forEach(alert => { + switch(alert.code) { + case PING: { + const detailB = utils.buildDetail({code: PING, age: alert.age ? alert.age : -1, deviceId: alert.deviceId}) + return queries.getValidNotifications(ERROR, _.omit(['age'], detailB)).then(res => { + if(res.length > 0) { + return Promise.resolve() + } + console.log("Adding PING alert on database for " + alert.machineName) + const message = `Machine down` + return queries.addNotification(ERROR, message, detailB) + }) + } + case STALE: { + const detailB = utils.buildDetail({code: STALE, deviceId: alert.deviceId}) + return queries.getValidNotifications(ERROR, detailB).then(res => { + if(res.length > 0) { + return Promise.resolve() + } + console.log("Adding STALE alert on database for " + alert.machineName) + const message = `Machine is stuck on ${alert.state} screen` + return queries.addNotification(ERROR, message, detailB) + }) + } + default: + return + } + }, alerts) + }).catch(console.error) } const blacklistNotify = (tx, isAddressReuse) => { - let detail = '' let message = '' + let detailB = {} if(isAddressReuse) { detail = `${tx.cryptoCode}_REUSED_${tx.toAddress}` + detailB = utils.buildDetail({cryptoCode: tx.cryptoCode, code: 'REUSED', cryptoAddress: tx.toAddress}) message = `Blocked reused address: ${tx.cryptoCode} ${tx.toAddress.substr(0,10)}...` } else { detail = `${tx.cryptoCode}_BLOCKED_${tx.toAddress}` + detailB = utils.buildDetail({cryptoCode: tx.cryptoCode, code: 'BLOCKED', cryptoAddress: tx.toAddress}) message = `Blocked blacklisted address: ${tx.cryptoCode} ${tx.toAddress.substr(0,10)}...` } + return queries.addNotification(COMPLIANCE, message, detailB) +} - return queries.addComplianceNotification(tx.deviceId, detail, message) +const clearBlacklistNotification = (cryptoCode, cryptoAddress) => { + return queries.clearBlacklistNotification(cryptoCode, cryptoAddress).catch(console.error) } const clearOldCustomerSuspendedNotifications = (customerId, deviceId) => { - const detail = `SUSPENDED_${customerId}` - return queries.invalidateNotification(null, detail, deviceId) + const detailB = utils.buildDetail({code: 'SUSPENDED', customerId, deviceId}) + return queries.invalidateNotification(detailB, 'compliance') } -const customerComplianceNotify = (customer, deviceId, prefix, days = null) => { - // prefix can be "BLOCKED", "SUSPENDED", etc - const detail = `${prefix}_${customer.id}` +const customerComplianceNotify = (customer, deviceId, code, days = null) => { + // code for now can be "BLOCKED", "SUSPENDED" + const detailB = utils.buildDetail({customerId: customer.id, code, deviceId}) const date = new Date() if (days) { date.setDate(date.getDate() + days) } - const message = prefix === "SUSPENDED" ? `Customer suspended until ${date.toLocaleString()}` : `Customer blocked` + const message = code === "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) + return clearOldCustomerSuspendedNotifications(customer.id, deviceId).then(() => { + return queries.getValidNotifications(COMPLIANCE, detailB) }).then(res => { if (res.length > 0) { return Promise.resolve() } - return queries.addComplianceNotification(deviceId, detail, message) - }) + return queries.addNotification(COMPLIANCE, message, detailB) + }).catch(console.error) } module.exports = { diff --git a/lib/notifier/queries.js b/lib/notifier/queries.js index a8380491..45fe71d1 100644 --- a/lib/notifier/queries.js +++ b/lib/notifier/queries.js @@ -77,6 +77,16 @@ const batchInvalidate = (ids) => { return db.none(sql, [formattedIds]) } +const clearBlacklistNotification = (cryptoCode, cryptoAddress) => { + const sql = `UPDATE notifications SET valid = 'f', read = 't' WHERE type = 'compliance' AND detail->>'cryptoCode' = $1 AND detail->>'cryptoAddress' = $2 AND (detail->>'code' = 'BLOCKED' OR detail->>'code' = 'REUSED')` + return db.none(sql, [cryptoCode, cryptoAddress]) +} + +const getValidNotifications = (type, detail) => { + const sql = `SELECT * FROM notifications where type = $1 AND valid = 't' AND detail @> $2` + return db.any(sql, [type, detail]) +} + module.exports = { machineEvents: dbm.machineEvents, addNotification,