From dccc4bc2f9ad0f4a56da6c53ef51028f7bd9113e Mon Sep 17 00:00:00 2001 From: juancarmore Date: Mon, 12 Jan 2026 11:52:32 +0100 Subject: [PATCH] backend: add room member error handling for existing members and role restrictions --- meet-ce/backend/src/models/error.model.ts | 24 ++++++++++++------- .../src/services/room-member.service.ts | 23 +++++++++++++++--- 2 files changed, 36 insertions(+), 11 deletions(-) diff --git a/meet-ce/backend/src/models/error.model.ts b/meet-ce/backend/src/models/error.model.ts index 6b94d1c0..2b50c1eb 100644 --- a/meet-ce/backend/src/models/error.model.ts +++ b/meet-ce/backend/src/models/error.model.ts @@ -231,19 +231,27 @@ export const errorDeletingRoom = (errorCode: MeetRoomDeletionErrorCode, message: return new OpenViduMeetError(errorCode, message, 409); }; -export const errorInvalidRoomMemberToken = (): OpenViduMeetError => { - return new OpenViduMeetError('Room Error', 'Invalid room member token', 400); -}; - -export const errorInvalidRoomMemberRole = (): OpenViduMeetError => { - return new OpenViduMeetError('Room Error', 'No valid room member role provided', 400); -}; +// Room member errors export const errorRoomMemberNotFound = (roomId: string, memberId: string): OpenViduMeetError => { return new OpenViduMeetError('Room Member Error', `Room member '${memberId}' not found in room '${roomId}'`, 404); }; -// Participant errors +export const errorRoomMemberAlreadyExists = (roomId: string, userId: string): OpenViduMeetError => { + return new OpenViduMeetError('Room Member Error', `User '${userId}' is already a member of room '${roomId}'`, 409); +}; + +export const errorRoomMemberCannotBeOwnerOrAdmin = (roomId: string, userId: string): OpenViduMeetError => { + return new OpenViduMeetError( + 'Room Member Error', + `User '${userId}' cannot be added as a member of room '${roomId}' because they are the room owner or an admin`, + 409 + ); +}; + +export const errorInvalidRoomMemberToken = (): OpenViduMeetError => { + return new OpenViduMeetError('Room Member Error', 'Invalid room member token', 400); +}; export const errorParticipantNotFound = (participantIdentity: string, roomId: string): OpenViduMeetError => { return new OpenViduMeetError( diff --git a/meet-ce/backend/src/services/room-member.service.ts b/meet-ce/backend/src/services/room-member.service.ts index 5c12c8ff..8055053f 100644 --- a/meet-ce/backend/src/services/room-member.service.ts +++ b/meet-ce/backend/src/services/room-member.service.ts @@ -23,6 +23,8 @@ import { errorInvalidRoomSecret, errorParticipantNotFound, errorRoomClosed, + errorRoomMemberAlreadyExists, + errorRoomMemberCannotBeOwnerOrAdmin, errorRoomMemberNotFound, errorUnauthorized, errorUserNotFound @@ -64,23 +66,38 @@ export class RoomMemberService { async createRoomMember(roomId: string, memberOptions: MeetRoomMemberOptions): Promise { const { userId, name, baseRole, customPermissions } = memberOptions; - // Generate memberId and member name let memberId: string; let memberName: string; let accessUrl = `/room/${roomId}`; if (userId) { - // Registered user: memberId = userId, get name from user service + // Registered user const user = await this.userService.getUser(userId); if (!user) { throw errorUserNotFound(userId); } + // Check if user is already a member of the room + const existingMember = await this.getRoomMember(roomId, userId); + + if (existingMember) { + throw errorRoomMemberAlreadyExists(roomId, userId); + } + + // Check that user is not admin or the owner of the room + const isOwner = await this.roomService.isRoomOwner(roomId, userId); + + if (user.role === MeetUserRole.ADMIN || isOwner) { + throw errorRoomMemberCannotBeOwnerOrAdmin(roomId, userId); + } + + // Use userId as memberId and user's name memberId = userId; memberName = user.name; } else if (name) { - // External user: generate memberId, use provided name + // External user + // Generate memberId and use provided name memberId = `ext-${secureUid(10)}`; memberName = name; accessUrl += `?secret=${memberId}`;