Skip to content

Commit 5fa1509

Browse files
authored
fix: guest room limit incorrectly counting DMs (RocketChat#37919)
1 parent f29a04e commit 5fa1509

6 files changed

Lines changed: 45 additions & 5 deletions

File tree

.changeset/strange-ants-impress.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
'@rocket.chat/model-typings': patch
3+
'@rocket.chat/models': patch
4+
'@rocket.chat/meteor': patch
5+
---
6+
7+
Makes roomsPerGuest exclude DMs when counting subscriptions, ensuring guest limits apply only to non-DM rooms as per expected behavior.

apps/meteor/ee/app/license/server/startup.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,9 @@ export const startLicense = async () => {
107107

108108
License.setLicenseLimitCounter('activeUsers', () => Users.getActiveLocalUserCount());
109109
License.setLicenseLimitCounter('guestUsers', () => Users.getActiveLocalGuestCount());
110-
License.setLicenseLimitCounter('roomsPerGuest', async (context) => (context?.userId ? Subscriptions.countByUserId(context.userId) : 0));
110+
License.setLicenseLimitCounter('roomsPerGuest', async (context) =>
111+
context?.userId ? Subscriptions.countByUserIdExceptType(context.userId, 'd') : 0,
112+
);
111113
License.setLicenseLimitCounter('privateApps', () => getAppCount('private'));
112114
License.setLicenseLimitCounter('marketplaceApps', () => getAppCount('marketplace'));
113115
License.setLicenseLimitCounter('monthlyActiveContacts', () => LivechatContacts.countContactsOnPeriod(moment.utc().format('YYYY-MM')));

apps/meteor/ee/server/startup/maxRoomsPerGuest.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@ callbacks.add(
88
'beforeAddedToRoom',
99
async ({ user }) => {
1010
if (user.roles?.includes('guest')) {
11-
if (await License.shouldPreventAction('roomsPerGuest', 0, { userId: user._id })) {
11+
// extraCount = 1 checks if adding one more room would exceed the limit
12+
// (not if they've already exceeded it, since this runs before adding them to the room)
13+
if (await License.shouldPreventAction('roomsPerGuest', 1, { userId: user._id })) {
1214
throw new Meteor.Error('error-max-rooms-per-guest-reached', i18n.t('error-max-rooms-per-guest-reached'));
1315
}
1416
}

ee/packages/license/src/license.spec.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,32 @@ describe('Validate License Limits', () => {
271271
expect(fairUsageCallback).toHaveBeenCalledTimes(0);
272272
expect(preventActionCallback).toHaveBeenCalledTimes(0);
273273
});
274+
275+
it('should check roomsPerGuest with per-user context', async () => {
276+
const licenseManager = await getReadyLicenseManager();
277+
const license = new MockedLicenseBuilder().withLimits('roomsPerGuest', [
278+
{
279+
max: 3,
280+
behavior: 'prevent_action',
281+
},
282+
]);
283+
284+
await expect(licenseManager.setLicense(await license.sign())).resolves.toBe(true);
285+
286+
licenseManager.setLicenseLimitCounter('roomsPerGuest', (context) => {
287+
switch (context?.userId) {
288+
case 'user1':
289+
return 2;
290+
case 'user2':
291+
return 3;
292+
default:
293+
return 0;
294+
}
295+
});
296+
297+
await expect(licenseManager.shouldPreventAction('roomsPerGuest', 1, { userId: 'user1' })).resolves.toBe(false);
298+
await expect(licenseManager.shouldPreventAction('roomsPerGuest', 1, { userId: 'user2' })).resolves.toBe(true);
299+
});
274300
});
275301
});
276302

packages/model-typings/src/models/ISubscriptionsModel.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -329,7 +329,7 @@ export interface ISubscriptionsModel extends IBaseModel<ISubscription> {
329329

330330
countByRoomIdAndRoles(roomId: string, roles: string[]): Promise<number>;
331331
countByRoomId(roomId: string, options?: CountDocumentsOptions): Promise<number>;
332-
countByUserId(userId: string): Promise<number>;
332+
countByUserIdExceptType(userId: string, typeException: ISubscription['t']): Promise<number>;
333333
openByRoomIdAndUserId(roomId: string, userId: string): Promise<UpdateResult>;
334334
countByRoomIdAndNotUserId(rid: string, uid: string): Promise<number>;
335335
countByRoomIdWhenUsernameExists(rid: string): Promise<number>;

packages/models/src/models/Subscriptions.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1172,8 +1172,11 @@ export class SubscriptionsRaw extends BaseRaw<ISubscription> implements ISubscri
11721172
return this.countDocuments(query);
11731173
}
11741174

1175-
countByUserId(userId: string): Promise<number> {
1176-
const query = { 'u._id': userId };
1175+
countByUserIdExceptType(userId: string, typeException: ISubscription['t']): Promise<number> {
1176+
const query: Filter<ISubscription> = {
1177+
'u._id': userId,
1178+
't': { $ne: typeException },
1179+
};
11771180

11781181
return this.countDocuments(query);
11791182
}

0 commit comments

Comments
 (0)