2015-12-16 11:15:43 +02:00
|
|
|
'use strict';
|
|
|
|
|
|
2022-01-19 20:52:12 -05:00
|
|
|
const winston = require('winston');
|
2024-08-02 10:06:28 -04:00
|
|
|
const validator = require('validator');
|
2022-01-19 20:52:12 -05:00
|
|
|
|
2023-07-12 13:03:54 -04:00
|
|
|
const batch = require('../batch');
|
|
|
|
|
const db = require('../database');
|
2020-09-28 11:18:43 -04:00
|
|
|
const notifications = require('../notifications');
|
2023-07-21 16:19:26 -04:00
|
|
|
const user = require('../user');
|
2023-07-12 13:03:54 -04:00
|
|
|
const io = require('../socket.io');
|
2025-10-22 12:51:50 -04:00
|
|
|
const activitypub = require('../activitypub');
|
2020-09-28 11:18:43 -04:00
|
|
|
const plugins = require('../plugins');
|
2024-08-02 10:06:28 -04:00
|
|
|
const utils = require('../utils');
|
2015-12-16 11:15:43 +02:00
|
|
|
|
2016-10-13 11:43:39 +02:00
|
|
|
module.exports = function (Messaging) {
|
2023-07-21 15:31:34 -04:00
|
|
|
Messaging.setUserNotificationSetting = async (uid, roomId, value) => {
|
|
|
|
|
if (parseInt(value, 10) === -1) {
|
|
|
|
|
// go back to default
|
|
|
|
|
return await db.deleteObjectField(`chat:room:${roomId}:notification:settings`, uid);
|
|
|
|
|
}
|
|
|
|
|
await db.setObjectField(`chat:room:${roomId}:notification:settings`, uid, parseInt(value, 10));
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Messaging.getUidsNotificationSetting = async (uids, roomId) => {
|
|
|
|
|
const [settings, roomData] = await Promise.all([
|
|
|
|
|
db.getObjectFields(`chat:room:${roomId}:notification:settings`, uids),
|
|
|
|
|
Messaging.getRoomData(roomId, ['notificationSetting']),
|
|
|
|
|
]);
|
|
|
|
|
return uids.map(uid => parseInt(settings[uid] || roomData.notificationSetting, 10));
|
|
|
|
|
};
|
|
|
|
|
|
2023-07-21 16:19:26 -04:00
|
|
|
Messaging.markRoomNotificationsRead = async (uid, roomId) => {
|
|
|
|
|
const chatNids = await db.getSortedSetScan({
|
|
|
|
|
key: `uid:${uid}:notifications:unread`,
|
|
|
|
|
match: `chat_${roomId}_*`,
|
|
|
|
|
});
|
|
|
|
|
if (chatNids.length) {
|
|
|
|
|
await notifications.markReadMultiple(chatNids, uid);
|
|
|
|
|
await user.notifications.pushCount(uid);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2019-07-22 11:18:13 -04:00
|
|
|
Messaging.notifyUsersInRoom = async (fromUid, roomId, messageObj) => {
|
2023-07-12 13:03:54 -04:00
|
|
|
const isPublic = parseInt(await db.getObjectField(`chat:room:${roomId}`, 'public'), 10) === 1;
|
2017-04-26 10:45:40 -06:00
|
|
|
|
2019-07-22 11:18:13 -04:00
|
|
|
let data = {
|
|
|
|
|
roomId: roomId,
|
|
|
|
|
fromUid: fromUid,
|
|
|
|
|
message: messageObj,
|
2023-07-12 13:03:54 -04:00
|
|
|
public: isPublic,
|
2019-07-22 11:18:13 -04:00
|
|
|
};
|
2020-11-20 16:06:26 -05:00
|
|
|
data = await plugins.hooks.fire('filter:messaging.notify', data);
|
2023-07-12 13:03:54 -04:00
|
|
|
if (!data) {
|
2019-07-22 11:18:13 -04:00
|
|
|
return;
|
|
|
|
|
}
|
2017-04-26 10:45:40 -06:00
|
|
|
|
2023-07-12 13:03:54 -04:00
|
|
|
// delivers full message to all online users in roomId
|
|
|
|
|
io.in(`chat_room_${roomId}`).emit('event:chats.receive', data);
|
|
|
|
|
|
|
|
|
|
const unreadData = { roomId, fromUid, public: isPublic };
|
|
|
|
|
if (isPublic && !messageObj.system) {
|
|
|
|
|
// delivers unread public msg to all online users on the chats page
|
|
|
|
|
io.in(`chat_room_public_${roomId}`).emit('event:chats.public.unread', unreadData);
|
|
|
|
|
}
|
2023-07-21 15:31:34 -04:00
|
|
|
if (messageObj.system) {
|
2019-10-09 13:29:49 -04:00
|
|
|
return;
|
|
|
|
|
}
|
2023-07-12 13:03:54 -04:00
|
|
|
|
|
|
|
|
// push unread count only for private rooms
|
2023-07-21 15:31:34 -04:00
|
|
|
if (!isPublic) {
|
|
|
|
|
const uids = await Messaging.getAllUidsInRoomFromSet(`chat:room:${roomId}:uids:online`);
|
2024-08-02 10:06:28 -04:00
|
|
|
unreadData.teaser = {
|
|
|
|
|
content: validator.escape(
|
|
|
|
|
String(utils.stripHTMLTags(utils.decodeHTMLEntities(messageObj.content)))
|
|
|
|
|
),
|
|
|
|
|
user: messageObj.fromUser,
|
|
|
|
|
timestampISO: messageObj.timestampISO,
|
|
|
|
|
};
|
2023-07-21 15:31:34 -04:00
|
|
|
Messaging.pushUnreadCount(uids, unreadData);
|
|
|
|
|
}
|
2023-07-12 13:03:54 -04:00
|
|
|
|
2023-09-27 14:09:07 -04:00
|
|
|
try {
|
2024-10-07 14:09:34 -04:00
|
|
|
await Promise.all([
|
|
|
|
|
sendNotification(fromUid, roomId, messageObj),
|
2024-10-15 11:27:54 -04:00
|
|
|
!isPublic && utils.isNumber(fromUid) ?
|
2025-10-22 12:51:50 -04:00
|
|
|
activitypub.out.create.privateNote(messageObj) : null,
|
2024-10-07 14:09:34 -04:00
|
|
|
]);
|
2023-09-27 14:09:07 -04:00
|
|
|
} catch (err) {
|
|
|
|
|
winston.error(`[messaging/notifications] Unabled to send notification\n${err.stack}`);
|
2019-07-22 11:18:13 -04:00
|
|
|
}
|
2017-02-22 13:34:57 +03:00
|
|
|
};
|
2015-12-16 11:15:43 +02:00
|
|
|
|
2023-10-25 13:25:55 -04:00
|
|
|
async function sendNotification(fromUid, roomId, messageObj) {
|
|
|
|
|
const [settings, roomData, realtimeUids] = await Promise.all([
|
2023-07-21 15:31:34 -04:00
|
|
|
db.getObject(`chat:room:${roomId}:notification:settings`),
|
2023-08-20 11:51:09 -04:00
|
|
|
Messaging.getRoomData(roomId),
|
2023-10-25 13:25:55 -04:00
|
|
|
io.getUidsInRoom(`chat_room_${roomId}`),
|
2023-07-21 15:31:34 -04:00
|
|
|
]);
|
|
|
|
|
const roomDefault = roomData.notificationSetting;
|
2023-10-25 13:25:55 -04:00
|
|
|
const uidsToNotify = [];
|
2023-07-21 15:31:34 -04:00
|
|
|
const { ALLMESSAGES } = Messaging.notificationSettings;
|
2023-07-14 11:19:57 -04:00
|
|
|
await batch.processSortedSet(`chat:room:${roomId}:uids:online`, async (uids) => {
|
2023-07-21 15:31:34 -04:00
|
|
|
uids = uids.filter(
|
2024-10-04 17:07:57 -04:00
|
|
|
uid => utils.isNumber(uid) &&
|
|
|
|
|
(parseInt((settings && settings[uid]) || roomDefault, 10) === ALLMESSAGES) &&
|
2024-10-09 13:46:51 -04:00
|
|
|
String(fromUid) !== String(uid) &&
|
2023-10-25 13:25:55 -04:00
|
|
|
!realtimeUids.includes(parseInt(uid, 10))
|
2023-07-21 15:31:34 -04:00
|
|
|
);
|
2023-07-12 13:03:54 -04:00
|
|
|
const hasRead = await Messaging.hasRead(uids, roomId);
|
2023-07-21 15:31:34 -04:00
|
|
|
uidsToNotify.push(...uids.filter((uid, index) => !hasRead[index]));
|
2023-07-12 13:03:54 -04:00
|
|
|
}, {
|
2023-07-20 22:26:55 -04:00
|
|
|
reverse: true,
|
2023-07-12 13:03:54 -04:00
|
|
|
batch: 500,
|
2023-07-21 15:31:34 -04:00
|
|
|
interval: 100,
|
2023-07-12 13:03:54 -04:00
|
|
|
});
|
2023-07-21 15:31:34 -04:00
|
|
|
|
|
|
|
|
if (uidsToNotify.length) {
|
|
|
|
|
const { displayname } = messageObj.fromUser;
|
|
|
|
|
const isGroupChat = await Messaging.isGroupChat(roomId);
|
2023-09-27 14:09:07 -04:00
|
|
|
const roomName = roomData.roomName || `[[modules:chat.room-id, ${roomId}]]`;
|
2023-08-20 11:51:09 -04:00
|
|
|
const notifData = {
|
2023-07-21 15:31:34 -04:00
|
|
|
type: isGroupChat ? 'new-group-chat' : 'new-chat',
|
2023-10-05 01:02:39 -04:00
|
|
|
subject: roomData.roomName ?
|
|
|
|
|
`[[email:notif.chat.new-message-from-user-in-room, ${displayname}, ${roomName}]]` :
|
|
|
|
|
`[[email:notif.chat.new-message-from-user, ${displayname}]]`,
|
2023-10-05 12:48:50 -04:00
|
|
|
bodyShort: isGroupChat || roomData.roomName ? `[[notifications:new-message-in, ${roomName}]]` : `[[notifications:new-message-from, ${displayname}]]`,
|
2023-07-21 15:31:34 -04:00
|
|
|
bodyLong: messageObj.content,
|
2023-09-27 14:09:07 -04:00
|
|
|
nid: `chat_${roomId}_${fromUid}_${Date.now()}`,
|
|
|
|
|
mergeId: `new-chat|${roomId}`, // as roomId is the differentiator, no distinction between direct vs. group req'd.
|
2023-07-21 15:31:34 -04:00
|
|
|
from: fromUid,
|
2023-09-27 14:09:07 -04:00
|
|
|
roomId,
|
|
|
|
|
roomName,
|
2023-07-21 15:31:34 -04:00
|
|
|
path: `/chats/${messageObj.roomId}`,
|
2023-08-20 11:51:09 -04:00
|
|
|
};
|
|
|
|
|
if (roomData.public) {
|
|
|
|
|
const icon = Messaging.getRoomIcon(roomData);
|
|
|
|
|
notifData.type = 'new-public-chat';
|
|
|
|
|
notifData.roomIcon = icon;
|
2023-10-05 01:02:39 -04:00
|
|
|
notifData.subject = `[[email:notif.chat.new-message-from-user-in-room, ${displayname}, ${roomName}]]`;
|
2023-10-05 12:48:50 -04:00
|
|
|
notifData.bodyShort = `[[notifications:user-posted-in-public-room, ${displayname}, ${icon}, ${roomName}]]`;
|
|
|
|
|
notifData.mergeId = `notifications:user-posted-in-public-room|${roomId}`;
|
2023-08-20 11:51:09 -04:00
|
|
|
}
|
|
|
|
|
const notification = await notifications.create(notifData);
|
2023-07-21 15:31:34 -04:00
|
|
|
await notifications.push(notification, uidsToNotify);
|
|
|
|
|
}
|
2015-12-16 11:15:43 +02:00
|
|
|
}
|
2017-02-18 02:30:48 -07:00
|
|
|
};
|