diff --git a/apps/meteor/.mocharc.js b/apps/meteor/.mocharc.js index 47099a4401c6a..fb5324f4c0fd7 100644 --- a/apps/meteor/.mocharc.js +++ b/apps/meteor/.mocharc.js @@ -24,6 +24,7 @@ module.exports = { ...base, // see https://github.com/mochajs/mocha/issues/3916 exit: true, spec: [ + 'lib/callbacks.spec.ts', 'ee/server/lib/ldap/*.spec.ts', 'ee/tests/**/*.tests.ts', 'ee/tests/**/*.spec.ts', diff --git a/apps/meteor/app/authentication/server/startup/index.js b/apps/meteor/app/authentication/server/startup/index.js index f14bce0bc527d..e3af64ecc3808 100644 --- a/apps/meteor/app/authentication/server/startup/index.js +++ b/apps/meteor/app/authentication/server/startup/index.js @@ -156,7 +156,7 @@ const getLinkedInName = ({ firstName, lastName }) => { }; const onCreateUserAsync = async function (options, user = {}) { - callbacks.run('beforeCreateUser', options, user); + await callbacks.run('beforeCreateUser', options, user); user.status = 'offline'; user.active = user.active !== undefined ? user.active : !settings.get('Accounts_ManuallyApproveNewUsers'); @@ -216,7 +216,7 @@ const onCreateUserAsync = async function (options, user = {}) { await Mailer.send(email); } - callbacks.run('onCreateUser', options, user); + await callbacks.run('onCreateUser', options, user); // App IPostUserCreated event hook await Apps.triggerEvent(AppEvents.IPostUserCreated, { user, performedBy: await safeGetMeteorUser() }); @@ -321,7 +321,7 @@ Accounts.insertUserDoc = function (...args) { }; const validateLoginAttemptAsync = async function (login) { - login = callbacks.run('beforeValidateLogin', login); + login = await callbacks.run('beforeValidateLogin', login); if (!(await isValidLoginAttemptByIp(getClientAddress(login.connection)))) { throw new Meteor.Error('error-login-blocked-for-ip', 'Login has been temporarily blocked For IP', { @@ -368,7 +368,7 @@ const validateLoginAttemptAsync = async function (login) { } } - login = callbacks.run('onValidateLogin', login); + login = await callbacks.run('onValidateLogin', login); await Users.updateLastLoginById(login.user._id); setImmediate(function () { diff --git a/apps/meteor/app/channel-settings/server/functions/saveRoomName.js b/apps/meteor/app/channel-settings/server/functions/saveRoomName.js index 4973ee8da8c26..26c901cd41b51 100644 --- a/apps/meteor/app/channel-settings/server/functions/saveRoomName.js +++ b/apps/meteor/app/channel-settings/server/functions/saveRoomName.js @@ -56,6 +56,6 @@ export async function saveRoomName(rid, displayName, user, sendMessage = true) { if (sendMessage) { await Message.saveSystemMessage('r', rid, displayName, user); } - callbacks.run('afterRoomNameChange', { rid, name: displayName, oldName: room.name }); + await callbacks.run('afterRoomNameChange', { rid, name: displayName, oldName: room.name }); return displayName; } diff --git a/apps/meteor/app/channel-settings/server/functions/saveRoomTopic.ts b/apps/meteor/app/channel-settings/server/functions/saveRoomTopic.ts index 328275b32b473..2db467582029c 100644 --- a/apps/meteor/app/channel-settings/server/functions/saveRoomTopic.ts +++ b/apps/meteor/app/channel-settings/server/functions/saveRoomTopic.ts @@ -24,6 +24,6 @@ export const saveRoomTopic = async function ( if (update && sendMessage) { await Message.saveSystemMessage('room_changed_topic', rid, roomTopic || '', user); } - callbacks.run('afterRoomTopicChange', { rid, topic: roomTopic }); + await callbacks.run('afterRoomTopicChange', { rid, topic: roomTopic }); return update; }; diff --git a/apps/meteor/app/cloud/server/functions/getWorkspaceLicense.ts b/apps/meteor/app/cloud/server/functions/getWorkspaceLicense.ts index 9453d86be4b8d..9e2774be2fb7d 100644 --- a/apps/meteor/app/cloud/server/functions/getWorkspaceLicense.ts +++ b/apps/meteor/app/cloud/server/functions/getWorkspaceLicense.ts @@ -10,10 +10,10 @@ import { SystemLogger } from '../../../../server/lib/logger/system'; export async function getWorkspaceLicense(): Promise<{ updated: boolean; license: string }> { const currentLicense = await Settings.findOne('Cloud_Workspace_License'); - const cachedLicenseReturn = () => { + const cachedLicenseReturn = async () => { const license = currentLicense?.value as string; if (license) { - callbacks.run('workspaceLicenseChanged', license); + await callbacks.run('workspaceLicenseChanged', license); } return { updated: false, license }; @@ -62,7 +62,7 @@ export async function getWorkspaceLicense(): Promise<{ updated: boolean; license await Settings.updateValueById('Cloud_Workspace_License', remoteLicense.license); - callbacks.run('workspaceLicenseChanged', remoteLicense.license); + await callbacks.run('workspaceLicenseChanged', remoteLicense.license); return { updated: true, license: remoteLicense.license }; } diff --git a/apps/meteor/app/cloud/server/functions/saveRegistrationData.js b/apps/meteor/app/cloud/server/functions/saveRegistrationData.js index f9f5e3c05a9dd..6455678ce5b9b 100644 --- a/apps/meteor/app/cloud/server/functions/saveRegistrationData.js +++ b/apps/meteor/app/cloud/server/functions/saveRegistrationData.js @@ -22,8 +22,8 @@ export function saveRegistrationData({ Settings.updateValueById('Cloud_Workspace_PublicKey', publicKey), Settings.updateValueById('Cloud_Workspace_Registration_Client_Uri', registration_client_uri), Settings.updateValueById('Cloud_Workspace_License', licenseData.license || ''), - ]).then((...results) => { - callbacks.run('workspaceLicenseChanged', licenseData.license); + ]).then(async (...results) => { + await callbacks.run('workspaceLicenseChanged', licenseData.license); return results; }); } diff --git a/apps/meteor/app/custom-oauth/server/custom_oauth_server.js b/apps/meteor/app/custom-oauth/server/custom_oauth_server.js index b5350f04b5365..fbd2f721c3be9 100644 --- a/apps/meteor/app/custom-oauth/server/custom_oauth_server.js +++ b/apps/meteor/app/custom-oauth/server/custom_oauth_server.js @@ -341,7 +341,7 @@ export class CustomOAuth { return; } - callbacks.run('afterProcessOAuthUser', { serviceName, serviceData, user }); + await callbacks.run('afterProcessOAuthUser', { serviceName, serviceData, user }); // User already created or merged and has identical name as before if ( @@ -437,7 +437,7 @@ const updateOrCreateUserFromExternalServiceAsync = async function (...args /* se const user = updateOrCreateUserFromExternalService.apply(this, args); - callbacks.run('afterValidateNewOAuthUser', { + await callbacks.run('afterValidateNewOAuthUser', { identity: serviceData, serviceName, user: await Users.findOneById(user.userId), diff --git a/apps/meteor/app/lib/client/methods/sendMessage.ts b/apps/meteor/app/lib/client/methods/sendMessage.ts index 75a6c843bad7c..58b645b41220c 100644 --- a/apps/meteor/app/lib/client/methods/sendMessage.ts +++ b/apps/meteor/app/lib/client/methods/sendMessage.ts @@ -41,7 +41,7 @@ Meteor.methods({ return; } - message = callbacks.run('beforeSaveMessage', message); + message = await callbacks.run('beforeSaveMessage', message); await onClientMessageReceived(message as IMessage).then(function (message) { ChatMessage.insert(message); return callbacks.run('afterSaveMessage', message); diff --git a/apps/meteor/app/lib/server/functions/addUserToDefaultChannels.ts b/apps/meteor/app/lib/server/functions/addUserToDefaultChannels.ts index 998aaa17ffcf2..7f3db9315c2cc 100644 --- a/apps/meteor/app/lib/server/functions/addUserToDefaultChannels.ts +++ b/apps/meteor/app/lib/server/functions/addUserToDefaultChannels.ts @@ -5,7 +5,7 @@ import { Message } from '@rocket.chat/core-services'; import { callbacks } from '../../../../lib/callbacks'; export const addUserToDefaultChannels = async function (user: IUser, silenced?: boolean): Promise { - callbacks.run('beforeJoinDefaultChannels', user); + await callbacks.run('beforeJoinDefaultChannels', user); const defaultRooms = await Rooms.findByDefaultAndTypes(true, ['c', 'p'], { projection: { usernames: 0 }, }).toArray(); diff --git a/apps/meteor/app/lib/server/functions/addUserToRoom.ts b/apps/meteor/app/lib/server/functions/addUserToRoom.ts index 914faf775c431..065ef9800e73d 100644 --- a/apps/meteor/app/lib/server/functions/addUserToRoom.ts +++ b/apps/meteor/app/lib/server/functions/addUserToRoom.ts @@ -34,7 +34,7 @@ export const addUserToRoom = async function ( } try { - callbacks.run('federation.beforeAddUserToARoom', { user, inviter }, room); + await callbacks.run('federation.beforeAddUserToARoom', { user, inviter }, room); } catch (error) { throw new Meteor.Error((error as any)?.message); } @@ -57,10 +57,10 @@ export const addUserToRoom = async function ( if (room.t === 'c' || room.t === 'p' || room.t === 'l') { // Add a new event, with an optional inviter - callbacks.run('beforeAddedToRoom', { user: userToBeAdded, inviter }, room); + await callbacks.run('beforeAddedToRoom', { user: userToBeAdded, inviter }, room); // Keep the current event - callbacks.run('beforeJoinRoom', userToBeAdded, room); + await callbacks.run('beforeJoinRoom', userToBeAdded, room); } await Apps.triggerEvent(AppEvents.IPreRoomUserJoined, room, userToBeAdded, inviter).catch((error) => { if (error.name === AppsEngineException.name) { @@ -107,12 +107,12 @@ export const addUserToRoom = async function ( } if (room.t === 'c' || room.t === 'p') { - process.nextTick(function () { + process.nextTick(async function () { // Add a new event, with an optional inviter - callbacks.run('afterAddedToRoom', { user: userToBeAdded, inviter }, room); + await callbacks.run('afterAddedToRoom', { user: userToBeAdded, inviter }, room); // Keep the current event - callbacks.run('afterJoinRoom', userToBeAdded, room); + await callbacks.run('afterJoinRoom', userToBeAdded, room); void Apps.triggerEvent(AppEvents.IPostRoomUserJoined, room, userToBeAdded, inviter); }); diff --git a/apps/meteor/app/lib/server/functions/archiveRoom.ts b/apps/meteor/app/lib/server/functions/archiveRoom.ts index 5174459fba81a..ad3487465682e 100644 --- a/apps/meteor/app/lib/server/functions/archiveRoom.ts +++ b/apps/meteor/app/lib/server/functions/archiveRoom.ts @@ -9,5 +9,5 @@ export const archiveRoom = async function (rid: string, user: IMessage['u']): Pr await Subscriptions.archiveByRoomId(rid); await Message.saveSystemMessage('room-archived', rid, '', user); - callbacks.run('afterRoomArchived', await Rooms.findOneById(rid), user); + await callbacks.run('afterRoomArchived', await Rooms.findOneById(rid), user); }; diff --git a/apps/meteor/app/lib/server/functions/createDirectRoom.ts b/apps/meteor/app/lib/server/functions/createDirectRoom.ts index 68553909c6caa..37c615820dc00 100644 --- a/apps/meteor/app/lib/server/functions/createDirectRoom.ts +++ b/apps/meteor/app/lib/server/functions/createDirectRoom.ts @@ -50,7 +50,7 @@ export async function createDirectRoom( if (members.length > (settings.get('DirectMesssage_maxUsers') || 1)) { throw new Error('error-direct-message-max-user-exceeded'); } - callbacks.run('beforeCreateDirectRoom', members); + await callbacks.run('beforeCreateDirectRoom', members); const membersUsernames: string[] = members .map((member) => { @@ -159,7 +159,7 @@ export async function createDirectRoom( if (isNewRoom) { const insertedRoom = await Rooms.findOneById(rid); - callbacks.run('afterCreateDirectRoom', insertedRoom, { members: roomMembers, creatorId: options?.creator }); + await callbacks.run('afterCreateDirectRoom', insertedRoom, { members: roomMembers, creatorId: options?.creator }); void Apps.triggerEvent('IPostRoomCreate', insertedRoom); } diff --git a/apps/meteor/app/lib/server/functions/createRoom.ts b/apps/meteor/app/lib/server/functions/createRoom.ts index 9793f3cfaa3ba..85ef146defb20 100644 --- a/apps/meteor/app/lib/server/functions/createRoom.ts +++ b/apps/meteor/app/lib/server/functions/createRoom.ts @@ -33,7 +33,7 @@ export const createRoom = async ( } > => { const { teamId, ...extraData } = roomExtraData || ({} as IRoom); - callbacks.run('beforeCreateRoom', { type, name, owner: ownerUsername, members, readOnly, extraData, options }); + await callbacks.run('beforeCreateRoom', { type, name, owner: ownerUsername, members, readOnly, extraData, options }); if (type === 'd') { return createDirectRoom(members as IUser[], extraData, { ...options, creator: options?.creator || ownerUsername }); } @@ -126,7 +126,7 @@ export const createRoom = async ( } if (type === 'c') { - callbacks.run('beforeCreateChannel', owner, roomProps); + await callbacks.run('beforeCreateChannel', owner, roomProps); } const room = await Rooms.createWithFullRoomData(roomProps); const shouldBeHandledByFederation = room.federated === true || ownerUsername.includes(':'); @@ -150,7 +150,7 @@ export const createRoom = async ( } try { - callbacks.run('federation.beforeAddUserToARoom', { user: member, inviter: owner }, room); + await callbacks.run('federation.beforeAddUserToARoom', { user: member, inviter: owner }, room); } catch (error) { continue; } @@ -180,7 +180,7 @@ export const createRoom = async ( await Message.saveSystemMessage('user-added-room-to-team', team.roomId, room.name || '', owner); } } - callbacks.run('afterCreateChannel', owner, room); + await callbacks.run('afterCreateChannel', owner, room); } else if (type === 'p') { callbacks.runAsync('afterCreatePrivateGroup', owner, room); } diff --git a/apps/meteor/app/lib/server/functions/deleteMessage.ts b/apps/meteor/app/lib/server/functions/deleteMessage.ts index 0a1dcd85ed3d7..e3d078203559d 100644 --- a/apps/meteor/app/lib/server/functions/deleteMessage.ts +++ b/apps/meteor/app/lib/server/functions/deleteMessage.ts @@ -50,7 +50,7 @@ export async function deleteMessage(message: IMessage, user: IUser): Promise 0) { message.tokens.forEach((token) => { token.text = token.text.replace(/([^\$])(\$[^\$])/gm, '$1$$$2'); diff --git a/apps/meteor/app/lib/server/functions/notifications/index.ts b/apps/meteor/app/lib/server/functions/notifications/index.ts index ca464e2e998a2..cf14355c16bd6 100644 --- a/apps/meteor/app/lib/server/functions/notifications/index.ts +++ b/apps/meteor/app/lib/server/functions/notifications/index.ts @@ -12,7 +12,7 @@ import { settings } from '../../../../settings/server'; * * @param {object} message the message to be parsed */ -export function parseMessageTextPerUser(messageText: string, message: IMessage, receiver: IUser): string { +export async function parseMessageTextPerUser(messageText: string, message: IMessage, receiver: IUser): Promise { const lng = receiver.language || settings.get('Language') || 'en'; const firstAttachment = message.attachments?.[0]; diff --git a/apps/meteor/app/lib/server/functions/removeUserFromRoom.ts b/apps/meteor/app/lib/server/functions/removeUserFromRoom.ts index 1cde25fcccc4e..bca939bc520b1 100644 --- a/apps/meteor/app/lib/server/functions/removeUserFromRoom.ts +++ b/apps/meteor/app/lib/server/functions/removeUserFromRoom.ts @@ -29,7 +29,7 @@ export const removeUserFromRoom = async function ( throw error; } - callbacks.run('beforeLeaveRoom', user, room); + await callbacks.run('beforeLeaveRoom', user, room); const subscription = await Subscriptions.findOneByRoomIdAndUserId(rid, user._id, { projection: { _id: 1 }, @@ -65,7 +65,7 @@ export const removeUserFromRoom = async function ( } // TODO: CACHE: maybe a queue? - callbacks.run('afterLeaveRoom', user, room); + await callbacks.run('afterLeaveRoom', user, room); await Apps.triggerEvent(AppEvents.IPostRoomUserLeave, room, user); }; diff --git a/apps/meteor/app/lib/server/functions/saveUser.js b/apps/meteor/app/lib/server/functions/saveUser.js index 6e254772bd402..66bbf90ca5044 100644 --- a/apps/meteor/app/lib/server/functions/saveUser.js +++ b/apps/meteor/app/lib/server/functions/saveUser.js @@ -108,7 +108,7 @@ async function validateUserData(userId, userData) { } if (userData.roles) { - callbacks.run('validateUserRoles', userData); + await callbacks.run('validateUserRoles', userData); } let nameValidation; @@ -419,7 +419,7 @@ export const saveUser = async function (userId, userData) { await Users.updateOne({ _id: userData._id }, updateUser); - callbacks.run('afterSaveUser', userData); + await callbacks.run('afterSaveUser', userData); // App IPostUserUpdated event hook const userUpdated = await Users.findOneById(userId); diff --git a/apps/meteor/app/lib/server/functions/sendMessage.js b/apps/meteor/app/lib/server/functions/sendMessage.js index 88ae2cd544f52..7f75cb36e2a60 100644 --- a/apps/meteor/app/lib/server/functions/sendMessage.js +++ b/apps/meteor/app/lib/server/functions/sendMessage.js @@ -238,7 +238,7 @@ export const sendMessage = async function (user, message, room, upsert = false) parseUrlsInMessage(message); - message = callbacks.run('beforeSaveMessage', message, room); + message = await callbacks.run('beforeSaveMessage', message, room); if (message) { if (message.t === 'otr') { const otrStreamer = notifications.streamRoomMessage; diff --git a/apps/meteor/app/lib/server/functions/setUserActiveStatus.ts b/apps/meteor/app/lib/server/functions/setUserActiveStatus.ts index f6f140842f903..2f168503dd58d 100644 --- a/apps/meteor/app/lib/server/functions/setUserActiveStatus.ts +++ b/apps/meteor/app/lib/server/functions/setUserActiveStatus.ts @@ -85,17 +85,17 @@ export async function setUserActiveStatus(userId: string, active: boolean, confi } if (active && !user.active) { - callbacks.run('beforeActivateUser', user); + await callbacks.run('beforeActivateUser', user); } await Users.setUserActive(userId, active); if (active && !user.active) { - callbacks.run('afterActivateUser', user); + await callbacks.run('afterActivateUser', user); } if (!active && user.active) { - callbacks.run('afterDeactivateUser', user); + await callbacks.run('afterDeactivateUser', user); } if (user.username) { diff --git a/apps/meteor/app/lib/server/functions/updateMessage.ts b/apps/meteor/app/lib/server/functions/updateMessage.ts index 33fcd08ff7f6d..83fdd40012145 100644 --- a/apps/meteor/app/lib/server/functions/updateMessage.ts +++ b/apps/meteor/app/lib/server/functions/updateMessage.ts @@ -43,7 +43,7 @@ export const updateMessage = async function (message: IMessage, user: IUser, ori parseUrlsInMessage(message); - message = callbacks.run('beforeSaveMessage', message); + message = await callbacks.run('beforeSaveMessage', message); const { _id, ...editedMessage } = message; @@ -77,7 +77,7 @@ export const updateMessage = async function (message: IMessage, user: IUser, ori setImmediate(async function () { const msg = await Messages.findOneById(_id); if (msg) { - callbacks.run('afterSaveMessage', msg, room, user._id); + await callbacks.run('afterSaveMessage', msg, room, user._id); } }); }; diff --git a/apps/meteor/app/lib/server/lib/notifyUsersOnMessage.js b/apps/meteor/app/lib/server/lib/notifyUsersOnMessage.js index af099b3e17dd9..8ee81de0f44f3 100644 --- a/apps/meteor/app/lib/server/lib/notifyUsersOnMessage.js +++ b/apps/meteor/app/lib/server/lib/notifyUsersOnMessage.js @@ -24,7 +24,7 @@ function messageContainsHighlight(message, highlights) { }); } -export function getMentions(message) { +export async function getMentions(message) { const { mentions, u: { _id: senderId }, @@ -46,7 +46,7 @@ export function getMentions(message) { const filteredMentions = userMentions.filter(({ _id }) => _id !== senderId && !['all', 'here'].includes(_id)).map(({ _id }) => _id); - const mentionIds = callbacks.run('beforeGetMentions', filteredMentions, { + const mentionIds = await callbacks.run('beforeGetMentions', filteredMentions, { userMentions, otherMentions, message, @@ -107,7 +107,7 @@ const getUnreadSettingCount = (roomType) => { async function updateUsersSubscriptions(message, room) { // Don't increase unread counter on thread messages if (room != null && !message.tmid) { - const { toAll, toHere, mentionIds } = getMentions(message); + const { toAll, toHere, mentionIds } = await getMentions(message); const userIds = new Set(mentionIds); diff --git a/apps/meteor/app/lib/server/lib/sendNotificationsOnMessage.js b/apps/meteor/app/lib/server/lib/sendNotificationsOnMessage.js index e91bef101de62..d34322f4ceb9e 100644 --- a/apps/meteor/app/lib/server/lib/sendNotificationsOnMessage.js +++ b/apps/meteor/app/lib/server/lib/sendNotificationsOnMessage.js @@ -73,7 +73,7 @@ export const sendNotification = async ({ const isThread = !!message.tmid && !message.tshow; - notificationMessage = parseMessageTextPerUser(notificationMessage, message, receiver); + notificationMessage = await parseMessageTextPerUser(notificationMessage, message, receiver); const isHighlighted = messageContainsHighlight(message, subscription.userHighlights); @@ -221,7 +221,7 @@ export async function sendMessageNotifications(message, room, usersInThread = [] return message; } - const { toAll: hasMentionToAll, toHere: hasMentionToHere, mentionIds } = getMentions(message); + const { toAll: hasMentionToAll, toHere: hasMentionToHere, mentionIds } = await getMentions(message); const mentionIdsWithoutGroups = [...mentionIds]; @@ -236,7 +236,7 @@ export async function sendMessageNotifications(message, room, usersInThread = [] // add users in thread to mentions array because they follow the same rules mentionIds.push(...usersInThread); - let notificationMessage = callbacks.run('beforeSendMessageNotifications', message.msg); + let notificationMessage = await callbacks.run('beforeSendMessageNotifications', message.msg); if (mentionIds.length > 0 && settings.get('UI_Use_Real_Name')) { notificationMessage = replaceMentionedUsernamesWithFullNames(message.msg, message.mentions); } diff --git a/apps/meteor/app/lib/server/methods/addUsersToRoom.ts b/apps/meteor/app/lib/server/methods/addUsersToRoom.ts index 151c6f2da34ab..69a879d07525b 100644 --- a/apps/meteor/app/lib/server/methods/addUsersToRoom.ts +++ b/apps/meteor/app/lib/server/methods/addUsersToRoom.ts @@ -82,7 +82,7 @@ Meteor.methods({ // Validate each user, then add to room const user = ((await Meteor.userAsync()) as IUser | null) ?? undefined; if (isRoomFederated(room)) { - callbacks.run('federation.onAddUsersToARoom', { invitees: data.users, inviter: user }, room); + await callbacks.run('federation.onAddUsersToARoom', { invitees: data.users, inviter: user }, room); return true; } diff --git a/apps/meteor/app/livechat/server/api/lib/departments.ts b/apps/meteor/app/livechat/server/api/lib/departments.ts index 468f581f70ec0..6d9ebb9c8c254 100644 --- a/apps/meteor/app/livechat/server/api/lib/departments.ts +++ b/apps/meteor/app/livechat/server/api/lib/departments.ts @@ -55,7 +55,7 @@ export async function findDepartments({ }; if (onlyMyDepartments) { - query = callbacks.run('livechat.applyDepartmentRestrictions', query, { userId }); + query = await callbacks.run('livechat.applyDepartmentRestrictions', query, { userId }); } const { cursor, totalCount } = LivechatDepartment.findPaginated(query, { @@ -89,7 +89,7 @@ export async function findArchivedDepartments({ }; if (onlyMyDepartments) { - query = callbacks.run('livechat.applyDepartmentRestrictions', query, { userId }); + query = await callbacks.run('livechat.applyDepartmentRestrictions', query, { userId }); } const { cursor, totalCount } = LivechatDepartment.findPaginated(query, { @@ -122,7 +122,7 @@ export async function findDepartmentById({ let query = { _id: departmentId }; if (onlyMyDepartments) { - query = callbacks.run('livechat.applyDepartmentRestrictions', query, { userId }); + query = await callbacks.run('livechat.applyDepartmentRestrictions', query, { userId }); } const result = { @@ -146,7 +146,7 @@ export async function findDepartmentsToAutocomplete({ let { conditions = {} } = selector; if (onlyMyDepartments) { - conditions = callbacks.run('livechat.applyDepartmentRestrictions', conditions, { userId: uid }); + conditions = await callbacks.run('livechat.applyDepartmentRestrictions', conditions, { userId: uid }); } const conditionsWithArchived = { archived: { $ne: !showArchived }, ...conditions }; diff --git a/apps/meteor/app/livechat/server/api/lib/livechat.ts b/apps/meteor/app/livechat/server/api/lib/livechat.ts index 2efb891956c7d..b3f72ad3de9b4 100644 --- a/apps/meteor/app/livechat/server/api/lib/livechat.ts +++ b/apps/meteor/app/livechat/server/api/lib/livechat.ts @@ -217,6 +217,6 @@ export async function getExtraConfigInfo(room?: IOmnichannelRoom): Promise } // TODO: please forgive me for this. Still finding the good types for these callbacks -export function onCheckRoomParams(params: any): any { +export function onCheckRoomParams(params: any): Promise { return callbacks.run('livechat.onCheckRoomApiParams', params); } diff --git a/apps/meteor/app/livechat/server/api/v1/room.ts b/apps/meteor/app/livechat/server/api/v1/room.ts index 01e5ff5026854..968a2bbbc3e18 100644 --- a/apps/meteor/app/livechat/server/api/v1/room.ts +++ b/apps/meteor/app/livechat/server/api/v1/room.ts @@ -37,13 +37,13 @@ const isAgentWithInfo = (agentObj: ILivechatAgent | { hiddenInfo: true }): agent API.v1.addRoute('livechat/room', { async get() { // I'll temporary use check for validation, as validateParams doesnt support what's being done here - const extraCheckParams = onCheckRoomParams({ + const extraCheckParams = await onCheckRoomParams({ token: String, rid: Match.Maybe(String), agentId: Match.Maybe(String), }); - check(this.queryParams, extraCheckParams); + check(this.queryParams, extraCheckParams as any); const { token, rid: roomId, agentId, ...extraParams } = this.queryParams; @@ -447,7 +447,7 @@ API.v1.addRoute( await Promise.allSettled([Livechat.saveGuest(guestData, this.userId), Livechat.saveRoomInfo(roomData)]); - callbacks.run('livechat.saveInfo', await LivechatRooms.findOneById(roomData._id), { + await callbacks.run('livechat.saveInfo', await LivechatRooms.findOneById(roomData._id), { user: this.user, oldRoom: room, }); diff --git a/apps/meteor/app/livechat/server/business-hour/index.ts b/apps/meteor/app/livechat/server/business-hour/index.ts index e8af0f1c97a46..e6259059463f3 100644 --- a/apps/meteor/app/livechat/server/business-hour/index.ts +++ b/apps/meteor/app/livechat/server/business-hour/index.ts @@ -9,8 +9,8 @@ import { DefaultBusinessHour } from './Default'; export const businessHourManager = new BusinessHourManager(cronJobs); -Meteor.startup(() => { - const { BusinessHourBehaviorClass } = callbacks.run('on-business-hour-start', { +Meteor.startup(async () => { + const { BusinessHourBehaviorClass } = await callbacks.run('on-business-hour-start', { BusinessHourBehaviorClass: SingleBusinessHourBehavior, }); businessHourManager.registerBusinessHourBehavior(new BusinessHourBehaviorClass()); diff --git a/apps/meteor/app/livechat/server/hooks/leadCapture.ts b/apps/meteor/app/livechat/server/hooks/leadCapture.ts index 39f1936db9035..74d3a677d1109 100644 --- a/apps/meteor/app/livechat/server/hooks/leadCapture.ts +++ b/apps/meteor/app/livechat/server/hooks/leadCapture.ts @@ -49,7 +49,7 @@ callbacks.add( if (msgEmails || msgPhones) { await LivechatVisitors.saveGuestEmailPhoneById(room.v._id, msgEmails, msgPhones); - callbacks.run('livechat.leadCapture', room); + await callbacks.run('livechat.leadCapture', room); } return message; diff --git a/apps/meteor/app/livechat/server/lib/Departments.ts b/apps/meteor/app/livechat/server/lib/Departments.ts index fbfd5060a5414..349af6bd227d4 100644 --- a/apps/meteor/app/livechat/server/lib/Departments.ts +++ b/apps/meteor/app/livechat/server/lib/Departments.ts @@ -46,7 +46,7 @@ class DepartmentHelperClass { this.logger.debug(`Post-department-removal actions completed: ${_id}. Notifying callbacks with department and agentsIds`); setImmediate(() => { - callbacks.run('livechat.afterRemoveDepartment', { department, agentsIds }); + void callbacks.run('livechat.afterRemoveDepartment', { department, agentsIds }); }); return ret; diff --git a/apps/meteor/app/livechat/server/lib/Helper.js b/apps/meteor/app/livechat/server/lib/Helper.js index 51626275a4553..c0be5a88490a0 100644 --- a/apps/meteor/app/livechat/server/lib/Helper.js +++ b/apps/meteor/app/livechat/server/lib/Helper.js @@ -54,7 +54,7 @@ export const createLivechatRoom = async (rid, name, guest, roomInfo = {}, extraD }), ); - const extraRoomInfo = callbacks.run('livechat.beforeRoom', roomInfo, extraData); + const extraRoomInfo = await callbacks.run('livechat.beforeRoom', roomInfo, extraData); const { _id, username, token, department: departmentId, status = 'online' } = guest; const newRoomAt = new Date(); @@ -96,7 +96,7 @@ export const createLivechatRoom = async (rid, name, guest, roomInfo = {}, extraD const roomId = (await Rooms.insertOne(room)).insertedId; Apps.triggerEvent(AppEvents.IPostLivechatRoomStarted, room); - callbacks.run('livechat.newRoom', room); + await callbacks.run('livechat.newRoom', room); await sendMessage(guest, { t: 'livechat-started', msg: '', groupable: false }, room); @@ -122,7 +122,7 @@ export const createLivechatInquiry = async ({ rid, name, guest, message, initial }), ); - const extraInquiryInfo = callbacks.run('livechat.beforeInquiry', extraData); + const extraInquiryInfo = await callbacks.run('livechat.beforeInquiry', extraData); const { _id, username, token, department, status = 'online' } = guest; const { msg } = message; @@ -398,7 +398,7 @@ export const forwardRoomToAgent = async (room, transferData) => { } logger.debug(`Inquiry ${inquiry._id} taken by agent ${agent._id}`); - callbacks.run('livechat.afterForwardChatToAgent', { rid, servedBy, oldServedBy }); + await callbacks.run('livechat.afterForwardChatToAgent', { rid, servedBy, oldServedBy }); return true; }; @@ -429,7 +429,7 @@ export const forwardRoomToDepartment = async (room, guest, transferData) => { } logger.debug(`Attempting to forward room ${room._id} to department ${transferData.departmentId}`); - callbacks.run('livechat.beforeForwardRoomToDepartment', { room, transferData }); + await callbacks.run('livechat.beforeForwardRoomToDepartment', { room, transferData }); const { _id: rid, servedBy: oldServedBy, departmentId: oldDepartmentId } = room; let agent = null; diff --git a/apps/meteor/app/livechat/server/lib/Livechat.js b/apps/meteor/app/livechat/server/lib/Livechat.js index 04841972f68b9..807757f176fab 100644 --- a/apps/meteor/app/livechat/server/lib/Livechat.js +++ b/apps/meteor/app/livechat/server/lib/Livechat.js @@ -180,7 +180,7 @@ export const Livechat = { } if (room == null) { - const defaultAgent = callbacks.run('livechat.checkDefaultAgentOnNewRoom', agent, guest); + const defaultAgent = await callbacks.run('livechat.checkDefaultAgentOnNewRoom', agent, guest); // if no department selected verify if there is at least one active and pick the first if (!defaultAgent && !guest.department) { const department = await this.getRequiredDepartment(); diff --git a/apps/meteor/app/livechat/server/lib/LivechatTyped.ts b/apps/meteor/app/livechat/server/lib/LivechatTyped.ts index 06933cf470f02..aa06c7b773ffc 100644 --- a/apps/meteor/app/livechat/server/lib/LivechatTyped.ts +++ b/apps/meteor/app/livechat/server/lib/LivechatTyped.ts @@ -324,7 +324,7 @@ class LivechatClass { await this.sendEmail(emailFromRegexp, email, emailFromRegexp, mailSubject, html); setImmediate(() => { - callbacks.run('livechat.sendTranscript', messages, email); + void callbacks.run('livechat.sendTranscript', messages, email); }); const requestData: IOmnichannelSystemMessage['requestData'] = { diff --git a/apps/meteor/app/livechat/server/lib/QueueManager.js b/apps/meteor/app/livechat/server/lib/QueueManager.js index 9a672a5d96000..62169cc4b0358 100644 --- a/apps/meteor/app/livechat/server/lib/QueueManager.js +++ b/apps/meteor/app/livechat/server/lib/QueueManager.js @@ -11,7 +11,7 @@ const logger = new Logger('QueueManager'); export const saveQueueInquiry = async (inquiry) => { await LivechatInquiry.queueInquiry(inquiry._id); - callbacks.run('livechat.afterInquiryQueued', inquiry); + await callbacks.run('livechat.afterInquiryQueued', inquiry); }; export const queueInquiry = async (room, inquiry, defaultAgent) => { diff --git a/apps/meteor/app/livechat/server/lib/RoutingManager.js b/apps/meteor/app/livechat/server/lib/RoutingManager.js index 0a79b06474744..5889261f5a1ba 100644 --- a/apps/meteor/app/livechat/server/lib/RoutingManager.js +++ b/apps/meteor/app/livechat/server/lib/RoutingManager.js @@ -226,7 +226,7 @@ export const RoutingManager = { async delegateAgent(agent, inquiry) { logger.debug(`Delegating Inquiry ${inquiry._id}`); - const defaultAgent = callbacks.run('livechat.beforeDelegateAgent', agent, { + const defaultAgent = await callbacks.run('livechat.beforeDelegateAgent', agent, { department: inquiry?.department, }); diff --git a/apps/meteor/app/livechat/server/lib/routing/AutoSelection.ts b/apps/meteor/app/livechat/server/lib/routing/AutoSelection.ts index ca95f8de968c1..1dd665c95b4c6 100644 --- a/apps/meteor/app/livechat/server/lib/routing/AutoSelection.ts +++ b/apps/meteor/app/livechat/server/lib/routing/AutoSelection.ts @@ -26,7 +26,7 @@ class AutoSelection implements IRoutingMethod { } async getNextAgent(department?: string, ignoreAgentId?: string): Promise { - const extraQuery = callbacks.run('livechat.applySimultaneousChatRestrictions', undefined, { + const extraQuery = await callbacks.run('livechat.applySimultaneousChatRestrictions', undefined, { ...(department ? { departmentId: department } : {}), }); if (department) { diff --git a/apps/meteor/app/livechat/server/methods/getDepartmentForwardRestrictions.ts b/apps/meteor/app/livechat/server/methods/getDepartmentForwardRestrictions.ts index d0c914e7fe244..b5712a57ae740 100644 --- a/apps/meteor/app/livechat/server/methods/getDepartmentForwardRestrictions.ts +++ b/apps/meteor/app/livechat/server/methods/getDepartmentForwardRestrictions.ts @@ -12,7 +12,7 @@ declare module '@rocket.chat/ui-contexts' { } Meteor.methods({ - 'livechat:getDepartmentForwardRestrictions'(departmentId) { + async 'livechat:getDepartmentForwardRestrictions'(departmentId) { methodDeprecationLogger.warn('livechat:getDepartmentForwardRestrictions will be deprecated in future versions of Rocket.Chat'); if (!Meteor.userId()) { throw new Meteor.Error('error-invalid-user', 'Invalid user', { @@ -20,7 +20,7 @@ Meteor.methods({ }); } - const options = callbacks.run('livechat.onLoadForwardDepartmentRestrictions', { departmentId }); + const options = await callbacks.run('livechat.onLoadForwardDepartmentRestrictions', { departmentId }); const { restrictions } = options; return restrictions; diff --git a/apps/meteor/app/livechat/server/methods/saveInfo.ts b/apps/meteor/app/livechat/server/methods/saveInfo.ts index c56f09efda36e..5d6d7e4c227c8 100644 --- a/apps/meteor/app/livechat/server/methods/saveInfo.ts +++ b/apps/meteor/app/livechat/server/methods/saveInfo.ts @@ -84,7 +84,7 @@ Meteor.methods({ const user = await Users.findOne({ _id: userId }, { projection: { _id: 1, username: 1 } }); setImmediate(async () => { - callbacks.run('livechat.saveInfo', await LivechatRooms.findOneById(roomData._id), { + void callbacks.run('livechat.saveInfo', await LivechatRooms.findOneById(roomData._id), { user, oldRoom: room, }); diff --git a/apps/meteor/app/message-pin/server/pinMessage.ts b/apps/meteor/app/message-pin/server/pinMessage.ts index b7819b304106e..83fb2cae2fd97 100644 --- a/apps/meteor/app/message-pin/server/pinMessage.ts +++ b/apps/meteor/app/message-pin/server/pinMessage.ts @@ -110,7 +110,7 @@ Meteor.methods({ username: me.username, }; - originalMessage = callbacks.run('beforeSaveMessage', originalMessage); + originalMessage = await callbacks.run('beforeSaveMessage', originalMessage); await Messages.setPinnedByIdAndUserId(originalMessage._id, originalMessage.pinnedBy, originalMessage.pinned); if (isTheLastMessage(room, message)) { @@ -200,7 +200,7 @@ Meteor.methods({ _id: userId, username: me.username, }; - originalMessage = callbacks.run('beforeSaveMessage', originalMessage); + originalMessage = await callbacks.run('beforeSaveMessage', originalMessage); const room = await Rooms.findOneById(originalMessage.rid, { projection: { ...roomAccessAttributes, lastMessage: 1 } }); if (!room) { diff --git a/apps/meteor/app/oembed/server/server.ts b/apps/meteor/app/oembed/server/server.ts index c65587930377c..51702700ba109 100644 --- a/apps/meteor/app/oembed/server/server.ts +++ b/apps/meteor/app/oembed/server/server.ts @@ -93,7 +93,7 @@ const getUrlContent = async function (urlObjStr: string | URL.UrlWithStringQuery throw new Error('invalid/unsafe port'); } - const data = callbacks.run('oembed:beforeGetUrlContent', { + const data = await callbacks.run('oembed:beforeGetUrlContent', { urlObj, parsedUrl, }); diff --git a/apps/meteor/app/push-notifications/server/lib/PushNotification.ts b/apps/meteor/app/push-notifications/server/lib/PushNotification.ts index 4aadedf2765cf..1925b59dc66a0 100644 --- a/apps/meteor/app/push-notifications/server/lib/PushNotification.ts +++ b/apps/meteor/app/push-notifications/server/lib/PushNotification.ts @@ -128,11 +128,11 @@ class PushNotification { throw new Error('Message sender not found'); } - let notificationMessage = callbacks.run('beforeSendMessageNotifications', message.msg); + let notificationMessage = await callbacks.run('beforeSendMessageNotifications', message.msg); if (message.mentions && Object.keys(message.mentions).length > 0 && settings.get('UI_Use_Real_Name')) { notificationMessage = replaceMentionedUsernamesWithFullNames(message.msg, message.mentions); } - notificationMessage = parseMessageTextPerUser(notificationMessage, message, receiver); + notificationMessage = await parseMessageTextPerUser(notificationMessage, message, receiver); const pushData = await getPushData({ room, diff --git a/apps/meteor/app/reactions/client/methods/setReaction.ts b/apps/meteor/app/reactions/client/methods/setReaction.ts index a2f5c6ced2138..ddf301ff55498 100644 --- a/apps/meteor/app/reactions/client/methods/setReaction.ts +++ b/apps/meteor/app/reactions/client/methods/setReaction.ts @@ -55,10 +55,10 @@ Meteor.methods({ if (!message.reactions || typeof message.reactions !== 'object' || Object.keys(message.reactions).length === 0) { delete message.reactions; Messages.update({ _id: messageId }, { $unset: { reactions: 1 } }); - callbacks.run('unsetReaction', messageId, reaction); + await callbacks.run('unsetReaction', messageId, reaction); } else { Messages.update({ _id: messageId }, { $set: { reactions: message.reactions } }); - callbacks.run('setReaction', messageId, reaction); + await callbacks.run('setReaction', messageId, reaction); } } else { if (!message.reactions) { @@ -72,7 +72,7 @@ Meteor.methods({ message.reactions[reaction].usernames.push(user.username); Messages.update({ _id: messageId }, { $set: { reactions: message.reactions } }); - callbacks.run('setReaction', messageId, reaction); + await callbacks.run('setReaction', messageId, reaction); } }, }); diff --git a/apps/meteor/app/reactions/server/setReaction.ts b/apps/meteor/app/reactions/server/setReaction.ts index 19178a7cd5754..66fa30f36605d 100644 --- a/apps/meteor/app/reactions/server/setReaction.ts +++ b/apps/meteor/app/reactions/server/setReaction.ts @@ -81,8 +81,8 @@ async function setReaction(room: IRoom, user: IUser, message: IMessage, reaction await Rooms.setReactionsInLastMessage(room._id, message.reactions); } } - callbacks.run('unsetReaction', message._id, reaction); - callbacks.run('afterUnsetReaction', message, { user, reaction, shouldReact, oldMessage }); + await callbacks.run('unsetReaction', message._id, reaction); + await callbacks.run('afterUnsetReaction', message, { user, reaction, shouldReact, oldMessage }); isReacted = false; } else { @@ -99,8 +99,8 @@ async function setReaction(room: IRoom, user: IUser, message: IMessage, reaction if (isTheLastMessage(room, message)) { await Rooms.setReactionsInLastMessage(room._id, message.reactions); } - callbacks.run('setReaction', message._id, reaction); - callbacks.run('afterSetReaction', message, { user, reaction, shouldReact }); + await callbacks.run('setReaction', message._id, reaction); + await callbacks.run('afterSetReaction', message, { user, reaction, shouldReact }); isReacted = true; } diff --git a/apps/meteor/app/slashcommands-topic/client/topic.ts b/apps/meteor/app/slashcommands-topic/client/topic.ts index ad6f9f01ca155..212f2aa86bcd0 100644 --- a/apps/meteor/app/slashcommands-topic/client/topic.ts +++ b/apps/meteor/app/slashcommands-topic/client/topic.ts @@ -12,7 +12,7 @@ slashCommands.add({ if (hasPermission('edit-room', item.rid)) { try { await Meteor.callAsync('saveRoomSettings', item.rid, 'roomTopic', params); - callbacks.run('roomTopicChanged', ChatRoom.findOne(item.rid)); + await callbacks.run('roomTopicChanged', ChatRoom.findOne(item.rid)); } catch (error: unknown) { dispatchToastMessage({ type: 'error', message: error }); throw error; diff --git a/apps/meteor/app/threads/server/functions.js b/apps/meteor/app/threads/server/functions.js index b793d7bd0cf05..5d31887b3f5b0 100644 --- a/apps/meteor/app/threads/server/functions.js +++ b/apps/meteor/app/threads/server/functions.js @@ -8,7 +8,7 @@ export async function reply({ tmid }, message, parentMessage, followers) { return false; } - const { toAll, toHere, mentionIds } = getMentions(message); + const { toAll, toHere, mentionIds } = await getMentions(message); const addToReplies = [ ...new Set([ diff --git a/apps/meteor/app/threads/server/hooks/aftersavemessage.ts b/apps/meteor/app/threads/server/hooks/aftersavemessage.ts index 742b2ef326501..9216f244d2c09 100644 --- a/apps/meteor/app/threads/server/hooks/aftersavemessage.ts +++ b/apps/meteor/app/threads/server/hooks/aftersavemessage.ts @@ -48,7 +48,7 @@ export async function processThreads(message: IMessage, room: IRoom) { return message; } - const { mentionIds } = getMentions(message); + const { mentionIds } = await getMentions(message); const replies = [ ...new Set([ diff --git a/apps/meteor/app/threads/server/methods/getThreadMessages.ts b/apps/meteor/app/threads/server/methods/getThreadMessages.ts index 99a3168ce3ea4..c6610718b7a66 100644 --- a/apps/meteor/app/threads/server/methods/getThreadMessages.ts +++ b/apps/meteor/app/threads/server/methods/getThreadMessages.ts @@ -47,7 +47,7 @@ Meteor.methods({ return []; } - callbacks.run('beforeReadMessages', thread.rid, user._id); + await callbacks.run('beforeReadMessages', thread.rid, user._id); await readThread({ userId: user._id, rid: thread.rid, tmid }); const result = await Messages.findVisibleThreadByThreadId(tmid, { diff --git a/apps/meteor/app/ui-utils/client/lib/LegacyRoomManager.ts b/apps/meteor/app/ui-utils/client/lib/LegacyRoomManager.ts index 4ba07ff2803a2..11d5fbd8a5d61 100644 --- a/apps/meteor/app/ui-utils/client/lib/LegacyRoomManager.ts +++ b/apps/meteor/app/ui-utils/client/lib/LegacyRoomManager.ts @@ -192,7 +192,7 @@ const computation = Tracker.autorun(() => { name, }; if (isNew) { - callbacks.run('streamNewMessage', msg); + await callbacks.run('streamNewMessage', msg); } } @@ -200,7 +200,7 @@ const computation = Tracker.autorun(() => { handleTrackSettingsChange(msg); - callbacks.run('streamMessage', msg); + await callbacks.run('streamMessage', msg); fireGlobalEvent('new-message', msg); }) as unknown as Promise diff --git a/apps/meteor/client/methods/updateMessage.ts b/apps/meteor/client/methods/updateMessage.ts index ac82382d8c0cd..5b79bb5173b4e 100644 --- a/apps/meteor/client/methods/updateMessage.ts +++ b/apps/meteor/client/methods/updateMessage.ts @@ -66,7 +66,7 @@ Meteor.methods({ } } - Tracker.nonreactive(() => { + Tracker.nonreactive(async () => { message.editedAt = new Date(Date.now()); message.editedBy = { @@ -74,7 +74,7 @@ Meteor.methods({ username: me.username, }; - message = callbacks.run('beforeSaveMessage', message) as IEditedMessage; + message = (await callbacks.run('beforeSaveMessage', message)) as IEditedMessage; const messageObject: Partial = { editedAt: message.editedAt, editedBy: message.editedBy, diff --git a/apps/meteor/client/providers/UserProvider/UserProvider.tsx b/apps/meteor/client/providers/UserProvider/UserProvider.tsx index 88599531240b4..e5e4712424a12 100644 --- a/apps/meteor/client/providers/UserProvider/UserProvider.tsx +++ b/apps/meteor/client/providers/UserProvider/UserProvider.tsx @@ -45,8 +45,8 @@ const logout = (): Promise => return resolve(); } - Meteor.logout(() => { - callbacks.run('afterLogoutCleanUp', user); + Meteor.logout(async () => { + await callbacks.run('afterLogoutCleanUp', user); call('logoutCleanUp', user).then(resolve, reject); }); }); diff --git a/apps/meteor/client/sidebar/header/UserDropdown.tsx b/apps/meteor/client/sidebar/header/UserDropdown.tsx index 4ea1597dfe87a..cc3318635aaf0 100644 --- a/apps/meteor/client/sidebar/header/UserDropdown.tsx +++ b/apps/meteor/client/sidebar/header/UserDropdown.tsx @@ -35,7 +35,7 @@ const isDefaultStatusName = (_name: string, id: string): _name is UserStatusEnum const setStatus = (status: (typeof userStatus.list)['']): void => { AccountBox.setStatus(status.statusType, !isDefaultStatus(status.id) ? status.name : ''); - callbacks.run('userStatusManuallySet', status); + void callbacks.run('userStatusManuallySet', status); }; const translateStatusName = (t: ReturnType, status: (typeof userStatus.list)['']): string => { diff --git a/apps/meteor/client/startup/iframeCommands.ts b/apps/meteor/client/startup/iframeCommands.ts index 856032d72edd3..761704c4f1c2c 100644 --- a/apps/meteor/client/startup/iframeCommands.ts +++ b/apps/meteor/client/startup/iframeCommands.ts @@ -69,7 +69,7 @@ const commands = { async 'logout'() { const user = Meteor.user(); Meteor.logout(() => { - callbacks.run('afterLogoutCleanUp', user); + void callbacks.run('afterLogoutCleanUp', user); Meteor.call('logoutCleanUp', user); return FlowRouter.go('home'); }); diff --git a/apps/meteor/client/views/account/security/EndToEnd.tsx b/apps/meteor/client/views/account/security/EndToEnd.tsx index dddec8dbfcf2e..f94804e7d3e35 100644 --- a/apps/meteor/client/views/account/security/EndToEnd.tsx +++ b/apps/meteor/client/views/account/security/EndToEnd.tsx @@ -35,7 +35,7 @@ const EndToEnd = (props: ComponentProps): ReactElement => { const handleLogout = useMutableCallback(() => { Meteor.logout(() => { - callbacks.run('afterLogoutCleanUp', user); + void callbacks.run('afterLogoutCleanUp', user); Meteor.call('logoutCleanUp', user); homeRoute.push({}); }); diff --git a/apps/meteor/client/views/setupWizard/providers/SetupWizardProvider.tsx b/apps/meteor/client/views/setupWizard/providers/SetupWizardProvider.tsx index 1df923b496f69..be385e34e0b32 100644 --- a/apps/meteor/client/views/setupWizard/providers/SetupWizardProvider.tsx +++ b/apps/meteor/client/views/setupWizard/providers/SetupWizardProvider.tsx @@ -73,7 +73,7 @@ const SetupWizardProvider = ({ children }: { children: ReactElement }): ReactEle const registerAdminUser = useCallback( async ({ fullname, username, email, password }): Promise => { await registerUser({ name: fullname, username, email, pass: password }); - callbacks.run('userRegistered', {}); + void callbacks.run('userRegistered', {}); try { await loginWithPassword(email, password); @@ -92,7 +92,7 @@ const SetupWizardProvider = ({ children }: { children: ReactElement }): ReactEle await defineUsername(username); await dispatchSettings([{ _id: 'Organization_Email', value: email }]); - callbacks.run('usernameSet', {}); + void callbacks.run('usernameSet', {}); }, [registerUser, setForceLogin, defineUsername, dispatchSettings, loginWithPassword, dispatchToastMessage, t], ); diff --git a/apps/meteor/ee/app/livechat-enterprise/server/hooks/checkAgentBeforeTakeInquiry.ts b/apps/meteor/ee/app/livechat-enterprise/server/hooks/checkAgentBeforeTakeInquiry.ts index cb6bb8ae68e9e..cfcdfa6315b4e 100644 --- a/apps/meteor/ee/app/livechat-enterprise/server/hooks/checkAgentBeforeTakeInquiry.ts +++ b/apps/meteor/ee/app/livechat-enterprise/server/hooks/checkAgentBeforeTakeInquiry.ts @@ -68,7 +68,7 @@ const validateMaxChats = async ({ const { queueInfo: { chats = 0 } = {} } = user; if (parseInt(maxNumberSimultaneousChat, 10) <= chats) { cbLogger.debug('Callback with error. Agent reached max amount of simultaneous chats'); - callbacks.run('livechat.onMaxNumberSimultaneousChatsReached', inquiry); + await callbacks.run('livechat.onMaxNumberSimultaneousChatsReached', inquiry); throw new Error('error-max-number-simultaneous-chats-reached'); } diff --git a/apps/meteor/ee/app/livechat-enterprise/server/lib/Department.ts b/apps/meteor/ee/app/livechat-enterprise/server/lib/Department.ts index cfac0f2db1c9c..a475155028409 100644 --- a/apps/meteor/ee/app/livechat-enterprise/server/lib/Department.ts +++ b/apps/meteor/ee/app/livechat-enterprise/server/lib/Department.ts @@ -21,7 +21,7 @@ export const findAllDepartmentsAvailable = async ( }; if (onlyMyDepartments) { - query = callbacks.run('livechat.applyDepartmentRestrictions', query, { userId: uid }); + query = await callbacks.run('livechat.applyDepartmentRestrictions', query, { userId: uid }); } const { cursor, totalCount } = LivechatDepartment.findPaginated(query, { limit: count, offset }); diff --git a/apps/meteor/lib/callbacks.spec.ts b/apps/meteor/lib/callbacks.spec.ts new file mode 100644 index 0000000000000..4459ec1cf4731 --- /dev/null +++ b/apps/meteor/lib/callbacks.spec.ts @@ -0,0 +1,70 @@ +import { expect } from 'chai'; +import { describe, it } from 'mocha'; + +import { callbacks, Callbacks } from './callbacks'; + +describe('callbacks legacy', () => { + it("if the callback doesn't return any value should return the original", async () => { + callbacks.add('test', () => undefined, callbacks.priority.LOW, '1'); + + const result = await callbacks.run('test', true); + + expect(result).to.be.true; + + callbacks.remove('test', '1'); + }); + + it('should return the value returned by the callback', async () => { + callbacks.add('test', () => false, callbacks.priority.LOW, '1'); + + const result = await callbacks.run('test', true); + + expect(result).to.be.false; + + callbacks.remove('test', '1'); + }); + + it('should accumulate the values returned by the callbacks', async () => { + callbacks.add('test', (old: number) => old * 5); + + callbacks.add('test', (old: number) => old * 2); + + expect(await callbacks.run('test', 3)).to.be.equal(30); + + expect(await callbacks.run('test', 2)).to.be.equal(20); + }); +}); + +describe('callbacks', () => { + it("if the callback doesn't return any value should return the original", async () => { + const test = Callbacks.create('test'); + + test.add(() => undefined, callbacks.priority.LOW, '1'); + + const result = await test.run(true); + + expect(result).to.be.true; + }); + + it('should return the value returned by the callback', async () => { + const test = Callbacks.create('test'); + + test.add(() => false, callbacks.priority.LOW, '1'); + + const result = await test.run(true); + + expect(result).to.be.false; + }); + + it('should accumulate the values returned by the callbacks', async () => { + const test = Callbacks.create('test'); + + test.add((old) => old * 5); + + test.add((old) => old * 2); + + expect(await test.run(3)).to.be.equal(30); + + expect(await test.run(2)).to.be.equal(20); + }); +}); diff --git a/apps/meteor/lib/callbacks.ts b/apps/meteor/lib/callbacks.ts index c38e8a699ae56..c9cce089ff774 100644 --- a/apps/meteor/lib/callbacks.ts +++ b/apps/meteor/lib/callbacks.ts @@ -26,9 +26,6 @@ import type { ILoginAttempt } from '../app/authentication/server/ILoginAttempt'; import { compareByRanking } from './utils/comparisons'; import type { CloseRoomParams } from '../app/livechat/server/lib/LivechatTyped'; -// Temporary since we are still using callbacks on client side -Promise.await = Promise.await || ((promise: Promise) => promise); - enum CallbackPriority { HIGH = -1000, MEDIUM = 0, @@ -263,10 +260,11 @@ export type Hook = | 'usernameSet' | 'userPasswordReset' | 'userRegistered' - | 'userStatusManuallySet'; + | 'userStatusManuallySet' + | 'test'; type Callback = { - (item: unknown, constant?: unknown): unknown; + (item: unknown, constant?: unknown): Promise; hook: Hook; id: string; priority: CallbackPriority; @@ -277,7 +275,7 @@ type CallbackTracker = (callback: Callback) => () => void; type HookTracker = (params: { hook: Hook; length: number }) => () => void; -class Callbacks { +export class Callbacks { private logger: Logger | undefined = undefined; private trackCallback: CallbackTracker | undefined = undefined; @@ -286,7 +284,7 @@ class Callbacks { private callbacks = new Map(); - private sequentialRunners = new Map unknown>(); + private sequentialRunners = new Map Promise>(); private asyncRunners = new Map unknown>(); @@ -301,47 +299,34 @@ class Callbacks { this.trackHook = trackHook; } - private runOne(callback: Callback, item: unknown, constant: unknown): unknown { + private runOne(callback: Callback, item: unknown, constant: unknown): Promise { const stopTracking = this.trackCallback?.(callback); - try { - const result = callback(item, constant); - if (result && result instanceof Promise) { - return Promise.await(result); - } - - return result; - } finally { - stopTracking?.(); - } + return Promise.resolve(callback(item, constant)).finally(stopTracking); } - private createSequentialRunner(hook: Hook, callbacks: Callback[]): (item: unknown, constant?: unknown) => unknown { + private createSequentialRunner(hook: Hook, callbacks: Callback[]): (item: unknown, constant?: unknown) => Promise { const wrapCallback = (callback: Callback) => - (item: unknown, constant?: unknown): unknown => { + async (item: unknown, constant?: unknown): Promise => { this.logger?.debug(`Executing callback with id ${callback.id} for hook ${callback.hook}`); - return this.runOne(callback, item, constant) ?? item; + return (await this.runOne(callback, item, constant)) ?? item; }; - const identity = (item: TItem): TItem => item; + const identity = (item: TItem): Promise => Promise.resolve(item); const pipe = - (curr: (item: unknown, constant?: unknown) => unknown, next: (item: unknown, constant?: unknown) => unknown) => - (item: unknown, constant?: unknown): unknown => - next(curr(item, constant), constant); + (curr: (item: unknown, constant?: unknown) => Promise, next: (item: unknown, constant?: unknown) => Promise) => + async (item: unknown, constant?: unknown): Promise => + next(await curr(item, constant), constant); const fn = callbacks.map(wrapCallback).reduce(pipe, identity); - return (item: unknown, constant?: unknown): unknown => { + return async (item: unknown, constant?: unknown): Promise => { const stopTracking = this.trackHook?.({ hook, length: callbacks.length }); - try { - return fn(item, constant); - } finally { - stopTracking?.(); - } + return fn(item, constant).finally(() => stopTracking?.()); }; } @@ -353,7 +338,7 @@ class Callbacks { for (const callback of callbacks) { setTimeout(() => { - this.runOne(callback, item, constant); + void this.runOne(callback, item, constant); }, 0); } @@ -436,9 +421,9 @@ class Callbacks { run( hook: THook, ...args: Parameters - ): ReturnType; + ): Promise>; - run(hook: Hook, item: TItem, constant?: TConstant): TNextItem; + run(hook: Hook, item: TItem, constant?: TConstant): Promise; /** * Successively run all of a hook's callbacks on an item @@ -448,8 +433,8 @@ class Callbacks { * @param constant an optional constant that will be passed along to each callback * @returns returns the item after it's been through all the callbacks for this hook */ - run(hook: Hook, item: unknown, constant?: unknown): unknown { - const runner = this.sequentialRunners.get(hook) ?? ((item: unknown, _constant?: unknown): unknown => item); + run(hook: Hook, item: unknown, constant?: unknown): Promise { + const runner = this.sequentialRunners.get(hook) ?? (async (item: unknown, _constant?: unknown): Promise => item); return runner(item, constant); } @@ -467,8 +452,27 @@ class Callbacks { const runner = this.asyncRunners.get(hook) ?? ((item: unknown, _constant?: unknown): unknown => item); return runner(item, constant); } + + static create(hook: string): Cb { + const callbacks = new Callbacks(); + + return { + add: (callback, priority, id) => callbacks.add(hook as any, callback, priority, id), + remove: (id) => callbacks.remove(hook as any, id), + run: (item, constant) => callbacks.run(hook as any, item, constant) as any, + }; + } } +/** + * Callback hooks provide an easy way to add extra steps to common operations. + * @deprecated + */ +type Cb = { + add: (callback: (item: I, constant?: C) => R | undefined, priority?: CallbackPriority, id?: string) => void; + remove: (id: string) => void; + run: (item: I, constant?: C) => Promise; +}; /** * Callback hooks provide an easy way to add extra steps to common operations. * @deprecated diff --git a/apps/meteor/server/lib/ldap/Manager.ts b/apps/meteor/server/lib/ldap/Manager.ts index be85fd2c7a56a..70d91398510b5 100644 --- a/apps/meteor/server/lib/ldap/Manager.ts +++ b/apps/meteor/server/lib/ldap/Manager.ts @@ -150,7 +150,7 @@ export class LDAPManager { } private static onMapUserData(ldapUser: ILDAPEntry, userData: IImportUser): void { - callbacks.run('mapLDAPUserData', userData, ldapUser); + void callbacks.run('mapLDAPUserData', userData, ldapUser); } private static async findUser(ldap: LDAPConnection, username: string, password: string): Promise { @@ -238,7 +238,7 @@ export class LDAPManager { } await this.syncUserAvatar(user, ldapUser); - callbacks.run('onLDAPLogin', { user, ldapUser, isNewUser }, ldap); + await callbacks.run('onLDAPLogin', { user, ldapUser, isNewUser }, ldap); } private static async loginExistingUser( diff --git a/apps/meteor/server/lib/readMessages.ts b/apps/meteor/server/lib/readMessages.ts index ff8ad49861e31..00bf04bd3449b 100644 --- a/apps/meteor/server/lib/readMessages.ts +++ b/apps/meteor/server/lib/readMessages.ts @@ -4,7 +4,7 @@ import { NotificationQueue, Subscriptions } from '@rocket.chat/models'; import { callbacks } from '../../lib/callbacks'; export async function readMessages(rid: IRoom['_id'], uid: IUser['_id'], readThreads: boolean): Promise { - callbacks.run('beforeReadMessages', rid, uid); + await callbacks.run('beforeReadMessages', rid, uid); const projection = { ls: 1, tunread: 1, alert: 1 }; const sub = await Subscriptions.findOneByRoomIdAndUserId(rid, uid, { projection }); diff --git a/apps/meteor/server/methods/addAllUserToRoom.ts b/apps/meteor/server/methods/addAllUserToRoom.ts index 829baa09c2030..993d618f9b691 100644 --- a/apps/meteor/server/methods/addAllUserToRoom.ts +++ b/apps/meteor/server/methods/addAllUserToRoom.ts @@ -54,7 +54,7 @@ Meteor.methods({ if (subscription != null) { continue; } - callbacks.run('beforeJoinRoom', user, room); + await callbacks.run('beforeJoinRoom', user, room); await Subscriptions.createWithRoomAndUser(room, user, { ts: now, open: true, @@ -64,7 +64,7 @@ Meteor.methods({ groupMentions: 0, }); await Message.saveSystemMessage('uj', rid, user.username || '', user, { ts: now }); - callbacks.run('afterJoinRoom', user, room); + await callbacks.run('afterJoinRoom', user, room); } return true; }, diff --git a/apps/meteor/server/methods/createDirectMessage.ts b/apps/meteor/server/methods/createDirectMessage.ts index 598c761a7a31c..7f5cffb073897 100644 --- a/apps/meteor/server/methods/createDirectMessage.ts +++ b/apps/meteor/server/methods/createDirectMessage.ts @@ -100,7 +100,7 @@ export async function createDirectMessage( options.subscriptionExtra = { open: true }; } try { - callbacks.run('federation.beforeCreateDirectMessage', roomUsers); + await callbacks.run('federation.beforeCreateDirectMessage', roomUsers); } catch (error) { throw new Meteor.Error((error as any)?.message); } diff --git a/apps/meteor/server/methods/deleteUser.ts b/apps/meteor/server/methods/deleteUser.ts index d83c002d92c04..1dc87f7f1dbd2 100644 --- a/apps/meteor/server/methods/deleteUser.ts +++ b/apps/meteor/server/methods/deleteUser.ts @@ -52,7 +52,7 @@ Meteor.methods({ await deleteUser(userId, confirmRelinquish); - callbacks.run('afterDeleteUser', user); + await callbacks.run('afterDeleteUser', user); // App IPostUserDeleted event hook await Apps.triggerEvent(AppEvents.IPostUserDeleted, { user, performedBy: await Meteor.userAsync() }); diff --git a/apps/meteor/server/methods/logoutCleanUp.ts b/apps/meteor/server/methods/logoutCleanUp.ts index 6e14b52c71ee8..84da0ec71a2af 100644 --- a/apps/meteor/server/methods/logoutCleanUp.ts +++ b/apps/meteor/server/methods/logoutCleanUp.ts @@ -18,7 +18,7 @@ Meteor.methods({ check(user, Object); setImmediate(() => { - callbacks.run('afterLogoutCleanUp', user); + void callbacks.run('afterLogoutCleanUp', user); }); // App IPostUserLogout event hook diff --git a/apps/meteor/server/methods/muteUserInRoom.ts b/apps/meteor/server/methods/muteUserInRoom.ts index 7d0520b8af2a5..c793e73215628 100644 --- a/apps/meteor/server/methods/muteUserInRoom.ts +++ b/apps/meteor/server/methods/muteUserInRoom.ts @@ -80,13 +80,13 @@ Meteor.methods({ }); } - callbacks.run('beforeMuteUser', { mutedUser, fromUser }, room); + await callbacks.run('beforeMuteUser', { mutedUser, fromUser }, room); await Rooms.muteUsernameByRoomId(data.rid, mutedUser.username); await Message.saveSystemMessage('user-muted', data.rid, mutedUser.username, fromUser); - callbacks.run('afterMuteUser', { mutedUser, fromUser }, room); + await callbacks.run('afterMuteUser', { mutedUser, fromUser }, room); return true; }, diff --git a/apps/meteor/server/methods/readThreads.ts b/apps/meteor/server/methods/readThreads.ts index 4ecc12ba67f6f..648625cfb0671 100644 --- a/apps/meteor/server/methods/readThreads.ts +++ b/apps/meteor/server/methods/readThreads.ts @@ -42,7 +42,7 @@ Meteor.methods({ throw new Meteor.Error('error-not-allowed', 'Not allowed', { method: 'getThreadMessages' }); } - callbacks.run('beforeReadMessages', thread.rid, user?._id); + await callbacks.run('beforeReadMessages', thread.rid, user?._id); await readThread({ userId: user?._id, rid: thread.rid, tmid }); if (user?._id) { callbacks.runAsync('afterReadMessages', room._id, { uid: user._id, tmid }); diff --git a/apps/meteor/server/methods/removeUserFromRoom.ts b/apps/meteor/server/methods/removeUserFromRoom.ts index f78d438a670ce..7b5072920d6e6 100644 --- a/apps/meteor/server/methods/removeUserFromRoom.ts +++ b/apps/meteor/server/methods/removeUserFromRoom.ts @@ -79,7 +79,7 @@ Meteor.methods({ } } - callbacks.run('beforeRemoveFromRoom', { removedUser, userWhoRemoved: fromUser }, room); + await callbacks.run('beforeRemoveFromRoom', { removedUser, userWhoRemoved: fromUser }, room); await Subscriptions.removeByRoomIdAndUserId(data.rid, removedUser._id); @@ -95,7 +95,7 @@ Meteor.methods({ } setImmediate(function () { - callbacks.run('afterRemoveFromRoom', { removedUser, userWhoRemoved: fromUser }, room); + void callbacks.run('afterRemoveFromRoom', { removedUser, userWhoRemoved: fromUser }, room); }); return true; diff --git a/apps/meteor/server/methods/unmuteUserInRoom.ts b/apps/meteor/server/methods/unmuteUserInRoom.ts index 65f41d4c3e0af..bc01d1e87a9b5 100644 --- a/apps/meteor/server/methods/unmuteUserInRoom.ts +++ b/apps/meteor/server/methods/unmuteUserInRoom.ts @@ -74,14 +74,14 @@ Meteor.methods({ }); } - callbacks.run('beforeUnmuteUser', { unmutedUser, fromUser }, room); + await callbacks.run('beforeUnmuteUser', { unmutedUser, fromUser }, room); await Rooms.unmuteUsernameByRoomId(data.rid, unmutedUser.username); await Message.saveSystemMessage('user-unmuted', data.rid, unmutedUser.username, fromUser); setImmediate(function () { - callbacks.run('afterUnmuteUser', { unmutedUser, fromUser }, room); + void callbacks.run('afterUnmuteUser', { unmutedUser, fromUser }, room); }); return true; diff --git a/apps/meteor/server/services/video-conference/service.ts b/apps/meteor/server/services/video-conference/service.ts index 7c2ca7a427b06..fe9a08e34d135 100644 --- a/apps/meteor/server/services/video-conference/service.ts +++ b/apps/meteor/server/services/video-conference/service.ts @@ -741,7 +741,7 @@ export class VideoConfService extends ServiceClassInternal implements IVideoConf user: AtLeast | undefined, options: VideoConferenceJoinOptions, ): Promise { - await callbacks.runAsync('onJoinVideoConference', call._id, user?._id); + void callbacks.runAsync('onJoinVideoConference', call._id, user?._id); await this.runOnUserJoinEvent(call._id, user as IVideoConferenceUser);