Skip to content

Commit 9ca4955

Browse files
Merge branch 'feat/add-endpoints-groups.membersOrderedByRole-channels.membersOrderedByRole' into feat/members-virtuoso-group
2 parents 1cd78d6 + 9f33896 commit 9ca4955

File tree

5 files changed

+97
-20
lines changed

5 files changed

+97
-20
lines changed

apps/meteor/app/api/server/v1/rooms.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { Media, Team } from '@rocket.chat/core-services';
22
import type { IRoom, IUpload } from '@rocket.chat/core-typings';
3+
import { isPrivateRoom, isPublicRoom } from '@rocket.chat/core-typings';
34
import { Messages, Rooms, Users, Uploads, Subscriptions } from '@rocket.chat/models';
45
import type { Notifications } from '@rocket.chat/rest-typings';
56
import {
@@ -874,7 +875,7 @@ API.v1.addRoute(
874875
return API.v1.notFound('The required "roomId" or "roomName" param provided does not match any room');
875876
}
876877

877-
if (findResult.t !== 'c' && findResult.t !== 'p') {
878+
if (!isPublicRoom(findResult) && !isPrivateRoom(findResult)) {
878879
return API.v1.failure('error-room-type-not-supported');
879880
}
880881

apps/meteor/app/lib/server/functions/syncRolePrioritiesForRoomIfRequired.ts

+9-15
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,15 @@
1-
import type { IRole, IRoom, IUser } from '@rocket.chat/core-typings';
2-
import { ROOM_ROLE_PRIORITY_MAP } from '@rocket.chat/core-typings';
1+
import type { IRoom, IUser } from '@rocket.chat/core-typings';
32
import { Subscriptions, Users, Rooms } from '@rocket.chat/models';
43

5-
export const getRoomRolePriorityForRole = (role: IRole['_id']) =>
6-
(ROOM_ROLE_PRIORITY_MAP as { [key: IRole['_id']]: number })[role] ?? ROOM_ROLE_PRIORITY_MAP.default;
7-
8-
export const calculateRoomRolePriorityFromRoles = (roles: IRole['_id'][]) => {
9-
return roles.reduce((acc, roleId) => Math.min(acc, getRoomRolePriorityForRole(roleId)), ROOM_ROLE_PRIORITY_MAP.default);
10-
};
4+
import { calculateRoomRolePriorityFromRoles } from '../../../../server/lib/roles/syncRoomRolePriority';
115

126
const READ_BATCH_SIZE = 1000;
137

14-
async function assignRoomRolePrioritiesFromMap(userIdAndroomRolePrioritiesMap: Map<IUser['_id'], IUser['roomRolePriorities']>) {
8+
async function assignRoomRolePrioritiesFromMap(userIdAndRoomRolePrioritiesMap: Map<IUser['_id'], IUser['roomRolePriorities']>) {
159
const bulk = Users.col.initializeUnorderedBulkOp();
1610

17-
for await (const [userId, roomRolePriorities] of userIdAndroomRolePrioritiesMap.entries()) {
18-
userIdAndroomRolePrioritiesMap.delete(userId);
11+
for await (const [userId, roomRolePriorities] of userIdAndRoomRolePrioritiesMap.entries()) {
12+
userIdAndRoomRolePrioritiesMap.delete(userId);
1913

2014
if (roomRolePriorities) {
2115
const updateFields = Object.entries(roomRolePriorities).reduce(
@@ -39,7 +33,7 @@ async function assignRoomRolePrioritiesFromMap(userIdAndroomRolePrioritiesMap: M
3933
}
4034

4135
export const syncRolePrioritiesForRoomIfRequired = async (rid: IRoom['_id']) => {
42-
const userIdAndroomRolePrioritiesMap = new Map<IUser['_id'], IUser['roomRolePriorities']>();
36+
const userIdAndRoomRolePrioritiesMap = new Map<IUser['_id'], IUser['roomRolePriorities']>();
4337

4438
if (await Rooms.hasCreatedRolePrioritiesForRoom(rid)) {
4539
return;
@@ -62,13 +56,13 @@ export const syncRolePrioritiesForRoomIfRequired = async (rid: IRoom['_id']) =>
6256
const roomId = sub.rid;
6357
const priority = calculateRoomRolePriorityFromRoles(sub.roles);
6458

65-
const existingPriorities = userIdAndroomRolePrioritiesMap.get(userId) || {};
59+
const existingPriorities = userIdAndRoomRolePrioritiesMap.get(userId) || {};
6660
existingPriorities[roomId] = priority;
67-
userIdAndroomRolePrioritiesMap.set(userId, existingPriorities);
61+
userIdAndRoomRolePrioritiesMap.set(userId, existingPriorities);
6862
}
6963

7064
// Flush any remaining priorities in the map
71-
await assignRoomRolePrioritiesFromMap(userIdAndroomRolePrioritiesMap);
65+
await assignRoomRolePrioritiesFromMap(userIdAndRoomRolePrioritiesMap);
7266

7367
await Rooms.markRolePrioritesCreatedForRoom(rid);
7468
};

apps/meteor/server/lib/findUsersOfRoomOrderedByRole.ts

+5-3
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,11 @@ export async function findUsersOfRoomOrderedByRole({
3939
const sortCriteria = {
4040
rolePriority: rolePrioritySort ?? 1,
4141
statusConnection: -1,
42-
...(usernameSort ?? {
43-
...(settings.get('UI_Use_Real_Name') ? { name: 1 } : { username: 1 }),
44-
}),
42+
...(usernameSort
43+
? { username: usernameSort }
44+
: {
45+
...(settings.get('UI_Use_Real_Name') ? { name: 1 } : { username: 1 }),
46+
}),
4547
};
4648

4749
const matchUserFilter = {
+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import type { Credentials } from '@rocket.chat/api-client';
2+
import type { IRole } from '@rocket.chat/core-typings';
3+
4+
import { api, credentials, request } from './api-data';
5+
6+
export const createCustomRole = async ({
7+
name,
8+
scope,
9+
description,
10+
credentials: customCredentials,
11+
}: Pick<IRole, 'name' | 'scope' | 'description'> & { credentials?: Credentials }) => {
12+
const response = await request
13+
.post(api('roles.create'))
14+
.set(customCredentials || credentials)
15+
.send({ name, scope, description });
16+
console.log(response.body);
17+
return response.body.role as IRole;
18+
};
19+
20+
export const deleteCustomRole = async ({ roleId, credentials: customCredentials }: { roleId: IRole['_id']; credentials?: Credentials }) => {
21+
const response = await request
22+
.post(api('roles.delete'))
23+
.set(customCredentials || credentials)
24+
.send({ roleId });
25+
return response.body.success as boolean;
26+
};
27+
28+
export const assignRoleToUser = async ({
29+
username,
30+
roleId,
31+
credentials: customCredentials,
32+
}: {
33+
username: string;
34+
roleId: string;
35+
credentials?: Credentials;
36+
}) => {
37+
const response = await request
38+
.post(api('roles.addUserToRole'))
39+
.set(customCredentials || credentials)
40+
.send({ username, roleId });
41+
return response.body.success as boolean;
42+
};

apps/meteor/tests/end-to-end/api/rooms.ts

+39-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import fs from 'fs';
22
import path from 'path';
33

44
import type { Credentials } from '@rocket.chat/api-client';
5-
import type { IMessage, IRoom, ITeam, IUpload, IUser, ImageAttachmentProps, SettingValue } from '@rocket.chat/core-typings';
5+
import type { IMessage, IRole, IRoom, ITeam, IUpload, IUser, ImageAttachmentProps, SettingValue } from '@rocket.chat/core-typings';
66
import { TEAM_TYPE } from '@rocket.chat/core-typings';
77
import { Random } from '@rocket.chat/random';
88
import { assert, expect } from 'chai';
@@ -13,6 +13,7 @@ import { getCredentials, api, request, credentials } from '../../data/api-data';
1313
import { sendSimpleMessage, deleteMessage } from '../../data/chat.helper';
1414
import { imgURL } from '../../data/interactions';
1515
import { getSettingValueById, updateEEPermission, updatePermission, updateSetting } from '../../data/permissions.helper';
16+
import { assignRoleToUser, createCustomRole, deleteCustomRole } from '../../data/roles.helper';
1617
import { createRoom, deleteRoom } from '../../data/rooms.helper';
1718
import { createTeam, deleteTeam } from '../../data/teams.helper';
1819
import { password } from '../../data/user';
@@ -3637,11 +3638,14 @@ describe('[Rooms]', () => {
36373638
});
36383639

36393640
describe('[/rooms.membersOrderedByRole]', () => {
3641+
const isEnterprise = Boolean(process.env.IS_EE);
3642+
36403643
let testChannel: IRoom;
36413644
let ownerUser: IUser;
36423645
let moderatorUser: IUser;
36433646
let memberUser1: IUser;
36443647
let memberUser2: IUser;
3648+
let customRole: IRole;
36453649

36463650
let ownerCredentials: { 'X-Auth-Token': string; 'X-User-Id': string };
36473651

@@ -3655,6 +3659,12 @@ describe('[Rooms]', () => {
36553659

36563660
ownerCredentials = await login(ownerUser.username, password);
36573661

3662+
customRole = await createCustomRole({
3663+
name: `customRole.${Random.id()}`,
3664+
scope: 'Subscriptions',
3665+
description: 'Custom Role',
3666+
});
3667+
36583668
// Create a public channel
36593669
const roomCreationResponse = await createRoom({
36603670
type: 'c',
@@ -3689,6 +3699,7 @@ describe('[Rooms]', () => {
36893699
after(async () => {
36903700
await deleteRoom({ type: 'c', roomId: testChannel._id });
36913701
await Promise.all([ownerUser, moderatorUser, memberUser1, memberUser2].map((user) => deleteUser(user)));
3702+
await deleteCustomRole({ roleId: customRole._id });
36923703
});
36933704

36943705
it('should return a list of members ordered by owner, moderator, then members by default', async () => {
@@ -3808,6 +3819,33 @@ describe('[Rooms]', () => {
38083819
expect(usernames).to.deep.equal(expected);
38093820
});
38103821

3822+
it('should not be affected by custom roles when sorting', async () => {
3823+
if (!isEnterprise) {
3824+
return;
3825+
}
3826+
await Promise.all([
3827+
assignRoleToUser({ username: moderatorUser.username as string, roleId: customRole._id }),
3828+
assignRoleToUser({ username: memberUser2.username as string, roleId: customRole._id }),
3829+
]);
3830+
3831+
const response = await request
3832+
.get(api('rooms.membersOrderedByRole'))
3833+
.set(credentials)
3834+
.query({
3835+
roomId: testChannel._id,
3836+
})
3837+
.expect('Content-Type', 'application/json')
3838+
.expect(200);
3839+
3840+
expect(response.body).to.have.property('success', true);
3841+
const [first, second, third, fourth] = response.body.members;
3842+
3843+
expect(first.username).to.equal(ownerUser.username);
3844+
expect(second.username).to.equal(moderatorUser.username);
3845+
expect(third.username).to.equal(memberUser1.username);
3846+
expect(fourth.username).to.equal(memberUser2.username);
3847+
});
3848+
38113849
describe('Additional Visibility Tests', () => {
38123850
let outsiderUser: IUser;
38133851
let insideUser: IUser;

0 commit comments

Comments
 (0)