mirror of
				https://github.com/NodeBB/NodeBB.git
				synced 2025-10-31 11:05:54 +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);
 | |
| 		}
 | |
| 	}
 | |
| };
 |