Feat: move notif center fns to own file on the notifier module

Fix: fix jest test
This commit is contained in:
Cesar 2021-01-20 14:37:34 +00:00 committed by Josh Harvey
parent 34f2b84fe2
commit 69d3e4cb9b
6 changed files with 204 additions and 190 deletions

View file

@ -6,20 +6,11 @@ const queries = require('./queries')
const settingsLoader = require('../new-settings-loader')
const customers = require('../customers')
const notificationCenter = require('./notificationCenter')
const utils = require('./utils')
const emailFuncs = require('./email')
const smsFuncs = require('./sms')
const codes = require('./codes')
const { STALE, STALE_STATE, PING } = require('./codes')
const { NOTIFICATION_TYPES: {
HIGH_VALUE_TX,
NORMAL_VALUE_TX,
FIAT_BALANCE,
CRYPTO_BALANCE,
COMPLIANCE,
ERROR }
} = codes
const { STALE, STALE_STATE } = require('./codes')
function buildMessage (alerts, notifications) {
const smsEnabled = utils.isActive(notifications.sms)
@ -52,7 +43,7 @@ function checkNotification (plugins) {
return getAlerts(plugins)
.then(alerts => {
notifyIfActive('errors', alerts).catch(console.error)
notifyIfActive('errors', 'errorAlertsNotify', alerts).catch(console.error)
const currentAlertFingerprint = utils.buildAlertFingerprint(
alerts,
notifications
@ -83,7 +74,7 @@ function getAlerts (plugins) {
queries.machineEvents(),
plugins.getMachineNames()
]).then(([balances, events, devices]) => {
notifyIfActive('balance', balances).catch(console.error)
notifyIfActive('balance', 'balancesNotify', balances).catch(console.error)
return buildAlerts(checkPings(devices), balances, events, devices)
})
}
@ -138,13 +129,6 @@ function checkStuckScreen (deviceEvents, machineName) {
return []
}
function notifCenterTransactionNotify (isHighValue, direction, fiat, fiatCode, deviceId, cryptoAddress) {
const messageSuffix = isHighValue ? 'High value' : ''
const message = `${messageSuffix} ${fiat} ${fiatCode} ${direction} transaction`
const detailB = utils.buildDetail({ deviceId: deviceId, direction, fiat, fiatCode, cryptoAddress })
return queries.addNotification(isHighValue ? HIGH_VALUE_TX : NORMAL_VALUE_TX, message, detailB)
}
function transactionNotify (tx, rec) {
return settingsLoader.loadLatest().then(settings => {
const notifSettings = configManager.getGlobalNotifications(settings.config)
@ -154,8 +138,12 @@ function transactionNotify (tx, rec) {
// for notification center
const directionDisplay = tx.direction === 'cashOut' ? 'cash-out' : 'cash-in'
const readyToNotify = tx.direction === 'cashIn' || (tx.direction === 'cashOut' && rec.isRedemption)
if (readyToNotify) {
notifyIfActive('transactions', highValueTx, directionDisplay, tx.fiat, tx.fiatCode, tx.deviceId, tx.toAddress).catch(console.error)
// 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) {
notifyIfActive('transactions', 'notifCenterTransactionNotify', highValueTx, directionDisplay, tx.fiat, tx.fiatCode, tx.deviceId, tx.toAddress).catch(console.error)
} else if (readyToNotify && highValueTx) {
notificationCenter.notifCenterTransactionNotify(highValueTx, directionDisplay, tx.fiat, tx.fiatCode, tx.deviceId, tx.toAddress).catch(console.error)
}
// alert through sms or email any transaction or high value transaction, if SMS || email alerts are enabled
@ -216,169 +204,21 @@ function sendTransactionMessage (rec, isHighValueTx) {
})
}
const clearOldCryptoNotifications = balances => {
return queries.getAllValidNotifications(CRYPTO_BALANCE).then(res => {
const filterByBalance = _.filter(notification => {
const { cryptoCode, code } = notification.detail
return !_.find(balance => balance.cryptoCode === cryptoCode && balance.code === code)(balances)
})
const indexesToInvalidate = _.compose(_.map('id'), filterByBalance)(res)
const notInvalidated = _.filter(notification => {
return !_.find(id => notification.id === id)(indexesToInvalidate)
}, res)
return (indexesToInvalidate.length ? queries.batchInvalidate(indexesToInvalidate) : Promise.resolve()).then(() => notInvalidated)
})
}
const cryptoBalancesNotify = (cryptoWarnings) => {
return clearOldCryptoNotifications(cryptoWarnings).then(notInvalidated => {
return cryptoWarnings.forEach(balance => {
// if notification exists in DB and wasnt invalidated then don't add a duplicate
if (_.find(o => {
const { code, cryptoCode } = o.detail
return code === balance.code && cryptoCode === balance.cryptoCode
}, notInvalidated)) return
const fiat = utils.formatCurrency(balance.fiatBalance.balance, balance.fiatCode)
const message = `${balance.code === 'HIGH_CRYPTO_BALANCE' ? 'High' : 'Low'} balance in ${balance.cryptoCode} [${fiat}]`
const detailB = utils.buildDetail({ cryptoCode: balance.cryptoCode, code: balance.code })
return queries.addNotification(CRYPTO_BALANCE, message, detailB)
})
})
}
const clearOldFiatNotifications = (balances) => {
return queries.getAllValidNotifications(FIAT_BALANCE).then(notifications => {
const filterByBalance = _.filter(notification => {
const { cassette, deviceId } = notification.detail
return !_.find(balance => balance.cassette === cassette && balance.deviceId === deviceId)(balances)
})
const indexesToInvalidate = _.compose(_.map('id'), filterByBalance)(notifications)
const notInvalidated = _.filter(notification => {
return !_.find(id => notification.id === id)(indexesToInvalidate)
}, notifications)
return (indexesToInvalidate.length ? queries.batchInvalidate(indexesToInvalidate) : Promise.resolve()).then(() => notInvalidated)
})
}
const fiatBalancesNotify = (fiatWarnings) => {
return clearOldFiatNotifications(fiatWarnings).then(notInvalidated => {
return fiatWarnings.forEach(balance => {
if (_.find(o => {
const { cassette, deviceId } = o.detail
return cassette === balance.cassette && deviceId === balance.deviceId
}, notInvalidated)) return
const message = `Cash-out cassette ${balance.cassette} almost empty!`
const detailB = utils.buildDetail({ deviceId: balance.deviceId, cassette: balance.cassette })
return queries.addNotification(FIAT_BALANCE, message, detailB)
})
})
}
const balancesNotify = (balances) => {
const cryptoFilter = o => o.code === 'HIGH_CRYPTO_BALANCE' || o.code === 'LOW_CRYPTO_BALANCE'
const fiatFilter = o => o.code === 'LOW_CASH_OUT'
const cryptoWarnings = _.filter(cryptoFilter, balances)
const fiatWarnings = _.filter(fiatFilter, balances)
return Promise.all([cryptoBalancesNotify(cryptoWarnings), fiatBalancesNotify(fiatWarnings)]).catch(console.error)
}
const clearOldErrorNotifications = alerts => {
return queries.getAllValidNotifications(ERROR)
.then(res => {
// for each valid notification in DB see if it exists in alerts
// if the notification doesn't exist in alerts, it is not valid anymore
const filterByAlert = _.filter(notification => {
const { code, deviceId } = notification.detail
return !_.find(alert => alert.code === code && alert.deviceId === deviceId)(alerts)
})
const indexesToInvalidate = _.compose(_.map('id'), filterByAlert)(res)
if (!indexesToInvalidate.length) return Promise.resolve()
return queries.batchInvalidate(indexesToInvalidate)
})
.catch(console.error)
}
const errorAlertsNotify = (alertRec) => {
const embedDeviceId = deviceId => _.assign({ deviceId })
const mapToAlerts = _.map(it => _.map(embedDeviceId(it), alertRec.devices[it].deviceAlerts))
const alerts = _.compose(_.flatten, mapToAlerts, _.keys)(alertRec.devices)
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()
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()
const message = `Machine is stuck on ${alert.state} screen`
return queries.addNotification(ERROR, message, detailB)
})
}
}
}, alerts)
}).catch(console.error)
}
const blacklistNotify = (tx, isAddressReuse) => {
const code = isAddressReuse ? 'REUSED' : 'BLOCKED'
const name = isAddressReuse ? 'reused' : 'blacklisted'
const detailB = utils.buildDetail({ cryptoCode: tx.cryptoCode, code, cryptoAddress: tx.toAddress })
const message = `Blocked ${name} address: ${tx.cryptoCode} ${tx.toAddress.substr(0, 10)}...`
return queries.addNotification(COMPLIANCE, message, detailB)
}
const clearBlacklistNotification = (cryptoCode, cryptoAddress) => {
return queries.clearBlacklistNotification(cryptoCode, cryptoAddress).catch(console.error)
}
const clearOldCustomerSuspendedNotifications = (customerId, deviceId) => {
const detailB = utils.buildDetail({ code: 'SUSPENDED', customerId, deviceId })
return queries.invalidateNotification(detailB, 'compliance')
}
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 = code === 'SUSPENDED' ? `Customer suspended until ${date.toLocaleString()}` : `Customer blocked`
return clearOldCustomerSuspendedNotifications(customer.id, deviceId)
.then(() => queries.getValidNotifications(COMPLIANCE, detailB))
.then(res => {
if (res.length > 0) return Promise.resolve()
return queries.addNotification(COMPLIANCE, message, detailB)
})
.catch(console.error)
}
const notificationCenterFunctions = {
'compliance': customerComplianceNotify,
'balance': balancesNotify,
'errors': errorAlertsNotify,
'transactions': notifCenterTransactionNotify
'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, ...args) => {
const notifyIfActive = (type, fnName, ...args) => {
return settingsLoader.loadLatest().then(settings => {
const notificationSettings = configManager.getGlobalNotifications(settings.config).notificationCenter
if (!notificationCenterFunctions[type]) return Promise.reject(new Error(`Notification of type ${type} does not exist`))
if (!notificationCenterFunctions[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[type](...args)
return notificationCenterFunctions[fnName](...args)
})
}
@ -388,7 +228,5 @@ module.exports = {
checkPings,
checkStuckScreen,
sendRedemptionMessage,
blacklistNotify,
clearBlacklistNotification,
notifyIfActive
}