Some checks failed
/ build (map[dockerfile:./services/api/Dockerfile name:api]) (push) Successful in 1m28s
/ build (map[dockerfile:./services/app/Dockerfile name:app]) (push) Successful in 1m45s
/ build (map[dockerfile:./services/files/Dockerfile name:files]) (push) Successful in 1m55s
/ build (map[dockerfile:./services/watchers/Dockerfile name:watchers]) (push) Successful in 2m10s
/ build (map[dockerfile:./services/tasks/Dockerfile name:tasks]) (push) Successful in 2m18s
/ build (map[dockerfile:./services/hasura/Dockerfile name:hasura]) (push) Successful in 2m20s
/ build (map[dockerfile:./services/web/Dockerfile name:web]) (push) Failing after 12m45s
/ deploy (push) Has been cancelled
250 lines
6.8 KiB
JavaScript
250 lines
6.8 KiB
JavaScript
const async = require("async")
|
|
const { ctx } = require("@modjo/core")
|
|
const { taskCtx } = require("@modjo/microservice-worker/ctx")
|
|
|
|
const humanizeDistance = require("utils/geo/humanizeDistance")
|
|
const addNotification = require("~/services/add-notification")
|
|
const {
|
|
getAlertNotificationExpirationInSeconds,
|
|
ALERT_NOTIFICATION_EXPIRATION_INTERVAL,
|
|
} = require("~/constants/time")
|
|
const {
|
|
LEVEL_COLORS,
|
|
LEVEL_DESCRIPTIONS,
|
|
} = require("~/constants/notifications")
|
|
|
|
const MAX_PARALLEL_PUSHES = 10
|
|
|
|
function createAlertNotification({
|
|
code,
|
|
reason,
|
|
level,
|
|
alertId,
|
|
alertingId,
|
|
initialDistance,
|
|
}) {
|
|
const baseText =
|
|
reason === "relative"
|
|
? "Un de vos proches a besoin d'aide"
|
|
: "Besoin d'aide"
|
|
const levelText = LEVEL_DESCRIPTIONS[level] || LEVEL_DESCRIPTIONS.green
|
|
const distanceText = initialDistance
|
|
? ` à ${humanizeDistance(initialDistance)}`
|
|
: ""
|
|
const notificationText = `${baseText} - ${levelText}${distanceText}`
|
|
const color = LEVEL_COLORS[level] || LEVEL_COLORS.green
|
|
const expires = getAlertNotificationExpirationInSeconds()
|
|
|
|
return {
|
|
data: {
|
|
action: "alert",
|
|
alertingId,
|
|
alertId,
|
|
level,
|
|
expires,
|
|
code,
|
|
initialDistance,
|
|
reason,
|
|
},
|
|
notification: {
|
|
title: `Nouvelle Alerte - #${code}`,
|
|
body: notificationText,
|
|
channel: "alert",
|
|
icon: `notif-${level}`,
|
|
priority: "high",
|
|
ttl: ALERT_NOTIFICATION_EXPIRATION_INTERVAL,
|
|
color,
|
|
actionId: "open-alert",
|
|
},
|
|
}
|
|
}
|
|
|
|
const numericLevel = {
|
|
green: 1,
|
|
yellow: 2,
|
|
red: 3,
|
|
}
|
|
|
|
module.exports = async function () {
|
|
async function setNotificationSent(alertingId, state) {
|
|
const sql = ctx.require("postgres")
|
|
const logger = taskCtx.require("logger")
|
|
|
|
logger.debug({ alertingId, state }, "Setting notification sent state")
|
|
|
|
if (state === false) {
|
|
logger.debug(
|
|
{ alertingId },
|
|
"Updating alerting record to mark notification_sent as FALSE"
|
|
)
|
|
await sql`
|
|
UPDATE
|
|
"alerting"
|
|
SET
|
|
"notification_sent" = FALSE
|
|
WHERE
|
|
"id" = ${alertingId}
|
|
`
|
|
} else {
|
|
logger.debug(
|
|
{ alertingId },
|
|
"Updating alerting record to mark notification_sent as TRUE with current timestamp"
|
|
)
|
|
await sql`
|
|
UPDATE
|
|
"alerting"
|
|
SET
|
|
"notification_sent" = TRUE,
|
|
"notification_sent_at" = NOW()
|
|
WHERE
|
|
"id" = ${alertingId}
|
|
`
|
|
}
|
|
logger.debug({ alertingId }, "Successfully updated notification sent state")
|
|
}
|
|
|
|
return Object.assign(
|
|
async function alertNotify(params) {
|
|
const logger = taskCtx.require("logger")
|
|
logger.info({ params }, "Starting alertNotify process")
|
|
|
|
const sql = ctx.require("postgres")
|
|
const { alertingId } = params
|
|
|
|
logger.debug({ alertingId }, "Querying alerting record")
|
|
const [alertingRow] = await sql`
|
|
SELECT
|
|
"alerting"."device_id" as "deviceId",
|
|
"alerting"."alert_id" as "alertId",
|
|
"alerting"."user_id" as "userId",
|
|
"alerting"."reason" as "reason",
|
|
"alerting"."initial_distance" as "initialDistance"
|
|
FROM
|
|
"alerting"
|
|
WHERE
|
|
"alerting"."id" = ${alertingId}
|
|
AND "alerting"."notification_sent" IS NULL
|
|
`
|
|
|
|
if (!alertingRow) {
|
|
logger.info({ alertingId }, "No alerting record found, exiting process")
|
|
return
|
|
}
|
|
|
|
const { reason, alertId, userId: alertingUserId } = alertingRow
|
|
logger.debug({ reason, alertId, alertingUserId }, "Found alerting record")
|
|
|
|
const devicesList = await sql`
|
|
SELECT
|
|
"id",
|
|
"fcm_token" as "fcmToken",
|
|
"notification_alert_level" as "notificationAlertLevel"
|
|
FROM
|
|
"device"
|
|
WHERE
|
|
"user_id" = ${alertingUserId}
|
|
AND "fcm_token" IS NOT NULL
|
|
`
|
|
const devices = devicesList.map((device) => ({ ...device }))
|
|
|
|
logger.debug({ alertId }, "Querying alert record")
|
|
const [{ userId: alertUserId, level, code }] = await sql`
|
|
SELECT
|
|
"alert"."level" as "level",
|
|
"alert"."user_id" as "userId",
|
|
"alert"."code" as "code"
|
|
FROM
|
|
"alert"
|
|
WHERE
|
|
"alert"."id" = ${alertId}
|
|
`
|
|
|
|
let sentOnce = false
|
|
|
|
await async.allLimit(devices, MAX_PARALLEL_PUSHES, async (device) => {
|
|
const { id: deviceId, fcmToken } = device
|
|
const notificationAlertLevel = device.notificationAlertLevel || "green"
|
|
logger.debug(
|
|
{ deviceId, notificationAlertLevel },
|
|
"Found device record"
|
|
)
|
|
|
|
if (alertUserId === alertingUserId) {
|
|
logger.info(
|
|
{ alertUserId, alertingUserId },
|
|
"Alert creator matches alerting user, skipping notification"
|
|
)
|
|
await setNotificationSent(alertingId, false)
|
|
// user doesn't receive it's own alerts notifications
|
|
// disable/comment return for dev/debug
|
|
return
|
|
}
|
|
|
|
const acceptLevel =
|
|
numericLevel[level] >= numericLevel[notificationAlertLevel]
|
|
|
|
logger.debug(
|
|
{ level, notificationAlertLevel, acceptLevel },
|
|
"Checking alert level threshold"
|
|
)
|
|
|
|
if (!acceptLevel) {
|
|
logger.info(
|
|
{ level, notificationAlertLevel },
|
|
"Alert level below device threshold, skipping notification"
|
|
)
|
|
await setNotificationSent(alertingId, false)
|
|
return
|
|
}
|
|
|
|
try {
|
|
logger.debug({ deviceId }, "Attempting to send push notification")
|
|
const notificationConfig = createAlertNotification({
|
|
code,
|
|
reason,
|
|
level,
|
|
alertId,
|
|
alertingId,
|
|
initialDistance: alertingRow.initialDistance,
|
|
})
|
|
|
|
const { messageId, success } = await addNotification({
|
|
fcmToken,
|
|
deviceId,
|
|
...notificationConfig,
|
|
userId: alertingUserId,
|
|
type: "alert",
|
|
})
|
|
|
|
if (!success) {
|
|
logger.error(
|
|
{ deviceId, alertingId },
|
|
"Failed to send push notification"
|
|
)
|
|
return
|
|
}
|
|
logger.info(
|
|
{ messageId, alertingId },
|
|
"Successfully sent push notification"
|
|
)
|
|
sentOnce = true
|
|
} catch (e) {
|
|
logger.error(
|
|
{ error: e, deviceId, alertingId },
|
|
"Failed to send push notification"
|
|
)
|
|
console.error(e)
|
|
}
|
|
})
|
|
|
|
logger.info(
|
|
{ alertingId, sentOnce },
|
|
"Setting final notification sent state"
|
|
)
|
|
await setNotificationSent(alertingId, sentOnce)
|
|
},
|
|
{
|
|
dedupOptions: { enabled: true },
|
|
}
|
|
)
|
|
}
|