diff --git a/apps/meteor/app/autotranslate/server/autotranslate.ts b/apps/meteor/app/autotranslate/server/autotranslate.ts index 7a9eb8780a2d..1e6c224c4115 100644 --- a/apps/meteor/app/autotranslate/server/autotranslate.ts +++ b/apps/meteor/app/autotranslate/server/autotranslate.ts @@ -15,7 +15,7 @@ import _ from 'underscore'; import { callbacks } from '../../../lib/callbacks'; import { isTruthy } from '../../../lib/isTruthy'; -import { broadcastMessageFromData } from '../../../server/modules/watchers/lib/messages'; +import { notifyOnMessageChange } from '../../lib/server/lib/notifyListener'; import { Markdown } from '../../markdown/server'; import { settings } from '../../settings/server'; @@ -332,7 +332,7 @@ export abstract class AutoTranslate { } private notifyTranslatedMessage(messageId: string): void { - void broadcastMessageFromData({ + void notifyOnMessageChange({ id: messageId, }); } diff --git a/apps/meteor/app/discussion/server/hooks/propagateDiscussionMetadata.ts b/apps/meteor/app/discussion/server/hooks/propagateDiscussionMetadata.ts index d8e3637575ab..05cf2326156f 100644 --- a/apps/meteor/app/discussion/server/hooks/propagateDiscussionMetadata.ts +++ b/apps/meteor/app/discussion/server/hooks/propagateDiscussionMetadata.ts @@ -2,15 +2,15 @@ import type { IRoom } from '@rocket.chat/core-typings'; import { Messages, Rooms, VideoConference } from '@rocket.chat/models'; import { callbacks } from '../../../../lib/callbacks'; -import { broadcastMessageFromData } from '../../../../server/modules/watchers/lib/messages'; import { deleteRoom } from '../../../lib/server/functions/deleteRoom'; +import { notifyOnMessageChange } from '../../../lib/server/lib/notifyListener'; const updateAndNotifyParentRoomWithParentMessage = async (room: IRoom): Promise => { const { value: parentMessage } = await Messages.refreshDiscussionMetadata(room); if (!parentMessage) { return; } - void broadcastMessageFromData({ + void notifyOnMessageChange({ id: parentMessage._id, data: parentMessage, }); diff --git a/apps/meteor/app/federation/server/endpoints/dispatch.js b/apps/meteor/app/federation/server/endpoints/dispatch.js index 4cab0b0c41e8..6c7fa5cad0e8 100644 --- a/apps/meteor/app/federation/server/endpoints/dispatch.js +++ b/apps/meteor/app/federation/server/endpoints/dispatch.js @@ -3,11 +3,10 @@ import { eventTypes } from '@rocket.chat/core-typings'; import { FederationServers, FederationRoomEvents, Rooms, Messages, Subscriptions, Users, ReadReceipts } from '@rocket.chat/models'; import EJSON from 'ejson'; -import { broadcastMessageFromData } from '../../../../server/modules/watchers/lib/messages'; import { API } from '../../../api/server'; import { FileUpload } from '../../../file-upload/server'; import { deleteRoom } from '../../../lib/server/functions/deleteRoom'; -import { notifyOnRoomChanged, notifyOnRoomChangedById } from '../../../lib/server/lib/notifyListener'; +import { notifyOnMessageChange, notifyOnRoomChanged, notifyOnRoomChangedById } from '../../../lib/server/lib/notifyListener'; import { notifyUsersOnMessage } from '../../../lib/server/lib/notifyUsersOnMessage'; import { sendAllNotifications } from '../../../lib/server/lib/sendNotificationsOnMessage'; import { processThreads } from '../../../threads/server/hooks/aftersavemessage'; @@ -303,7 +302,7 @@ const eventHandlers = { } } if (messageForNotification) { - void broadcastMessageFromData({ + void notifyOnMessageChange({ id: messageForNotification._id, data: messageForNotification, }); @@ -334,7 +333,7 @@ const eventHandlers = { } else { // Update the message await Messages.updateOne({ _id: persistedMessage._id }, { $set: { msg: message.msg, federation: message.federation } }); - void broadcastMessageFromData({ + void notifyOnMessageChange({ id: persistedMessage._id, data: { ...persistedMessage, @@ -404,7 +403,7 @@ const eventHandlers = { // Update the property await Messages.updateOne({ _id: messageId }, { $set: { [`reactions.${reaction}`]: reactionObj } }); - void broadcastMessageFromData({ + void notifyOnMessageChange({ id: persistedMessage._id, data: { ...persistedMessage, @@ -462,7 +461,7 @@ const eventHandlers = { // Otherwise, update the property await Messages.updateOne({ _id: messageId }, { $set: { [`reactions.${reaction}`]: reactionObj } }); } - void broadcastMessageFromData({ + void notifyOnMessageChange({ id: persistedMessage._id, data: { ...persistedMessage, diff --git a/apps/meteor/app/lib/server/functions/deleteMessage.ts b/apps/meteor/app/lib/server/functions/deleteMessage.ts index e977874b3454..04542d5f1d27 100644 --- a/apps/meteor/app/lib/server/functions/deleteMessage.ts +++ b/apps/meteor/app/lib/server/functions/deleteMessage.ts @@ -5,11 +5,10 @@ import { Messages, Rooms, Uploads, Users, ReadReceipts } from '@rocket.chat/mode import { Meteor } from 'meteor/meteor'; import { callbacks } from '../../../../lib/callbacks'; -import { broadcastMessageFromData } from '../../../../server/modules/watchers/lib/messages'; import { canDeleteMessageAsync } from '../../../authorization/server/functions/canDeleteMessage'; import { FileUpload } from '../../../file-upload/server'; import { settings } from '../../../settings/server'; -import { notifyOnRoomChangedById } from '../lib/notifyListener'; +import { notifyOnRoomChangedById, notifyOnMessageChange } from '../lib/notifyListener'; export const deleteMessageValidatingPermission = async (message: AtLeast, userId: IUser['_id']): Promise => { if (!message?._id) { @@ -93,7 +92,7 @@ export async function deleteMessage(message: IMessage, user: IUser): Promise => { + const user = await Users.findOne>(userId, { projection: { name: 1 } }); + return user?.name; + }, + { maxAge: 10000 }, +); + +const getSettingCached = mem(async (setting: string): Promise => Settings.getValueById(setting), { maxAge: 10000 }); + +export async function getMessageToBroadcast({ id, data }: { id: IMessage['_id']; data?: IMessage }): Promise { + const message = data ?? (await Messages.findOneById(id)); + if (!message) { + return; + } + + if (message.t) { + const hiddenSystemMessages = (await getSettingCached('Hide_System_Messages')) as MessageTypesValues[]; + const shouldHide = shouldHideSystemMessage(message.t, hiddenSystemMessages); + + if (shouldHide) { + return; + } + } + + if (message._hidden || message.imported != null) { + return; + } + + const useRealName = (await getSettingCached('UI_Use_Real_Name')) === true; + if (useRealName) { + if (message.u?._id) { + const name = await getUserNameCached(message.u._id); + if (name) { + message.u.name = name; + } + } + + if (message.mentions?.length) { + for await (const mention of message.mentions) { + const name = await getUserNameCached(mention._id); + if (name) { + mention.name = name; + } + } + } + } + + return message; +} + +export const notifyOnMessageChange = withDbWatcherCheck(async ({ id, data }: { id: IMessage['_id']; data?: IMessage }): Promise => { + if (!dbWatchersDisabled) { + return; + } + const message = await getMessageToBroadcast({ id, data }); + if (!message) { + return; + } + void api.broadcast('watch.messages', { message }); +}); diff --git a/apps/meteor/app/message-pin/server/pinMessage.ts b/apps/meteor/app/message-pin/server/pinMessage.ts index b0eab3f929d6..b53c4ed572b9 100644 --- a/apps/meteor/app/message-pin/server/pinMessage.ts +++ b/apps/meteor/app/message-pin/server/pinMessage.ts @@ -8,11 +8,10 @@ import { check } from 'meteor/check'; import { Meteor } from 'meteor/meteor'; import { isTruthy } from '../../../lib/isTruthy'; -import { broadcastMessageFromData } from '../../../server/modules/watchers/lib/messages'; import { canAccessRoomAsync, roomAccessAttributes } from '../../authorization/server'; import { hasPermissionAsync } from '../../authorization/server/functions/hasPermission'; import { isTheLastMessage } from '../../lib/server/functions/isTheLastMessage'; -import { notifyOnRoomChangedById } from '../../lib/server/lib/notifyListener'; +import { notifyOnRoomChangedById, notifyOnMessageChange } from '../../lib/server/lib/notifyListener'; import { settings } from '../../settings/server'; import { getUserAvatarURL } from '../../utils/server/getUserAvatarURL'; @@ -227,7 +226,7 @@ Meteor.methods({ if (settings.get('Message_Read_Receipt_Store_Users')) { await ReadReceipts.setPinnedByMessageId(originalMessage._id, originalMessage.pinned); } - void broadcastMessageFromData({ + void notifyOnMessageChange({ id: message._id, }); diff --git a/apps/meteor/app/message-star/server/starMessage.ts b/apps/meteor/app/message-star/server/starMessage.ts index 4529efb63f6f..048fbdaca01b 100644 --- a/apps/meteor/app/message-star/server/starMessage.ts +++ b/apps/meteor/app/message-star/server/starMessage.ts @@ -4,10 +4,9 @@ import { Messages, Subscriptions, Rooms } from '@rocket.chat/models'; import type { ServerMethods } from '@rocket.chat/ui-contexts'; import { Meteor } from 'meteor/meteor'; -import { broadcastMessageFromData } from '../../../server/modules/watchers/lib/messages'; import { canAccessRoomAsync, roomAccessAttributes } from '../../authorization/server'; import { isTheLastMessage } from '../../lib/server/functions/isTheLastMessage'; -import { notifyOnRoomChangedById } from '../../lib/server/lib/notifyListener'; +import { notifyOnRoomChangedById, notifyOnMessageChange } from '../../lib/server/lib/notifyListener'; import { settings } from '../../settings/server'; declare module '@rocket.chat/ui-contexts' { @@ -63,7 +62,7 @@ Meteor.methods({ await Messages.updateUserStarById(message._id, uid, message.starred); - void broadcastMessageFromData({ + void notifyOnMessageChange({ id: message._id, }); diff --git a/apps/meteor/app/reactions/server/setReaction.ts b/apps/meteor/app/reactions/server/setReaction.ts index 896e5041bd61..e935e042b184 100644 --- a/apps/meteor/app/reactions/server/setReaction.ts +++ b/apps/meteor/app/reactions/server/setReaction.ts @@ -8,12 +8,11 @@ import _ from 'underscore'; import { callbacks } from '../../../lib/callbacks'; import { i18n } from '../../../server/lib/i18n'; -import { broadcastMessageFromData } from '../../../server/modules/watchers/lib/messages'; import { canAccessRoomAsync } from '../../authorization/server'; import { hasPermissionAsync } from '../../authorization/server/functions/hasPermission'; import { emoji } from '../../emoji/server'; import { isTheLastMessage } from '../../lib/server/functions/isTheLastMessage'; -import { notifyOnRoomChangedById } from '../../lib/server/lib/notifyListener'; +import { notifyOnRoomChangedById, notifyOnMessageChange } from '../../lib/server/lib/notifyListener'; const removeUserReaction = (message: IMessage, reaction: string, username: string) => { if (!message.reactions) { @@ -111,7 +110,7 @@ async function setReaction(room: IRoom, user: IUser, message: IMessage, reaction await Apps.self?.triggerEvent(AppEvents.IPostMessageReacted, message, user, reaction, isReacted); - void broadcastMessageFromData({ + void notifyOnMessageChange({ id: message._id, }); } diff --git a/apps/meteor/app/threads/server/hooks/aftersavemessage.ts b/apps/meteor/app/threads/server/hooks/aftersavemessage.ts index ab1fa182599b..179cb5ec12b7 100644 --- a/apps/meteor/app/threads/server/hooks/aftersavemessage.ts +++ b/apps/meteor/app/threads/server/hooks/aftersavemessage.ts @@ -4,7 +4,7 @@ import { Messages } from '@rocket.chat/models'; import { Meteor } from 'meteor/meteor'; import { callbacks } from '../../../../lib/callbacks'; -import { broadcastMessageFromData } from '../../../../server/modules/watchers/lib/messages'; +import { notifyOnMessageChange } from '../../../lib/server/lib/notifyListener'; import { updateThreadUsersSubscriptions, getMentions } from '../../../lib/server/lib/notifyUsersOnMessage'; import { sendMessageNotifications } from '../../../lib/server/lib/sendNotificationsOnMessage'; import { settings } from '../../../settings/server'; @@ -62,7 +62,7 @@ export async function processThreads(message: IMessage, room: IRoom) { await notifyUsersOnReply(message, replies); await metaData(message, parentMessage, replies); await notification(message, room, replies); - void broadcastMessageFromData({ + void notifyOnMessageChange({ id: message.tmid, }); diff --git a/apps/meteor/ee/server/lib/message-read-receipt/ReadReceipt.js b/apps/meteor/ee/server/lib/message-read-receipt/ReadReceipt.js index 66be655a7d09..b1d9f43985ad 100644 --- a/apps/meteor/ee/server/lib/message-read-receipt/ReadReceipt.js +++ b/apps/meteor/ee/server/lib/message-read-receipt/ReadReceipt.js @@ -2,11 +2,10 @@ import { api } from '@rocket.chat/core-services'; import { LivechatVisitors, ReadReceipts, Messages, Rooms, Subscriptions, Users } from '@rocket.chat/models'; import { Random } from '@rocket.chat/random'; -import { notifyOnRoomChangedById } from '../../../../app/lib/server/lib/notifyListener'; +import { notifyOnRoomChangedById, notifyOnMessageChange } from '../../../../app/lib/server/lib/notifyListener'; import { settings } from '../../../../app/settings/server'; import { SystemLogger } from '../../../../server/lib/logger/system'; import { roomCoordinator } from '../../../../server/lib/rooms/roomCoordinator'; -import { broadcastMessageFromData } from '../../../../server/modules/watchers/lib/messages'; // debounced function by roomId, so multiple calls within 2 seconds to same roomId runs only once const list = {}; @@ -70,7 +69,7 @@ export const ReadReceipt = { if (isUserAlone) { const result = await Messages.setAsReadById(message._id); if (result.modifiedCount > 0) { - void broadcastMessageFromData({ + void notifyOnMessageChange({ id: message._id, }); } diff --git a/apps/meteor/server/features/EmailInbox/EmailInbox_Incoming.ts b/apps/meteor/server/features/EmailInbox/EmailInbox_Incoming.ts index 642d989f85b6..0797d896f22d 100644 --- a/apps/meteor/server/features/EmailInbox/EmailInbox_Incoming.ts +++ b/apps/meteor/server/features/EmailInbox/EmailInbox_Incoming.ts @@ -12,11 +12,11 @@ import type { ParsedMail, Attachment } from 'mailparser'; import stripHtml from 'string-strip-html'; import { FileUpload } from '../../../app/file-upload/server'; +import { notifyOnMessageChange } from '../../../app/lib/server/lib/notifyListener'; import { Livechat as LivechatTyped } from '../../../app/livechat/server/lib/LivechatTyped'; import { QueueManager } from '../../../app/livechat/server/lib/QueueManager'; import { settings } from '../../../app/settings/server'; import { i18n } from '../../lib/i18n'; -import { broadcastMessageFromData } from '../../modules/watchers/lib/messages'; import { logger } from './logger'; type FileAttachment = VideoAttachmentProps & ImageAttachmentProps & AudioAttachmentProps; @@ -234,7 +234,7 @@ export async function onEmailReceived(email: ParsedMail, inbox: string, departme }, ); room && (await LivechatRooms.updateEmailThreadByRoomId(room._id, thread)); - void broadcastMessageFromData({ + void notifyOnMessageChange({ id: msgId, }); }) diff --git a/apps/meteor/server/features/EmailInbox/EmailInbox_Outgoing.ts b/apps/meteor/server/features/EmailInbox/EmailInbox_Outgoing.ts index 708d00422b5d..80be176ada35 100644 --- a/apps/meteor/server/features/EmailInbox/EmailInbox_Outgoing.ts +++ b/apps/meteor/server/features/EmailInbox/EmailInbox_Outgoing.ts @@ -6,11 +6,11 @@ import type Mail from 'nodemailer/lib/mailer'; import { FileUpload } from '../../../app/file-upload/server'; import { sendMessage } from '../../../app/lib/server/functions/sendMessage'; +import { notifyOnMessageChange } from '../../../app/lib/server/lib/notifyListener'; import { settings } from '../../../app/settings/server'; import { slashCommands } from '../../../app/utils/server/slashCommand'; import { callbacks } from '../../../lib/callbacks'; import { i18n } from '../../lib/i18n'; -import { broadcastMessageFromData } from '../../modules/watchers/lib/messages'; import { inboxes } from './EmailInbox'; import type { Inbox } from './EmailInbox'; import { logger } from './logger'; @@ -171,7 +171,7 @@ slashCommands.add({ }, }, ); - void broadcastMessageFromData({ + void notifyOnMessageChange({ id: message._id, }); diff --git a/apps/meteor/server/modules/watchers/lib/messages.ts b/apps/meteor/server/modules/watchers/lib/messages.ts deleted file mode 100644 index e127f465efe9..000000000000 --- a/apps/meteor/server/modules/watchers/lib/messages.ts +++ /dev/null @@ -1,71 +0,0 @@ -import { api, dbWatchersDisabled } from '@rocket.chat/core-services'; -import type { IMessage, IUser, SettingValue, MessageTypesValues } from '@rocket.chat/core-typings'; -import { Messages, Settings, Users } from '@rocket.chat/models'; -import mem from 'mem'; - -import { shouldHideSystemMessage } from '../../../lib/systemMessage/hideSystemMessage'; - -const getUserNameCached = mem( - async (userId: string): Promise => { - const user = await Users.findOne>(userId, { projection: { name: 1 } }); - return user?.name; - }, - { maxAge: 10000 }, -); - -const getSettingCached = mem(async (setting: string): Promise => Settings.getValueById(setting), { maxAge: 10000 }); - -export async function getMessageToBroadcast({ id, data }: { id: IMessage['_id']; data?: IMessage }): Promise { - const message = data ?? (await Messages.findOneById(id)); - if (!message) { - return; - } - - if (message.t) { - const hiddenSystemMessages = (await getSettingCached('Hide_System_Messages')) as MessageTypesValues[]; - const shouldHide = shouldHideSystemMessage(message.t, hiddenSystemMessages); - - if (shouldHide) { - return; - } - } - - if (message._hidden || message.imported != null) { - return; - } - - const useRealName = (await getSettingCached('UI_Use_Real_Name')) === true; - if (useRealName) { - if (message.u?._id) { - const name = await getUserNameCached(message.u._id); - if (name) { - message.u.name = name; - } - } - - if (message.mentions?.length) { - for await (const mention of message.mentions) { - const name = await getUserNameCached(mention._id); - if (name) { - mention.name = name; - } - } - } - } - - return message; -} - -// TODO once the broadcast from file apps/meteor/server/modules/watchers/watchers.module.ts is removed -// this function can be renamed to broadcastMessage -export async function broadcastMessageFromData({ id, data }: { id: IMessage['_id']; data?: IMessage }): Promise { - // if db watchers are active, the event will be triggered automatically so we don't need to broadcast it here. - if (!dbWatchersDisabled) { - return; - } - const message = await getMessageToBroadcast({ id, data }); - if (!message) { - return; - } - void api.broadcast('watch.messages', { message }); -} diff --git a/apps/meteor/server/modules/watchers/watchers.module.ts b/apps/meteor/server/modules/watchers/watchers.module.ts index 684db6945626..c42b24d35b7e 100644 --- a/apps/meteor/server/modules/watchers/watchers.module.ts +++ b/apps/meteor/server/modules/watchers/watchers.module.ts @@ -37,9 +37,9 @@ import { LivechatPriority, } from '@rocket.chat/models'; +import { getMessageToBroadcast } from '../../../app/lib/server/lib/notifyListener'; import { subscriptionFields, roomFields } from '../../../lib/publishFields'; import type { DatabaseWatcher } from '../../database/DatabaseWatcher'; -import { getMessageToBroadcast } from './lib/messages'; type BroadcastCallback = (event: T, ...args: Parameters) => Promise; diff --git a/apps/meteor/server/services/messages/service.ts b/apps/meteor/server/services/messages/service.ts index 03906bfd0208..4485bb7ad93b 100644 --- a/apps/meteor/server/services/messages/service.ts +++ b/apps/meteor/server/services/messages/service.ts @@ -6,12 +6,12 @@ import { Messages, Rooms } from '@rocket.chat/models'; import { deleteMessage } from '../../../app/lib/server/functions/deleteMessage'; import { sendMessage } from '../../../app/lib/server/functions/sendMessage'; import { updateMessage } from '../../../app/lib/server/functions/updateMessage'; +import { notifyOnMessageChange } from '../../../app/lib/server/lib/notifyListener'; import { executeSendMessage } from '../../../app/lib/server/methods/sendMessage'; import { executeSetReaction } from '../../../app/reactions/server/setReaction'; import { settings } from '../../../app/settings/server'; import { getUserAvatarURL } from '../../../app/utils/server/getUserAvatarURL'; import { BeforeSaveCannedResponse } from '../../../ee/server/hooks/messages/BeforeSaveCannedResponse'; -import { broadcastMessageFromData } from '../../modules/watchers/lib/messages'; import { BeforeSaveBadWords } from './hooks/BeforeSaveBadWords'; import { BeforeSaveCheckMAC } from './hooks/BeforeSaveCheckMAC'; import { BeforeSaveJumpToMessage } from './hooks/BeforeSaveJumpToMessage'; @@ -121,7 +121,7 @@ export class MessageService extends ServiceClassInternal implements IMessageServ Rooms.incMsgCountById(rid, 1), ]); - void broadcastMessageFromData({ + void notifyOnMessageChange({ id: result.insertedId, }); diff --git a/apps/meteor/server/services/video-conference/service.ts b/apps/meteor/server/services/video-conference/service.ts index f51ef8ec1c2f..a26e947b6b80 100644 --- a/apps/meteor/server/services/video-conference/service.ts +++ b/apps/meteor/server/services/video-conference/service.ts @@ -40,6 +40,7 @@ import { RocketChatAssets } from '../../../app/assets/server'; import { canAccessRoomIdAsync } from '../../../app/authorization/server/functions/canAccessRoom'; import { createRoom } from '../../../app/lib/server/functions/createRoom'; import { sendMessage } from '../../../app/lib/server/functions/sendMessage'; +import { notifyOnMessageChange } from '../../../app/lib/server/lib/notifyListener'; import { metrics } from '../../../app/metrics/server/lib/metrics'; import PushNotification from '../../../app/push-notifications/server/lib/PushNotification'; import { Push } from '../../../app/push/server/push'; @@ -55,7 +56,6 @@ import { isRoomCompatibleWithVideoConfRinging } from '../../lib/isRoomCompatible import { roomCoordinator } from '../../lib/rooms/roomCoordinator'; import { videoConfProviders } from '../../lib/videoConfProviders'; import { videoConfTypes } from '../../lib/videoConfTypes'; -import { broadcastMessageFromData } from '../../modules/watchers/lib/messages'; const { db } = MongoInternals.defaultRemoteCollectionDriver().mongo; @@ -360,7 +360,7 @@ export class VideoConfService extends ServiceClassInternal implements IVideoConf const text = i18n.t('video_livechat_missed', { username: name }); await Messages.setBlocksById(call.messages.started, [this.buildMessageBlock(text)]); - await broadcastMessageFromData({ + await notifyOnMessageChange({ id: call.messages.started, }); } diff --git a/apps/meteor/tests/unit/app/apps/server/messages.tests.js b/apps/meteor/tests/unit/app/apps/server/messages.tests.js index 2959820e0df9..04866f6440b6 100644 --- a/apps/meteor/tests/unit/app/apps/server/messages.tests.js +++ b/apps/meteor/tests/unit/app/apps/server/messages.tests.js @@ -18,6 +18,9 @@ const { AppMessagesConverter } = proxyquire.noCallThru().load('../../../../../ap Messages: new MessagesMock(), Users: new UsersMock(), }, + '@rocket.chat/core-typings': { + isMessageFromVisitor: (message) => 'token' in message, + }, }); describe('The AppMessagesConverter instance', () => { diff --git a/apps/meteor/tests/unit/server/modules/watchers/lib/messages.spec.ts b/apps/meteor/tests/unit/app/lib/server/lib/notifyListener.spec.ts similarity index 74% rename from apps/meteor/tests/unit/server/modules/watchers/lib/messages.spec.ts rename to apps/meteor/tests/unit/app/lib/server/lib/notifyListener.spec.ts index 5ef8bbdd1634..60b01dcefd12 100644 --- a/apps/meteor/tests/unit/server/modules/watchers/lib/messages.spec.ts +++ b/apps/meteor/tests/unit/app/lib/server/lib/notifyListener.spec.ts @@ -9,7 +9,7 @@ describe('Message Broadcast Tests', () => { let messagesFindOneStub: sinon.SinonStub; let broadcastStub: sinon.SinonStub; let getMessageToBroadcast: any; - let broadcastMessageFromData: any; + let notifyOnMessageChange: any; let memStub: sinon.SinonStub; const sampleMessage: IMessage = { @@ -49,18 +49,14 @@ describe('Message Broadcast Tests', () => { broadcastStub = sinon.stub(); memStub = sinon.stub().callsFake((fn: any) => fn); - const proxyMock = proxyquire.noCallThru().load('../../../../../../server/modules/watchers/lib/messages', { + const proxyMock = proxyquire.noPreserveCache().load('../../../../../../app/lib/server/lib/notifyListener', { '@rocket.chat/models': modelsStubs(), '@rocket.chat/core-services': coreStubs(false), 'mem': memStub, }); getMessageToBroadcast = proxyMock.getMessageToBroadcast; - broadcastMessageFromData = proxyMock.broadcastMessageFromData; - }); - - afterEach(() => { - sinon.reset(); + notifyOnMessageChange = proxyMock.notifyOnMessageChange; }); describe('getMessageToBroadcast', () => { @@ -77,12 +73,19 @@ describe('Message Broadcast Tests', () => { const testCases = [ { - description: 'should return undefined if message is hidden or imported', + description: 'should return undefined if message is hidden', message: { ...sampleMessage, _hidden: true }, hideSystemMessages: [], useRealName: false, expectedResult: undefined, }, + { + description: 'should return undefined if message is imported', + message: { ...sampleMessage, imported: true }, + hideSystemMessages: [], + useRealName: false, + expectedResult: undefined, + }, { description: 'should hide message if type is in hideSystemMessage settings', message: sampleMessage, @@ -97,6 +100,26 @@ describe('Message Broadcast Tests', () => { useRealName: true, expectedResult: { ...sampleMessage, u: { ...sampleMessage.u, name: 'Real User' } }, }, + { + description: 'should return the message with mentions real name if useRealName is true', + message: { + ...sampleMessage, + mentions: [ + { _id: 'mention1', username: 'mention1', name: 'Mention 1' }, + { _id: 'mention2', username: 'mention2', name: 'Mention 2' }, + ], + }, + hideSystemMessages: [], + useRealName: true, + expectedResult: { + ...sampleMessage, + u: { ...sampleMessage.u, name: 'Real User' }, + mentions: [ + { _id: 'mention1', username: 'mention1', name: 'Mention 1' }, + { _id: 'mention2', username: 'mention2', name: 'Mention 2' }, + ], + }, + }, { description: 'should return the message if Hide_System_Messages is undefined', message: sampleMessage, @@ -162,7 +185,12 @@ describe('Message Broadcast Tests', () => { getSettingValueByIdStub.withArgs('UI_Use_Real_Name').resolves(useRealName); if (useRealName) { - usersFindOneStub.resolves({ name: 'Real User' }); + const realNames = + message.mentions && message.mentions.length > 0 + ? [message.u.name, ...message.mentions.map((mention) => mention.name)] + : [message.u.name]; + + realNames.forEach((user, index) => usersFindOneStub.onCall(index).resolves({ name: user })); } const result = await getMessageToBroadcast({ id: '123' }); @@ -172,14 +200,14 @@ describe('Message Broadcast Tests', () => { }); }); - describe('broadcastMessageFromData', () => { + describe('notifyOnMessageChange', () => { const setupProxyMock = (dbWatchersDisabled: boolean) => { - const proxyMock = proxyquire.noCallThru().load('../../../../../../server/modules/watchers/lib/messages', { + const proxyMock = proxyquire.noCallThru().load('../../../../../../app/lib/server/lib/notifyListener', { '@rocket.chat/models': modelsStubs(), '@rocket.chat/core-services': coreStubs(dbWatchersDisabled), 'mem': memStub, }); - broadcastMessageFromData = proxyMock.broadcastMessageFromData; + notifyOnMessageChange = proxyMock.notifyOnMessageChange; }; const testCases = [ @@ -187,25 +215,33 @@ describe('Message Broadcast Tests', () => { description: 'should broadcast the message if dbWatchersDisabled is true', dbWatchersDisabled: true, expectBroadcast: true, + message: sampleMessage, }, { description: 'should not broadcast the message if dbWatchersDisabled is false', dbWatchersDisabled: false, expectBroadcast: false, + message: sampleMessage, + }, + { + description: 'should not broadcast the message if there is no data attributes', + dbWatchersDisabled: true, + expectBroadcast: false, + message: null, }, ]; - testCases.forEach(({ description, dbWatchersDisabled, expectBroadcast }) => { + testCases.forEach(({ description, dbWatchersDisabled, expectBroadcast, message }) => { it(description, async () => { setupProxyMock(dbWatchersDisabled); - messagesFindOneStub.resolves(sampleMessage); + messagesFindOneStub.resolves(message); getSettingValueByIdStub.resolves([]); - await broadcastMessageFromData({ id: '123', data: sampleMessage }); + await notifyOnMessageChange({ id: '123', data: message }); if (expectBroadcast) { expect(broadcastStub.calledOnce).to.be.true; - expect(broadcastStub.calledOnceWith('watch.messages', { message: sampleMessage })).to.be.true; + expect(broadcastStub.calledOnceWith('watch.messages', { message })).to.be.true; } else { expect(broadcastStub.called).to.be.false; }