Skip to content

Commit 3dfb557

Browse files
authored
fix: teams.addMembers API to assign roles properly (RocketChat#36852)
1 parent e10eca1 commit 3dfb557

4 files changed

Lines changed: 108 additions & 8 deletions

File tree

.changeset/nice-bottles-breathe.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
'@rocket.chat/core-services': patch
3+
'@rocket.chat/meteor': patch
4+
---
5+
6+
Fixes `teams.addMembers` API to assign team member roles properly.

apps/meteor/server/services/team/service.ts

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Room, Authorization, Message, ServiceClassInternal } from '@rocket.chat/core-services';
1+
import { Room, Authorization, Message, ServiceClassInternal, api } from '@rocket.chat/core-services';
22
import type {
33
IListRoomsFilter,
44
ITeamAutocompleteResult,
@@ -723,7 +723,21 @@ export class TeamService extends ServiceClassInternal implements ITeamService {
723723
await addUserToRoom(team.roomId, user, createdBy, { skipSystemMessage: false });
724724

725725
if (member.roles) {
726-
await this.addRolesToMember(teamId, member.userId, member.roles);
726+
const isRoleAddedToTeam = await this.addRolesToMember(teamId, member.userId, member.roles);
727+
const isRoleAddedToSubscription = await this.addRolesToSubscription(team.roomId, member.userId, member.roles);
728+
if (settings.get<boolean>('UI_DisplayRoles') && isRoleAddedToTeam && isRoleAddedToSubscription) {
729+
member.roles.forEach((role) => {
730+
void api.broadcast('user.roleUpdate', {
731+
type: 'added',
732+
_id: role,
733+
u: {
734+
_id: user._id,
735+
username: user.username,
736+
},
737+
scope: team.roomId,
738+
});
739+
});
740+
}
727741
}
728742
}
729743
}
@@ -939,6 +953,17 @@ export class TeamService extends ServiceClassInternal implements ITeamService {
939953
return !!(await TeamMember.updateRolesByTeamIdAndUserId(teamId, userId, roles));
940954
}
941955

956+
async addRolesToSubscription(roomId: string, userId: string, roles: Array<string>): Promise<boolean> {
957+
const subscription = await Subscriptions.findOneByRoomIdAndUserId(roomId, userId);
958+
959+
if (!subscription) {
960+
// TODO should this throw an error instead?
961+
return false;
962+
}
963+
964+
return !!(await Subscriptions.addRolesByUserId(userId, roles, roomId));
965+
}
966+
942967
async removeRolesFromMember(teamId: string, userId: string, roles: Array<string>): Promise<boolean> {
943968
const isMember = await TeamMember.findOneByUserIdAndTeamId(userId, teamId, {
944969
projection: { _id: 1 },

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

Lines changed: 74 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -430,11 +430,6 @@ describe('/teams.addMembers', () => {
430430
let testUser: TestUser<IUser>;
431431
let testUser2: TestUser<IUser>;
432432

433-
before(async () => {
434-
testUser = await createUser();
435-
testUser2 = await createUser();
436-
});
437-
438433
before('Create test team', (done) => {
439434
void request
440435
.post(api('teams.create'))
@@ -449,7 +444,14 @@ describe('/teams.addMembers', () => {
449444
});
450445
});
451446

452-
after(() => Promise.all([deleteUser(testUser), deleteUser(testUser2), deleteTeam(credentials, teamName)]));
447+
after(() => deleteTeam(credentials, teamName));
448+
449+
beforeEach(async () => {
450+
testUser = await createUser();
451+
testUser2 = await createUser();
452+
});
453+
454+
afterEach(() => Promise.all([deleteUser(testUser), deleteUser(testUser2)]));
453455

454456
it('should add members to a public team', (done) => {
455457
void request
@@ -516,6 +518,72 @@ describe('/teams.addMembers', () => {
516518
.then(() => done())
517519
.catch(done);
518520
});
521+
522+
it('should add members and assign roles to them properly', (done) => {
523+
void request
524+
.post(api('teams.addMembers'))
525+
.set(credentials)
526+
.send({
527+
teamName: testTeam.name,
528+
members: [
529+
{
530+
userId: testUser._id,
531+
roles: ['owner', 'leader'],
532+
},
533+
{
534+
userId: testUser2._id,
535+
roles: ['moderator'],
536+
},
537+
],
538+
})
539+
.expect('Content-Type', 'application/json')
540+
.expect(200)
541+
.expect((res) => {
542+
expect(res.body).to.have.property('success', true);
543+
})
544+
.then(() =>
545+
request
546+
.get(api('rooms.membersOrderedByRole'))
547+
.set(credentials)
548+
.query({
549+
roomId: testTeam.roomId,
550+
})
551+
.expect('Content-Type', 'application/json')
552+
.expect(200)
553+
.expect((response) => {
554+
expect(response.body).to.have.property('success', true);
555+
expect(response.body).to.have.property('members');
556+
expect(response.body.members).to.have.length(3);
557+
expect(response.body.members[1]).to.have.property('_id');
558+
expect(response.body.members[1]).to.have.property('roles');
559+
expect(response.body.members[1]).to.have.property('username');
560+
expect(response.body.members[1]).to.have.property('name');
561+
562+
const members = (response.body.members as IUser[]).map(({ _id, username, name, roles }) => ({
563+
_id,
564+
username,
565+
name,
566+
roles,
567+
}));
568+
569+
expect(members).to.deep.own.include({
570+
_id: testUser._id,
571+
username: testUser.username,
572+
name: testUser.name,
573+
roles: ['owner', 'leader'],
574+
});
575+
576+
expect(members).to.deep.own.include({
577+
_id: testUser2._id,
578+
username: testUser2.username,
579+
name: testUser2.name,
580+
roles: ['moderator'],
581+
});
582+
}),
583+
)
584+
.then(() => done())
585+
.catch(done);
586+
});
519587
});
520588

521589
describe('/teams.members', () => {

packages/core-services/src/types/ITeamService.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ export interface ITeamService {
125125
getStatistics(): Promise<ITeamStats>;
126126
findBySubscribedUserIds(userId: string, callerId?: string): Promise<ITeam[]>;
127127
addRolesToMember(teamId: string, userId: string, roles: Array<string>): Promise<boolean>;
128+
addRolesToSubscription(roomId: string, userId: string, roles: Array<string>): Promise<boolean>;
128129
getRoomInfo(
129130
room: AtLeast<IRoom, 'teamId' | 'teamMain' | '_id'>,
130131
): Promise<{ team?: Pick<ITeam, 'name' | 'roomId' | 'type'>; parentRoom?: Pick<IRoom, 'name' | 'fname' | 't' | '_id'> }>;

0 commit comments

Comments
 (0)