Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,6 @@ export async function saveRoomName(
await Message.saveSystemMessage('r', rid, displayName, user);
}

await callbacks.run('afterRoomNameChange', { rid, name: displayName, oldName: room.name });
await callbacks.run('afterRoomNameChange', { room, name: displayName, oldName: room.name, userId: user._id });
return displayName;
}
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,11 @@ callbacks.add(
callbacks.add(
'afterRoomNameChange',
async (roomConfig) => {
const { rid, name, oldName } = roomConfig;
const {
room: { _id: rid },
name,
oldName,
} = roomConfig;
await Rooms.updateMany({ prid: rid, ...(oldName && { topic: oldName }) }, { $set: { topic: name } });
return roomConfig;
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ const create = async ({
}

if (discussionMsg) {
afterSaveMessageAsync(discussionMsg, parentRoom);
afterSaveMessageAsync(discussionMsg, parentRoom, user);
}

return discussion;
Expand Down
4 changes: 2 additions & 2 deletions apps/meteor/app/e2e/server/beforeCreateRoom.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { beforeCreateRoomCallback } from '../../../lib/callbacks/beforeCreateRoomCallback';
import { prepareCreateRoomCallback } from '../../../lib/callbacks/beforeCreateRoomCallback';
import { settings } from '../../settings/server';

beforeCreateRoomCallback.add(({ type, extraData }) => {
prepareCreateRoomCallback.add(({ type, extraData }) => {
if (
settings.get<boolean>('E2E_Enable') &&
((type === 'd' && settings.get<boolean>('E2E_Enabled_Default_DirectRooms')) ||
Expand Down
2 changes: 1 addition & 1 deletion apps/meteor/app/lib/client/methods/sendMessage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ Meteor.methods<ServerMethods>({

await onClientMessageReceived(message as IMessage).then((message) => {
Messages.state.store(message);
return callbacks.run('afterSaveMessage', message, { room });
return callbacks.run('afterSaveMessage', message, { room, user });
});
},
});
10 changes: 7 additions & 3 deletions apps/meteor/app/lib/server/functions/addUserToRoom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { Meteor } from 'meteor/meteor';

import { RoomMemberActions } from '../../../../definition/IRoomTypeConfig';
import { callbacks } from '../../../../lib/callbacks';
import { beforeAddUserToRoom } from '../../../../lib/callbacks/beforeAddUserToRoom';
import { getSubscriptionAutotranslateDefaultConfig } from '../../../../server/lib/getSubscriptionAutotranslateDefaultConfig';
import { roomCoordinator } from '../../../../server/lib/rooms/roomCoordinator';
import { settings } from '../../../settings/server';
Expand All @@ -17,9 +18,10 @@ import { notifyOnRoomChangedById, notifyOnSubscriptionChangedById } from '../lib
* This function adds user to the given room.
* Caution - It does not validates if the user has permission to join room
*/

export const addUserToRoom = async function (
rid: string,
user: Pick<IUser, '_id'> | string,
user: Pick<IUser, '_id' | 'username'> | string,
inviter?: Pick<IUser, '_id' | 'username'>,
{
skipSystemMessage,
Expand Down Expand Up @@ -55,11 +57,13 @@ export const addUserToRoom = async function (
}

try {
await callbacks.run('federation.beforeAddUserToARoom', { user: userToBeAdded, inviter }, room);
await beforeAddUserToRoom.run({ user: userToBeAdded, inviter }, room);
} catch (error) {
throw new Meteor.Error((error as any)?.message);
}

// TODO: are we calling this twice?

await callbacks.run('beforeAddedToRoom', { user: userToBeAdded, inviter });

// Check if user is already in room
Expand All @@ -77,7 +81,7 @@ export const addUserToRoom = async function (

throw error;
}

// TODO: are we calling this twice?
if (room.t === 'c' || room.t === 'p' || room.t === 'l') {
// Add a new event, with an optional inviter
await callbacks.run('beforeAddedToRoom', { user: userToBeAdded, inviter }, room);
Expand Down
23 changes: 11 additions & 12 deletions apps/meteor/app/lib/server/functions/createRoom.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import { AppEvents, Apps } from '@rocket.chat/apps';
import { AppsEngineException } from '@rocket.chat/apps-engine/definition/exceptions';
import { Federation, FederationEE, License, Message, Team } from '@rocket.chat/core-services';
import { Message, Team } from '@rocket.chat/core-services';
import type { ICreateRoomParams, ISubscriptionExtraData } from '@rocket.chat/core-services';
import type { ICreatedRoom, IUser, IRoom, RoomType } from '@rocket.chat/core-typings';
import { Rooms, Subscriptions, Users } from '@rocket.chat/models';
import { Meteor } from 'meteor/meteor';

import { createDirectRoom } from './createDirectRoom';
import { callbacks } from '../../../../lib/callbacks';
import { beforeCreateRoomCallback } from '../../../../lib/callbacks/beforeCreateRoomCallback';
import { beforeAddUserToRoom } from '../../../../lib/callbacks/beforeAddUserToRoom';
import { beforeCreateRoomCallback, prepareCreateRoomCallback } from '../../../../lib/callbacks/beforeCreateRoomCallback';
import { calculateRoomRolePriorityFromRoles } from '../../../../lib/roles/calculateRoomRolePriorityFromRoles';
import { getSubscriptionAutotranslateDefaultConfig } from '../../../../server/lib/getSubscriptionAutotranslateDefaultConfig';
import { syncRoomRolePriorityForUserAndRoom } from '../../../../server/lib/roles/syncRoomRolePriority';
Expand Down Expand Up @@ -64,13 +65,11 @@ async function createUsersSubscriptions({

const memberIdAndRolePriorityMap: Record<IUser['_id'], number> = {};

const membersCursor = Users.findUsersByUsernames<Pick<IUser, '_id' | 'username' | 'settings' | 'federated' | 'roles'>>(members, {
projection: { 'username': 1, 'settings.preferences': 1, 'federated': 1, 'roles': 1 },
});
const membersCursor = Users.findUsersByUsernames(members);

for await (const member of membersCursor) {
try {
await callbacks.run('federation.beforeAddUserToARoom', { user: member, inviter: owner }, room);
await beforeAddUserToRoom.run({ user: member, inviter: owner }, room);
await callbacks.run('beforeAddedToRoom', { user: member, inviter: owner });
} catch (error) {
continue;
Expand Down Expand Up @@ -133,7 +132,7 @@ export const createRoom = async <T extends RoomType>(
> => {
const { teamId, ...extraData } = roomExtraData || ({} as IRoom);

await beforeCreateRoomCallback.run({
await prepareCreateRoomCallback.run({
type,
// name,
// owner: ownerUsername,
Expand Down Expand Up @@ -238,10 +237,10 @@ export const createRoom = async <T extends RoomType>(

const shouldBeHandledByFederation = roomProps.federated === true || owner.username.includes(':');

if (shouldBeHandledByFederation) {
const federation = (await License.hasValidLicense()) ? FederationEE : Federation;
await federation.beforeCreateRoom(roomProps);
}
await beforeCreateRoomCallback.run({
owner,
room: roomProps,
});

if (type === 'c') {
await callbacks.run('beforeCreateChannel', owner, roomProps);
Expand All @@ -266,7 +265,7 @@ export const createRoom = async <T extends RoomType>(
}
callbacks.runAsync('afterCreateRoom', owner, room);
if (shouldBeHandledByFederation) {
callbacks.runAsync('federation.afterCreateFederatedRoom', room, { owner, originalMemberList: members });
callbacks.runAsync('federation.afterCreateFederatedRoom', room, { owner, originalMemberList: members, options });
}

void Apps.self?.triggerEvent(AppEvents.IPostRoomCreate, room);
Expand Down
2 changes: 1 addition & 1 deletion apps/meteor/app/lib/server/functions/sendMessage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,7 @@ export const sendMessage = async function (user: any, message: any, room: any, u
}

// TODO: is there an opportunity to send returned data to notifyOnMessageChange?
await afterSaveMessage(message, room);
await afterSaveMessage(message, room, user);

void notifyOnMessageChange({ id: message._id });

Expand Down
2 changes: 1 addition & 1 deletion apps/meteor/app/lib/server/functions/updateMessage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ export const updateMessage = async function (

// although this is an "afterSave" kind callback, we know they can extend message's properties
// so we wait for it to run before broadcasting
const data = await afterSaveMessage(msg, room, user._id);
const data = await afterSaveMessage(msg, room, user);

void notifyOnMessageChange({
id: msg._id,
Expand Down
18 changes: 4 additions & 14 deletions apps/meteor/app/lib/server/lib/afterSaveMessage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,9 @@ import { Rooms } from '@rocket.chat/models';

import { callbacks } from '../../../../lib/callbacks';

export async function afterSaveMessage(
message: IMessage,
room: IRoom,
uid?: IUser['_id'],
roomUpdater?: Updater<IRoom>,
): Promise<IMessage> {
export async function afterSaveMessage(message: IMessage, room: IRoom, user: IUser, roomUpdater?: Updater<IRoom>): Promise<IMessage> {
const updater = roomUpdater ?? Rooms.getUpdater();
const data = await callbacks.run('afterSaveMessage', message, { room, uid, roomUpdater: updater });
const data = await callbacks.run('afterSaveMessage', message, { room, user, roomUpdater: updater });

if (!roomUpdater && updater.hasChanges()) {
await Rooms.updateFromUpdater({ _id: room._id }, updater);
Expand All @@ -21,13 +16,8 @@ export async function afterSaveMessage(
return data as unknown as IMessage;
}

export function afterSaveMessageAsync(
message: IMessage,
room: IRoom,
uid?: IUser['_id'],
roomUpdater: Updater<IRoom> = Rooms.getUpdater(),
): void {
callbacks.runAsync('afterSaveMessage', message, { room, uid, roomUpdater });
export function afterSaveMessageAsync(message: IMessage, room: IRoom, user: IUser, roomUpdater: Updater<IRoom> = Rooms.getUpdater()): void {
callbacks.runAsync('afterSaveMessage', message, { room, user, roomUpdater });

if (roomUpdater.hasChanges()) {
void Rooms.updateFromUpdater({ _id: room._id }, roomUpdater);
Expand Down
2 changes: 1 addition & 1 deletion apps/meteor/app/lib/server/methods/addUsersToRoom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ export const addUsersToRoomMethod = async (userId: string, data: { rid: string;

// Validate each user, then add to room
if (isRoomFederated(room)) {
await callbacks.run('federation.onAddUsersToARoom', { invitees: data.users, inviter: user }, room);
await callbacks.run('federation.onAddUsersToRoom', { invitees: data.users, inviter: user }, room);
return true;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import { useEncryptedRoomDescription } from './useEncryptedRoomDescription';
import UserAutoCompleteMultipleFederated from '../../../components/UserAutoCompleteMultiple/UserAutoCompleteMultipleFederated';
import { useCreateChannelTypePermission } from '../../../hooks/useCreateChannelTypePermission';
import { useHasLicenseModule } from '../../../hooks/useHasLicenseModule';
import { useIsFederationEnabled } from '../../../hooks/useIsFederationEnabled';
import { goToRoomById } from '../../../lib/utils/goToRoomById';

type CreateChannelModalProps = {
Expand Down Expand Up @@ -65,7 +66,7 @@ const CreateChannelModal = ({ teamId = '', onClose, reload }: CreateChannelModal
const e2eEnabled = useSetting('E2E_Enable');
const namesValidation = useSetting('UTF8_Channel_Names_Validation');
const allowSpecialNames = useSetting('UI_Allow_room_names_with_special_chars');
const federationEnabled = useSetting('Federation_Matrix_enabled', false);
const federationEnabled = useIsFederationEnabled();
const e2eEnabledForPrivateByDefault = useSetting('E2E_Enabled_Default_PrivateRooms') && e2eEnabled;

const getEncryptedHint = useEncryptedRoomDescription('channel');
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { useAtLeastOnePermission, useSetting } from '@rocket.chat/ui-contexts';
import { useAtLeastOnePermission } from '@rocket.chat/ui-contexts';
import { useTranslation } from 'react-i18next';

import { useCreateNewItems } from './useCreateNewItems';
import { useMatrixFederationItems } from './useMatrixFederationItems';
import { useIsEnterprise } from '../../../hooks/useIsEnterprise';
import { useIsFederationEnabled } from '../../../hooks/useIsFederationEnabled';

const CREATE_ROOM_PERMISSIONS = ['create-c', 'create-p', 'create-d', 'start-discussion', 'start-discussion-other-user'];

Expand All @@ -12,7 +13,7 @@ export const useCreateNewMenu = () => {
const showCreate = useAtLeastOnePermission(CREATE_ROOM_PERMISSIONS);

const { data } = useIsEnterprise();
const isMatrixEnabled = useSetting('Federation_Matrix_enabled') && data?.isEnterprise;
const isMatrixEnabled = useIsFederationEnabled() && data?.isEnterprise;

const createRoomItems = useCreateNewItems();
const matrixFederationSearchItems = useMatrixFederationItems({ isMatrixEnabled });
Expand Down
6 changes: 6 additions & 0 deletions apps/meteor/client/hooks/useIsFederationEnabled.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { useSetting } from '@rocket.chat/ui-contexts';

export const useIsFederationEnabled = () => {
const federationMatrixEnabled = useSetting('Federation_Matrix_enabled', false) === true;
return federationMatrixEnabled;
};
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import { useForm, Controller } from 'react-hook-form';
import UserAutoCompleteMultipleFederated from '../../../components/UserAutoCompleteMultiple/UserAutoCompleteMultipleFederated';
import { useCreateChannelTypePermission } from '../../../hooks/useCreateChannelTypePermission';
import { useHasLicenseModule } from '../../../hooks/useHasLicenseModule';
import { useIsFederationEnabled } from '../../../hooks/useIsFederationEnabled';
import { goToRoomById } from '../../../lib/utils/goToRoomById';
import { useEncryptedRoomDescription } from '../hooks/useEncryptedRoomDescription';

Expand Down Expand Up @@ -67,7 +68,9 @@ const CreateChannelModal = ({ teamId = '', mainRoom, onClose, reload }: CreateCh
const e2eEnabled = useSetting('E2E_Enable');
const namesValidation = useSetting('UTF8_Channel_Names_Validation');
const allowSpecialNames = useSetting('UI_Allow_room_names_with_special_chars');
const federationEnabled = useSetting('Federation_Matrix_enabled', false);

const federationEnabled = useIsFederationEnabled();

const e2eEnabledForPrivateByDefault = useSetting('E2E_Enabled_Default_PrivateRooms') && e2eEnabled;

const getEncryptedHint = useEncryptedRoomDescription('channel');
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { useAtLeastOnePermission, useSetting } from '@rocket.chat/ui-contexts';
import { useAtLeastOnePermission } from '@rocket.chat/ui-contexts';
import { useTranslation } from 'react-i18next';

import { useCreateRoomItems } from './useCreateRoomItems';
import { useMatrixFederationItems } from './useMatrixFederationItems';
import { useIsEnterprise } from '../../../../hooks/useIsEnterprise';
import { useIsFederationEnabled } from '../../../../hooks/useIsFederationEnabled';

const CREATE_ROOM_PERMISSIONS = ['create-c', 'create-p', 'create-d', 'start-discussion', 'start-discussion-other-user'];

Expand All @@ -12,7 +13,7 @@ export const useCreateRoom = () => {
const showCreate = useAtLeastOnePermission(CREATE_ROOM_PERMISSIONS);

const { data } = useIsEnterprise();
const isMatrixEnabled = useSetting('Federation_Matrix_enabled') && data?.isEnterprise;
const isMatrixEnabled = useIsFederationEnabled() && data?.isEnterprise;

const createRoomItems = useCreateRoomItems();
const matrixFederationSearchItems = useMatrixFederationItems({ isMatrixEnabled });
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { useSetting } from '@rocket.chat/ui-contexts';
import type { ReactElement } from 'react';

import { useHasLicenseModule } from '../../../../hooks/useHasLicenseModule';
import type { ComposerMessageProps } from '../ComposerMessage';
import ComposerMessage from '../ComposerMessage';
import ComposerFederationDisabled from './ComposerFederationDisabled';
import ComposerFederationJoinRoomDisabled from './ComposerFederationJoinRoomDisabled';
import { useIsFederationEnabled } from '../../../../hooks/useIsFederationEnabled';

const ComposerFederation = ({ subscription, children, ...props }: ComposerMessageProps): ReactElement => {
const federationEnabled = useSetting('Federation_Matrix_enabled') === true;
const federationEnabled = useIsFederationEnabled();
const federationModuleEnabled = useHasLicenseModule('federation') === true;

if (!federationEnabled) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import { useEnablePopupPreview } from '../hooks/useEnablePopupPreview';
import { useMessageComposerMergedRefs } from '../hooks/useMessageComposerMergedRefs';
import { useMessageBoxAutoFocus } from './hooks/useMessageBoxAutoFocus';
import { useMessageBoxPlaceholder } from './hooks/useMessageBoxPlaceholder';
import { useIsFederationEnabled } from '../../../../hooks/useIsFederationEnabled';

const reducer = (_: unknown, event: FormEvent<HTMLInputElement>): boolean => {
const target = event.target as HTMLInputElement;
Expand Down Expand Up @@ -279,7 +280,8 @@ const MessageBox = ({

const { autoGrowRef, textAreaStyle } = useAutoGrow(textareaRef, isRecordingAudio);

const federationMatrixEnabled = useSetting('Federation_Matrix_enabled', false);
const federationMatrixEnabled = useIsFederationEnabled();

const canSend = useReactiveValue(
useCallback(() => {
if (!room.t) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import type { IRoom, IUser, Username } from '@rocket.chat/core-typings';
import { isRoomFederated } from '@rocket.chat/core-typings';
import { Users } from '@rocket.chat/models';

import { callbacks } from '../../../../../../../lib/callbacks';
import { beforeAddUserToRoom } from '../../../../../../../lib/callbacks/beforeAddUserToRoom';
import { throwIfFederationNotEnabledOrNotReady } from '../../../../../../../server/services/federation/utils';

// biome-ignore lint/complexity/noStaticOnlyClass: <explanation>
export class FederationHooksEE {
public static onFederatedRoomCreated(callback: (room: IRoom, owner: IUser, originalMemberList: string[]) => Promise<void>): void {
callbacks.add(
Expand All @@ -24,7 +27,7 @@ export class FederationHooksEE {

public static onUsersAddedToARoom(callback: (room: IRoom, addedUsers: IUser[] | Username[], inviter?: IUser) => Promise<void>): void {
callbacks.add(
'federation.onAddUsersToARoom',
'federation.onAddUsersToRoom',
async (params: { invitees: IUser[] | Username[]; inviter: IUser }, room: IRoom) => {
if (!room || !isRoomFederated(room) || !params || !params.invitees || !params.inviter) {
return;
Expand Down Expand Up @@ -84,14 +87,15 @@ export class FederationHooksEE {
}

public static beforeAddUserToARoom(callback: (userToBeAdded: IUser | string, room: IRoom, inviter?: IUser) => Promise<void>): void {
callbacks.add(
'federation.beforeAddUserToARoom',
async (params: { user: IUser | string; inviter?: IUser }, room: IRoom) => {
beforeAddUserToRoom.add(
async (params, room: IRoom) => {
if (!room || !isRoomFederated(room) || !params || !params.user) {
return;
}
throwIfFederationNotEnabledOrNotReady();
await callback(params.user, room, params.inviter);

const inviter = (params.inviter && (await Users.findOneById(params.inviter._id))) || undefined;
await callback(params.user, room, inviter);
},
callbacks.priority.HIGH,
'federation-v2-before-add-user-to-the-room',
Expand All @@ -101,9 +105,9 @@ export class FederationHooksEE {
public static removeAllListeners(): void {
callbacks.remove('beforeCreateDirectRoom', 'federation-v2-before-create-direct-message-room');
callbacks.remove('afterCreateDirectRoom', 'federation-v2-after-create-direct-message-room');
callbacks.remove('federation.onAddUsersToARoom', 'federation-v2-on-add-users-to-a-room');
callbacks.remove('federation.onAddUsersToRoom', 'federation-v2-on-add-users-to-a-room');
callbacks.remove('afterAddedToRoom', 'federation-v2-after-add-user-to-a-room');
callbacks.remove('federation.afterCreateFederatedRoom', 'federation-v2-after-create-room');
callbacks.remove('federation.beforeAddUserToARoom', 'federation-v2-before-add-user-to-the-room');
beforeAddUserToRoom.remove('federation-v2-before-add-user-to-the-room');
}
}
Loading
Loading