From 227b53cd39ccac6e8c3f5b65311a4e72d01b6cf4 Mon Sep 17 00:00:00 2001 From: devthejo Date: Sun, 1 Jun 2025 09:58:01 +0200 Subject: [PATCH] feat(follow-location): alert-geosync --- libs/common/oapi/services/alert-geosync.js | 64 +++++++++++++++++++ libs/common/tasks/index.js | 9 +++ .../v1/operations/alert/send-alert.patch.js | 44 +++---------- .../src/queues/geocode-alert-guess-address.js | 20 +++++- .../src/queues/geocode-alert-what-3-words.js | 27 +++++++- services/tasks/src/queues/geocode-move.js | 34 ++++++++++ 6 files changed, 159 insertions(+), 39 deletions(-) create mode 100644 libs/common/oapi/services/alert-geosync.js create mode 100644 libs/common/tasks/index.js diff --git a/libs/common/oapi/services/alert-geosync.js b/libs/common/oapi/services/alert-geosync.js new file mode 100644 index 0000000..d0ea74f --- /dev/null +++ b/libs/common/oapi/services/alert-geosync.js @@ -0,0 +1,64 @@ +const async = require("async") +const { ctx } = require("@modjo/core") +const tasks = require("~/tasks") + +module.exports = async function alertGeolocSync(params) { + const { addTask } = ctx.require("amqp") + const redis = ctx.require("redisHotGeodata") + + const { + alertId, + coordinates, + userId, + deviceId, + notifyAround = false, + notifyRelatives = false, + isLast = false, + } = params + + return async.parallel([ + async () => { + if (coordinates && coordinates.length === 2) { + const [longitude, latitude] = coordinates + return redis.geoadd("alert", longitude, latitude, alertId) + } + }, + + async () => + notifyAround && + userId && + deviceId && + addTask(tasks.GEOCODE_ALERT, { + alertId, + userId, + deviceId, + coordinates, + }), + + async () => + notifyRelatives && + userId && + addTask(tasks.RELATIVE_ALERT, { + alertId, + userId, + }), + + async () => + coordinates && + coordinates.length === 2 && + addTask(tasks.GEOCODE_ALERT_GUESS_ADDRESS, { + alertId, + coordinates, + isLast, + }), + + async () => + coordinates && + coordinates.length === 2 && + addTask(tasks.GEOCODE_ALERT_WHAT3WORDS, { + alertId, + coordinates, + isLast, + }), + ]) +} diff --git a/libs/common/tasks/index.js b/libs/common/tasks/index.js new file mode 100644 index 0000000..9b8688a --- /dev/null +++ b/libs/common/tasks/index.js @@ -0,0 +1,9 @@ +/** + * Common task constants for geocoding operations + */ +module.exports = { + GEOCODE_ALERT_GUESS_ADDRESS: "geocodeAlertGuessAddress", + GEOCODE_ALERT_WHAT3WORDS: "geocodeAlertWhat3Words", + GEOCODE_ALERT: "geocodeAlert", + RELATIVE_ALERT: "relativeAlert", +} diff --git a/services/api/src/api/v1/operations/alert/send-alert.patch.js b/services/api/src/api/v1/operations/alert/send-alert.patch.js index f50ced6..20c86bf 100644 --- a/services/api/src/api/v1/operations/alert/send-alert.patch.js +++ b/services/api/src/api/v1/operations/alert/send-alert.patch.js @@ -1,16 +1,13 @@ -const async = require("async") const { ctx } = require("@modjo/core") const { reqCtx } = require("@modjo/express/ctx") const { nanoid } = require("nanoid") // const natoUuid = require("utils/nato-alphabet/uuid") const wordsUuid = require("utils/words-id/uuid") -const tasks = require("~/tasks") +const alertGeosync = require("common/oapi/services/alert-geosync") module.exports = function () { const sql = ctx.require("postgres") - const { addTask } = ctx.require("amqp") - const redis = ctx.require("redisHotGeodata") // ;(async () => { // for (const row of await sql`SELECT id,uuid FROM alert`) { @@ -74,36 +71,15 @@ module.exports = function () { ` }) - await async.parallel([ - async () => { - const [longitude, latitude] = coordinates - return redis.geoadd("alert", longitude, latitude, alertId) - }, - async () => - notifyAround && - addTask(tasks.GEOCODE_ALERT, { - alertId, - userId, - deviceId, - coordinates, - }), - async () => - notifyRelatives && - addTask(tasks.RELATIVE_ALERT, { - alertId, - userId, - }), - async () => - addTask(tasks.GEOCODE_ALERT_GUESS_ADDRESS, { - alertId, - coordinates, - }), - async () => - addTask(tasks.GEOCODE_ALERT_WHAT3WORDS, { - alertId, - coordinates, - }), - ]) + await alertGeosync({ + alertId, + coordinates, + userId, + deviceId, + notifyAround, + notifyRelatives, + isLast: false, + }) return { alertId, accessCode, code } } diff --git a/services/tasks/src/queues/geocode-alert-guess-address.js b/services/tasks/src/queues/geocode-alert-guess-address.js index d56a0fe..be14252 100644 --- a/services/tasks/src/queues/geocode-alert-guess-address.js +++ b/services/tasks/src/queues/geocode-alert-guess-address.js @@ -11,10 +11,24 @@ module.exports = async function () { const sql = ctx.require("postgres") - const { coordinates, alertId } = params + const { coordinates, alertId, isLast = false } = params + + // Check if coordinates is valid + if ( + !coordinates || + !Array.isArray(coordinates) || + coordinates.length !== 2 + ) { + logger.error( + { params }, + "Invalid coordinates for geocodeAlertGuessAddress" + ) + return + } const nominatimResult = await nominatimReverse(coordinates) if (!nominatimResult) { + logger.error({ params }, "Failed to get nominatim result") return } const { display_name: address } = nominatimResult @@ -23,11 +37,13 @@ module.exports = async function () { return } + const fields = isLast ? { last_address: address } : { address } + await sql` UPDATE "alert" SET - "address" = ${address} + ${sql(fields)} WHERE "id" = ${alertId} ` diff --git a/services/tasks/src/queues/geocode-alert-what-3-words.js b/services/tasks/src/queues/geocode-alert-what-3-words.js index 845bfa1..92fd996 100644 --- a/services/tasks/src/queues/geocode-alert-what-3-words.js +++ b/services/tasks/src/queues/geocode-alert-what-3-words.js @@ -11,17 +11,38 @@ module.exports = async function () { const sql = ctx.require("postgres") - const { coordinates, alertId } = params + const { coordinates, alertId, isLast = false } = params + + // Check if coordinates is valid + if ( + !coordinates || + !Array.isArray(coordinates) || + coordinates.length !== 2 + ) { + logger.error( + { params }, + "Invalid coordinates for geocodeAlertWhat3words" + ) + return + } const what3wordsResult = await what3words(coordinates) + if (!what3wordsResult) { + logger.error({ params }, "Failed to get what3words result") + return + } + const { words, nearestPlace } = what3wordsResult + const fields = isLast + ? { last_what3words: words, last_nearest_place: nearestPlace } + : { what3words: words, nearest_place: nearestPlace } + await sql` UPDATE "alert" SET - "what3words" = ${words}, - "nearest_place" = ${nearestPlace} + ${sql(fields)} WHERE "id" = ${alertId} ` diff --git a/services/tasks/src/queues/geocode-move.js b/services/tasks/src/queues/geocode-move.js index 3028b36..a5e6914 100644 --- a/services/tasks/src/queues/geocode-move.js +++ b/services/tasks/src/queues/geocode-move.js @@ -3,6 +3,7 @@ const async = require("async") const { ctx } = require("@modjo/core") // const { taskCtx } = require("@modjo/microservice-worker/ctx") +const alertGeosync = require("common/oapi/services/alert-geosync") const { ignoreForeignKeyViolation } = require("common/libs/pg/ignoreErrors") const { DEVICE_RADIUS_ALL_DEFAULT, @@ -116,6 +117,39 @@ module.exports = async function () { AND "follow_location" = TRUE ` }, + async () => { + if (!device.followLocation) { + return + } + + // Get all open alerts for this device that follow location + const alerts = await sql` + SELECT + "id", + "notify_around" + FROM + "alert" + WHERE + "device_id" = ${deviceId} + AND "state" = 'open' + AND "follow_location" = TRUE + ` + + // Update geolocation data for each alert + await Promise.all( + alerts.map((alert) => + alertGeosync({ + alertId: alert.id, + coordinates, + userId, + deviceId, + notifyAround: alert.notifyAround, + notifyRelatives: false, + isLast: true, + }) + ) + ) + }, ]) // elapsed.end()