From 8db7d53337dce9bd3568f0b842b653810f6805a9 Mon Sep 17 00:00:00 2001 From: Your Name Date: Thu, 25 Sep 2025 15:04:45 -0600 Subject: [PATCH] Improve replica set setup and add UnifiedPush test endpoint --- docker-compose.dev.yml | 4 +- docker-compose.yml | 4 +- .../controllers/api-v3/pushNotifications.js | 53 +++++++++++++++++++ website/server/libs/pushNotifications.js | 1 + 4 files changed, 58 insertions(+), 4 deletions(-) diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml index 56dba30aeb..e67ff32fb1 100644 --- a/docker-compose.dev.yml +++ b/docker-compose.dev.yml @@ -25,7 +25,7 @@ services: mongo: condition: service_healthy environment: - - NODE_DB_URI=mongodb://mongo/habitrpg + - NODE_DB_URI=mongodb://mongo/habitrpg?replicaSet=rs networks: - habitica ports: @@ -38,7 +38,7 @@ services: restart: unless-stopped command: ["--replSet", "rs", "--bind_ip_all", "--port", "27017"] healthcheck: - test: echo "try { rs.status() } catch (err) { rs.initiate() }" | mongosh --port 27017 --quiet + test: echo "try { rs.status() } catch (err) { rs.initiate({_id: 'rs', members: [{ _id: 0, host: 'mongo:27017' }]}) }" | mongosh --port 27017 --quiet interval: 10s timeout: 30s start_period: 0s diff --git a/docker-compose.yml b/docker-compose.yml index 33b1ef55f9..d2a50338e0 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -8,7 +8,7 @@ services: depends_on: - mongo environment: - - NODE_DB_URI=mongodb://mongo/habitica # this only needs to be adapted if using a separate database + - NODE_DB_URI=mongodb://mongo/habitica?replicaSet=rs # this only needs to be adapted if using a separate database - BASE_URL=http://127.0.0.1:8080 # change this to the URL under which your instance will be reachable - INVITE_ONLY=false # change to `true` after registration of initial users, to restrict further registrations networks: @@ -21,7 +21,7 @@ services: hostname: mongo command: ["--replSet", "rs", "--bind_ip_all", "--port", "27017"] healthcheck: - test: echo "try { rs.status() } catch (err) { rs.initiate() }" | mongosh --port 27017 --quiet + test: echo "try { rs.status() } catch (err) { rs.initiate({_id: 'rs', members: [{ _id: 0, host: 'mongo:27017' }]}) }" | mongosh --port 27017 --quiet interval: 10s timeout: 30s start_period: 0s diff --git a/website/server/controllers/api-v3/pushNotifications.js b/website/server/controllers/api-v3/pushNotifications.js index c6ec45366f..0f6a310ab9 100644 --- a/website/server/controllers/api-v3/pushNotifications.js +++ b/website/server/controllers/api-v3/pushNotifications.js @@ -3,6 +3,7 @@ import { NotFound, } from '../../libs/errors'; import { model as PushDevice } from '../../models/pushDevice'; +import { sendNotification as sendPushNotification } from '../../libs/pushNotifications'; const api = {}; @@ -57,6 +58,58 @@ api.addPushDevice = { }, }; +/** + * @apiIgnore + * @api {post} /api/v3/user/push-devices/test Send a test push notification + * @apiName UserSendTestPushNotification + * @apiGroup User + * + * @apiParam (Body) {String} [regId] The id of a specific push device to target + * + * @apiSuccess {String} message Success message + */ +api.sendUnifiedPushTest = { + method: 'POST', + url: '/user/push-devices/test', + middlewares: [authWithHeaders()], + async handler (req, res) { + const { user } = res.locals; + + const regId = req.body?.regId; + const pushDevices = user.pushDevices?.toObject ? user.pushDevices.toObject() : user.pushDevices; + let unifiedPushDevices = (pushDevices || []).filter(device => device?.type === 'unifiedpush'); + + if (regId) { + unifiedPushDevices = unifiedPushDevices.filter(device => device.regId === regId); + } + + if (unifiedPushDevices.length === 0) { + throw new NotFound(res.t('pushDeviceNotFound')); + } + + const notificationTitle = req.body?.title + || res.t('unifiedPushTestTitle', { defaultValue: 'Habitica UnifiedPush Test' }); + const notificationMessage = req.body?.message + || res.t('unifiedPushTestMessage', { defaultValue: 'This is a test UnifiedPush notification from Habitica.' }); + const successMessage = res.t('unifiedPushTestSent', { defaultValue: 'UnifiedPush test notification sent.' }); + + const userForPush = user.toObject ? user.toObject() : { ...user }; + userForPush._id = user._id; + userForPush.pushDevices = unifiedPushDevices; + + await sendPushNotification(userForPush, { + identifier: 'unifiedPushTestNotification', + title: notificationTitle, + message: notificationMessage, + payload: { + message: notificationMessage, + }, + }); + + res.respond(200, null, successMessage); + }, +}; + /** * @apiIgnore * @api {delete} /api/v3/user/push-devices/:regId remove a push device from a user diff --git a/website/server/libs/pushNotifications.js b/website/server/libs/pushNotifications.js index 66fa675593..8d816165b0 100644 --- a/website/server/libs/pushNotifications.js +++ b/website/server/libs/pushNotifications.js @@ -144,6 +144,7 @@ async function sendUnifiedPushNotification (user, pushDevice, details, payload) const body = { title: details.title, message: details.message, + body: details.message, identifier: details.identifier, payload, };