backend: add updateRoomStatus endpoint and validation for room status updates

This commit is contained in:
juancarmore 2025-08-29 17:40:26 +02:00
parent 2466acabce
commit 982247736e
4 changed files with 76 additions and 1 deletions

View File

@ -150,6 +150,30 @@ export const updateRoomPreferences = async (req: Request, res: Response) => {
} }
}; };
export const updateRoomStatus = async (req: Request, res: Response) => {
const logger = container.get(LoggerService);
const roomService = container.get(RoomService);
const { status } = req.body;
const { roomId } = req.params;
logger.verbose(`Updating room status for room '${roomId}' to '${status}'`);
try {
const { room, updated } = await roomService.updateMeetRoomStatus(roomId, status);
let message: string;
if (updated) {
message = `Room '${roomId}' ${status} successfully`;
} else {
message = `Room '${roomId}' scheduled to be closed when the meeting ends`;
}
return res.status(updated ? 200 : 202).json({ message, room });
} catch (error) {
handleError(res, error, `updating room status for room '${roomId}'`);
}
};
export const generateRecordingToken = async (req: Request, res: Response) => { export const generateRecordingToken = async (req: Request, res: Response) => {
const logger = container.get(LoggerService); const logger = container.get(LoggerService);
const roomService = container.get(RoomService); const roomService = container.get(RoomService);

View File

@ -8,6 +8,7 @@ import {
MeetRoomFilters, MeetRoomFilters,
MeetRoomOptions, MeetRoomOptions,
MeetRoomPreferences, MeetRoomPreferences,
MeetRoomStatus,
MeetVirtualBackgroundPreferences, MeetVirtualBackgroundPreferences,
ParticipantRole, ParticipantRole,
RecordingPermissions RecordingPermissions
@ -207,6 +208,10 @@ const UpdateRoomPreferencesSchema = z.object({
preferences: RoomPreferencesSchema preferences: RoomPreferencesSchema
}); });
const UpdateRoomStatusSchema = z.object({
status: z.enum([MeetRoomStatus.OPEN, MeetRoomStatus.CLOSED])
});
const RecordingTokenRequestSchema = z.object({ const RecordingTokenRequestSchema = z.object({
secret: z.string().nonempty('Secret is required') secret: z.string().nonempty('Secret is required')
}); });
@ -299,6 +304,17 @@ export const withValidRoomBulkDeleteRequest = (req: Request, res: Response, next
next(); next();
}; };
export const withValidRoomStatus = (req: Request, res: Response, next: NextFunction) => {
const { success, error, data } = UpdateRoomStatusSchema.safeParse(req.body);
if (!success) {
return rejectUnprocessableRequest(res, error);
}
req.body = data;
next();
};
export const withValidRoomSecret = (req: Request, res: Response, next: NextFunction) => { export const withValidRoomSecret = (req: Request, res: Response, next: NextFunction) => {
const { success, error, data } = RecordingTokenRequestSchema.safeParse(req.body); const { success, error, data } = RecordingTokenRequestSchema.safeParse(req.body);

View File

@ -16,7 +16,8 @@ import {
withValidRoomId, withValidRoomId,
withValidRoomOptions, withValidRoomOptions,
withValidRoomPreferences, withValidRoomPreferences,
withValidRoomSecret withValidRoomSecret,
withValidRoomStatus
} from '../middlewares/index.js'; } from '../middlewares/index.js';
export const roomRouter = Router(); export const roomRouter = Router();
@ -42,6 +43,7 @@ roomRouter.delete(
withValidRoomBulkDeleteRequest, withValidRoomBulkDeleteRequest,
roomCtrl.bulkDeleteRooms roomCtrl.bulkDeleteRooms
); );
roomRouter.get( roomRouter.get(
'/:roomId', '/:roomId',
withAuth(apiKeyValidator, tokenAndRoleValidator(UserRole.ADMIN), participantTokenValidator), withAuth(apiKeyValidator, tokenAndRoleValidator(UserRole.ADMIN), participantTokenValidator),
@ -55,6 +57,7 @@ roomRouter.delete(
withValidRoomDeleteRequest, withValidRoomDeleteRequest,
roomCtrl.deleteRoom roomCtrl.deleteRoom
); );
roomRouter.get( roomRouter.get(
'/:roomId/preferences', '/:roomId/preferences',
withAuth(apiKeyValidator, tokenAndRoleValidator(UserRole.ADMIN), participantTokenValidator), withAuth(apiKeyValidator, tokenAndRoleValidator(UserRole.ADMIN), participantTokenValidator),
@ -70,6 +73,14 @@ roomRouter.put(
roomCtrl.updateRoomPreferences roomCtrl.updateRoomPreferences
); );
roomRouter.put(
'/:roomId/status',
withAuth(apiKeyValidator, tokenAndRoleValidator(UserRole.ADMIN)),
withValidRoomId,
withValidRoomStatus,
roomCtrl.updateRoomStatus
);
// Internal room routes // Internal room routes
export const internalRoomRouter = Router(); export const internalRoomRouter = Router();
internalRoomRouter.use(bodyParser.urlencoded({ extended: true })); internalRoomRouter.use(bodyParser.urlencoded({ extended: true }));

View File

@ -146,6 +146,30 @@ export class RoomService {
return room; return room;
} }
/**
* Updates the status of a specific meeting room.
*
* @param roomId - The unique identifier of the meeting room to update
* @param status - The new status to apply to the meeting room
* @returns A Promise that resolves to an object containing the updated room
* and a boolean indicating if the update was immediate or scheduled
*/
async updateMeetRoomStatus(roomId: string, status: MeetRoomStatus): Promise<{ room: MeetRoom; updated: boolean }> {
const room = await this.getMeetRoom(roomId);
// If closing the room while a meeting is active, mark it to be closed when the meeting ends
if (status === MeetRoomStatus.CLOSED && room.status === MeetRoomStatus.ACTIVE_MEETING) {
room.meetingEndAction = MeetingEndAction.CLOSE;
return { room, updated: false };
} else {
room.status = status;
room.meetingEndAction = MeetingEndAction.NONE;
}
await this.storageService.saveMeetRoom(room);
return { room, updated: true };
}
/** /**
* Checks if a meeting room with the specified name exists * Checks if a meeting room with the specified name exists
* *