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
8 changes: 3 additions & 5 deletions apps/meteor/app/lib/server/functions/createDirectRoom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ export async function createDirectRoom(
members: IUser[] | string[],
roomExtraData: Partial<IRoom> = {},
options: {
forceNew?: boolean;
creator?: IUser['_id'];
subscriptionExtra?: ISubscriptionExtraData;
},
Expand Down Expand Up @@ -77,15 +78,11 @@ export async function createDirectRoom(
const uids = roomMembers.map(({ _id }) => _id).sort();

// Deprecated: using users' _id to compose the room _id is deprecated
const room: IRoom | null =
uids.length === 2
? await Rooms.findOneById(uids.join(''), { projection: { _id: 1 } })
: await Rooms.findOneDirectRoomContainingAllUserIDs(uids, { projection: { _id: 1 } });
const room: IRoom | null = options?.forceNew ? null : await Rooms.findOneDirectRoomContainingAllUserIDs(uids, { projection: { _id: 1 } });

const isNewRoom = !room;

const roomInfo = {
...(uids.length === 2 && { _id: uids.join('') }), // Deprecated: using users' _id to compose the room _id is deprecated
t: 'd',
usernames,
usersCount: members.length,
Expand Down Expand Up @@ -186,6 +183,7 @@ export async function createDirectRoom(
...options?.subscriptionExtra,
...(options?.creator !== member._id && { open: members.length > 2 }),
...subscriptionStatus,
...(roomExtraData.federated && member._id === options?.creator && { roles: ['owner'] }),
}),
},
{ upsert: true },
Expand Down
5 changes: 2 additions & 3 deletions apps/meteor/app/lib/server/methods/addUsersToRoom.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { api } from '@rocket.chat/core-services';
import type { IUser } from '@rocket.chat/core-typings';
import { isRoomNativeFederated, type IUser } from '@rocket.chat/core-typings';
import type { ServerMethods } from '@rocket.chat/ddp-client';
import { Subscriptions, Users, Rooms } from '@rocket.chat/models';
import { Match } from 'meteor/check';
Expand Down Expand Up @@ -52,8 +52,7 @@ export const addUsersToRoomMethod = async (userId: string, data: { rid: string;
});
const userInRoom = subscription != null;

// TODO: Can't add to direct room ever, unless it's a federated room
if (room.t === 'd') {
if (room.t === 'd' && !isRoomNativeFederated(room)) {
throw new Meteor.Error('error-cant-invite-for-direct-room', "Can't invite user to direct rooms", {
method: 'addUsersToRoom',
});
Expand Down
10 changes: 9 additions & 1 deletion apps/meteor/server/services/room/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export class RoomService extends ServiceClassInternal implements IRoomService {
protected name = 'room';

async updateDirectMessageRoomName(room: IRoom): Promise<boolean> {
const subs = await Subscriptions.findByRoomId(room._id, { projection: { u: 1 } }).toArray();
const subs = await Subscriptions.findByRoomId(room._id, { projection: { u: 1, status: 1 } }).toArray();

const uids = subs.map((sub) => sub.u._id);

Expand All @@ -46,6 +46,10 @@ export class RoomService extends ServiceClassInternal implements IRoomService {
const roomNames = getNameForDMs(roomMembers);

for await (const sub of subs) {
// don't update the name if the user is invited but hasn't accepted yet
if (sub.status === 'INVITED') {
continue;
}
await Subscriptions.updateOne({ _id: sub._id }, { $set: roomNames[sub.u._id] });

void notifyOnSubscriptionChangedByRoomIdAndUserId(room._id, sub.u._id, 'updated');
Expand Down Expand Up @@ -259,6 +263,7 @@ export class RoomService extends ServiceClassInternal implements IRoomService {
skipAlertSound = false,
skipSystemMessage = false,
status,
roles,
}: {
room: IRoom;
ts: Date;
Expand All @@ -268,6 +273,7 @@ export class RoomService extends ServiceClassInternal implements IRoomService {
skipAlertSound?: boolean;
skipSystemMessage?: boolean;
status?: 'INVITED';
roles?: ISubscription['roles'];
}): Promise<string | undefined> {
const autoTranslateConfig = getSubscriptionAutotranslateDefaultConfig(userToBeAdded);

Expand All @@ -278,10 +284,12 @@ export class RoomService extends ServiceClassInternal implements IRoomService {
unread: 1,
userMentions: 1,
groupMentions: 0,
...(roles && { roles }),
...(status && { status }),
...(inviter && { inviter: { _id: inviter._id, username: inviter.username!, name: inviter.name } }),
...autoTranslateConfig,
...getDefaultSubscriptionPref(userToBeAdded),
...(room.t === 'd' && inviter && { fname: inviter.name, name: inviter.username }),
});

if (insertedId) {
Expand Down
2 changes: 1 addition & 1 deletion apps/meteor/tests/e2e/create-direct.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,6 @@ test.describe.serial('channel-direct-message', () => {
await page.keyboard.press('Enter');
await poHomeChannel.sidenav.btnCreate.click();

await expect(page).toHaveURL('direct/rocket.catrocketchat.internal.admin.test');
await expect(page).toHaveURL(/direct\/.*/);
});
});
2 changes: 1 addition & 1 deletion apps/meteor/tests/e2e/e2e-encryption/e2ee-otr.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ test.describe('E2EE OTR (Off-The-Record)', () => {
await page.keyboard.press('Enter');
await poHomeChannel.sidenav.btnCreate.click();

await expect(page).toHaveURL(`/direct/user2${Users.userE2EE.data.username}`);
await expect(page).toHaveURL(/direct\/.*/);

await poHomeChannel.tabs.kebab.click({ force: true });
if (await poHomeChannel.tabs.btnDisableE2E.isVisible()) {
Expand Down
1 change: 1 addition & 0 deletions ee/packages/federation-matrix/src/FederationMatrix.ts
Original file line number Diff line number Diff line change
Expand Up @@ -922,6 +922,7 @@ export class FederationMatrix extends ServiceClass implements IFederationMatrixS

await Room.performAcceptRoomInvite(room, subscription, user);
}

if (action === 'reject') {
try {
await federationSDK.rejectInvite(room.federation.mrid, matrixUserId);
Expand Down
25 changes: 19 additions & 6 deletions ee/packages/federation-matrix/src/events/member.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ async function getOrCreateFederatedRoom({
name: roomName,
members: inviteeUsername ? [inviteeUsername, inviterUsername] : [inviterUsername],
options: {
forceNew: true, // an invite means the room does not exist yet
creator: inviterUserId,
},
extraData: {
Expand Down Expand Up @@ -137,10 +138,6 @@ async function handleInvite({

const joinRuleType = getJoinRuleType(strippedState);

// DMs do not have a join rule type (they are treated as invite only rooms),
// so we use 'd' for direct messages translation to RC.
const roomType = content?.is_direct ? 'd' : joinRuleType;

const roomOriginDomain = senderId.split(':')?.pop();
if (!roomOriginDomain) {
throw new Error(`Room origin domain not found: ${roomId}`);
Expand All @@ -149,9 +146,14 @@ async function handleInvite({
const roomNameState = strippedState?.find((state: PduForType<'m.room.name'>) => state.type === 'm.room.name');
const matrixRoomName = roomNameState?.content?.name;

// DMs do not have a join rule type (they are treated as invite only rooms),
// so we use 'd' for direct messages translation to RC.
const roomType = content?.is_direct || !matrixRoomName ? 'd' : joinRuleType;

let roomName: string;
let roomFName: string;
if (content?.is_direct) {

if (roomType === 'd') {
roomName = senderId;
roomFName = senderId;
} else {
Expand All @@ -166,8 +168,9 @@ async function handleInvite({
roomType,
inviterUserId: inviterUser._id,
inviterUsername: inviterUser.username as string, // TODO: Remove force cast
inviteeUsername: content?.is_direct ? inviteeUser.username : undefined,
inviteeUsername: roomType === 'd' ? inviteeUser.username : undefined,
});

if (!room) {
throw new Error(`Room not found or could not be created: ${roomId}`);
}
Expand All @@ -184,6 +187,11 @@ async function handleInvite({
inviter: inviterUser,
status: 'INVITED',
});

// if an invite is sent to a DM, we need to update the room name to reflect all participants
if (room.t === 'd') {
await Room.updateDirectMessageRoomName(room);
}
}

async function handleJoin({
Expand All @@ -205,6 +213,11 @@ async function handleJoin({
throw new Error(`Subscription not found while joining user ${userId} to room ${roomId}`);
}

// update room name for DMs
if (room.t === 'd') {
await Room.updateDirectMessageRoomName(room);
}

if (!subscription.status) {
logger.info('User is already joined to the room, skipping...');
return;
Expand Down
Loading
Loading