mirror of
https://github.com/NodeBB/NodeBB.git
synced 2025-11-01 11:35:55 +01:00
148 lines
5.3 KiB
JavaScript
148 lines
5.3 KiB
JavaScript
'use strict';
|
|
|
|
const winston = require('winston');
|
|
const validator = require('validator');
|
|
|
|
const batch = require('../batch');
|
|
const db = require('../database');
|
|
const notifications = require('../notifications');
|
|
const user = require('../user');
|
|
const io = require('../socket.io');
|
|
const activitypub = require('../activitypub');
|
|
const plugins = require('../plugins');
|
|
const utils = require('../utils');
|
|
|
|
module.exports = function (Messaging) {
|
|
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));
|
|
};
|
|
|
|
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);
|
|
}
|
|
};
|
|
|
|
Messaging.notifyUsersInRoom = async (fromUid, roomId, messageObj) => {
|
|
const isPublic = parseInt(await db.getObjectField(`chat:room:${roomId}`, 'public'), 10) === 1;
|
|
|
|
let data = {
|
|
roomId: roomId,
|
|
fromUid: fromUid,
|
|
message: messageObj,
|
|
public: isPublic,
|
|
};
|
|
data = await plugins.hooks.fire('filter:messaging.notify', data);
|
|
if (!data) {
|
|
return;
|
|
}
|
|
|
|
// 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);
|
|
}
|
|
if (messageObj.system) {
|
|
return;
|
|
}
|
|
|
|
// push unread count only for private rooms
|
|
if (!isPublic) {
|
|
const uids = await Messaging.getAllUidsInRoomFromSet(`chat:room:${roomId}:uids:online`);
|
|
unreadData.teaser = {
|
|
content: validator.escape(
|
|
String(utils.stripHTMLTags(utils.decodeHTMLEntities(messageObj.content)))
|
|
),
|
|
user: messageObj.fromUser,
|
|
timestampISO: messageObj.timestampISO,
|
|
};
|
|
Messaging.pushUnreadCount(uids, unreadData);
|
|
}
|
|
|
|
try {
|
|
await Promise.all([
|
|
sendNotification(fromUid, roomId, messageObj),
|
|
!isPublic && utils.isNumber(fromUid) ?
|
|
activitypub.out.create.privateNote(messageObj) : null,
|
|
]);
|
|
} catch (err) {
|
|
winston.error(`[messaging/notifications] Unabled to send notification\n${err.stack}`);
|
|
}
|
|
};
|
|
|
|
async function sendNotification(fromUid, roomId, messageObj) {
|
|
const [settings, roomData, realtimeUids] = await Promise.all([
|
|
db.getObject(`chat:room:${roomId}:notification:settings`),
|
|
Messaging.getRoomData(roomId),
|
|
io.getUidsInRoom(`chat_room_${roomId}`),
|
|
]);
|
|
const roomDefault = roomData.notificationSetting;
|
|
const uidsToNotify = [];
|
|
const { ALLMESSAGES } = Messaging.notificationSettings;
|
|
await batch.processSortedSet(`chat:room:${roomId}:uids:online`, async (uids) => {
|
|
uids = uids.filter(
|
|
uid => utils.isNumber(uid) &&
|
|
(parseInt((settings && settings[uid]) || roomDefault, 10) === ALLMESSAGES) &&
|
|
String(fromUid) !== String(uid) &&
|
|
!realtimeUids.includes(parseInt(uid, 10))
|
|
);
|
|
const hasRead = await Messaging.hasRead(uids, roomId);
|
|
uidsToNotify.push(...uids.filter((uid, index) => !hasRead[index]));
|
|
}, {
|
|
reverse: true,
|
|
batch: 500,
|
|
interval: 100,
|
|
});
|
|
|
|
if (uidsToNotify.length) {
|
|
const { displayname } = messageObj.fromUser;
|
|
const isGroupChat = await Messaging.isGroupChat(roomId);
|
|
const roomName = roomData.roomName || `[[modules:chat.room-id, ${roomId}]]`;
|
|
const notifData = {
|
|
type: isGroupChat ? 'new-group-chat' : 'new-chat',
|
|
subject: roomData.roomName ?
|
|
`[[email:notif.chat.new-message-from-user-in-room, ${displayname}, ${roomName}]]` :
|
|
`[[email:notif.chat.new-message-from-user, ${displayname}]]`,
|
|
bodyShort: isGroupChat || roomData.roomName ? `[[notifications:new-message-in, ${roomName}]]` : `[[notifications:new-message-from, ${displayname}]]`,
|
|
bodyLong: messageObj.content,
|
|
nid: `chat_${roomId}_${fromUid}_${Date.now()}`,
|
|
mergeId: `new-chat|${roomId}`, // as roomId is the differentiator, no distinction between direct vs. group req'd.
|
|
from: fromUid,
|
|
roomId,
|
|
roomName,
|
|
path: `/chats/${messageObj.roomId}`,
|
|
};
|
|
if (roomData.public) {
|
|
const icon = Messaging.getRoomIcon(roomData);
|
|
notifData.type = 'new-public-chat';
|
|
notifData.roomIcon = icon;
|
|
notifData.subject = `[[email:notif.chat.new-message-from-user-in-room, ${displayname}, ${roomName}]]`;
|
|
notifData.bodyShort = `[[notifications:user-posted-in-public-room, ${displayname}, ${icon}, ${roomName}]]`;
|
|
notifData.mergeId = `notifications:user-posted-in-public-room|${roomId}`;
|
|
}
|
|
const notification = await notifications.create(notifData);
|
|
await notifications.push(notification, uidsToNotify);
|
|
}
|
|
}
|
|
};
|