diff --git a/backend/openapi/components/responses/internal/success-get-room-preferences.yaml b/backend/openapi/components/responses/internal/success-get-room-preferences.yaml new file mode 100644 index 0000000..13c13f7 --- /dev/null +++ b/backend/openapi/components/responses/internal/success-get-room-preferences.yaml @@ -0,0 +1,16 @@ +description: Success response for retrieving the room preferences +content: + application/json: + schema: + $ref: '../../schemas/meet-room-preferences.yaml' + examples: + complete_room_details: + summary: Room preferences response + value: + preferences: + chatPreferences: + enabled: true + recordingPreferences: + enabled: false + virtualBackgroundPreferences: + enabled: true diff --git a/backend/openapi/openvidu-meet-internal-api.yaml b/backend/openapi/openvidu-meet-internal-api.yaml index 530c78b..589f80c 100644 --- a/backend/openapi/openvidu-meet-internal-api.yaml +++ b/backend/openapi/openvidu-meet-internal-api.yaml @@ -24,6 +24,8 @@ paths: $ref: './paths/internal/global-preferences.yaml#/~1preferences~1appearance' /rooms/{roomId}: $ref: './paths/internal/rooms.yaml#/~1rooms~1{roomId}' + /rooms/{roomId}/preferences: + $ref: './paths/internal/rooms.yaml#/~1rooms~1{roomId}~1preferences' /rooms/{roomId}/recording-token: $ref: './paths/internal/rooms.yaml#/~1rooms~1{roomId}~1recording-token' /rooms/{roomId}/roles: diff --git a/backend/openapi/paths/internal/rooms.yaml b/backend/openapi/paths/internal/rooms.yaml index 1253fe4..1457449 100644 --- a/backend/openapi/paths/internal/rooms.yaml +++ b/backend/openapi/paths/internal/rooms.yaml @@ -25,6 +25,29 @@ $ref: '../../components/responses/validation-error.yaml' '500': $ref: '../../components/responses/internal-server-error.yaml' +/rooms/{roomId}/preferences: + get: + operationId: getRoomPreferences + summary: Get room preferences + description: > + Retrieves the preferences of an OpenVidu Meet room with the specified room ID. + tags: + - Internal API - Rooms + parameters: + - $ref: '../../components/parameters/room-id-path.yaml' + responses: + '200': + $ref: '../../components/responses/internal/success-get-room-preferences.yaml' + '401': + $ref: '../../components/responses/unauthorized-error.yaml' + '403': + $ref: '../../components/responses/forbidden-error.yaml' + '404': + $ref: '../../components/responses/error-room-not-found.yaml' + '422': + $ref: '../../components/responses/validation-error.yaml' + '500': + $ref: '../../components/responses/internal-server-error.yaml' /rooms/{roomId}/recording-token: post: operationId: generateRecordingToken diff --git a/backend/src/controllers/room.controller.ts b/backend/src/controllers/room.controller.ts index 943260b..b8ffabd 100644 --- a/backend/src/controllers/room.controller.ts +++ b/backend/src/controllers/room.controller.ts @@ -209,3 +209,18 @@ export const getRoomRoleAndPermissions = async (req: Request, res: Response) => handleError(res, error, `getting room role and permissions for room '${roomId}' and secret '${secret}'`); } }; + +export const getRoomPreferences = async (req: Request, res: Response) => { + const logger = container.get(LoggerService); + const roomService = container.get(RoomService); + const { roomId } = req.params; + + logger.verbose(`Getting room preferences for room '${roomId}'`); + + try { + const { preferences } = await roomService.getMeetRoom(roomId); + return res.status(200).json(preferences); + } catch (error) { + handleError(res, error, `getting room preferences for room '${roomId}'`); + } +}; diff --git a/backend/src/routes/room.routes.ts b/backend/src/routes/room.routes.ts index 9be50fd..c2ace5a 100644 --- a/backend/src/routes/room.routes.ts +++ b/backend/src/routes/room.routes.ts @@ -87,3 +87,10 @@ internalRoomRouter.get( withValidRoomId, roomCtrl.getRoomRoleAndPermissions ); + +internalRoomRouter.get( + '/:roomId/preferences', + withAuth(participantTokenValidator), + withValidRoomId, + roomCtrl.getRoomPreferences +); diff --git a/backend/tests/helpers/assertion-helpers.ts b/backend/tests/helpers/assertion-helpers.ts index 410f8e6..ae11bc7 100644 --- a/backend/tests/helpers/assertion-helpers.ts +++ b/backend/tests/helpers/assertion-helpers.ts @@ -93,6 +93,12 @@ export const expectSuccessRoomResponse = ( expectValidRoom(response.body, idPrefix, autoDeletionDate, preferences); }; +export const expectSuccessRoomPreferencesResponse = (response: any, preferences: MeetRoomPreferences) => { + expect(response.status).toBe(200); + expect(response.body).toBeDefined(); + expect(response.body).toEqual(preferences); +}; + export const expectValidRoom = ( room: MeetRoom, idPrefix: string, @@ -187,7 +193,9 @@ export const expectValidRecordingLocationHeader = (response: any) => { const locationHeader = response.headers.location; expect(locationHeader).toBeDefined(); const locationHeaderUrl = new URL(locationHeader); - expect(locationHeaderUrl.pathname).toBe(`${INTERNAL_CONFIG.API_BASE_PATH_V1}/recordings/${response.body.recordingId}`); + expect(locationHeaderUrl.pathname).toBe( + `${INTERNAL_CONFIG.API_BASE_PATH_V1}/recordings/${response.body.recordingId}` + ); }; /** diff --git a/backend/tests/helpers/request-helpers.ts b/backend/tests/helpers/request-helpers.ts index 813e483..b3c0812 100644 --- a/backend/tests/helpers/request-helpers.ts +++ b/backend/tests/helpers/request-helpers.ts @@ -200,6 +200,15 @@ export const getRoom = async (roomId: string, fields?: string) => { .query({ fields }); }; +export const getRoomPreferences = async (roomId: string, cookie: string) => { + checkAppIsRunning(); + + return await request(app) + .get(`${INTERNAL_CONFIG.INTERNAL_API_BASE_PATH_V1}/rooms/${roomId}/preferences`) + .set('Cookie', cookie) + .send(); +}; + export const updateRoomPreferences = async (roomId: string, preferences: any) => { checkAppIsRunning(); diff --git a/backend/tests/helpers/test-scenarios.ts b/backend/tests/helpers/test-scenarios.ts index ed5b8a6..d5ef6e0 100644 --- a/backend/tests/helpers/test-scenarios.ts +++ b/backend/tests/helpers/test-scenarios.ts @@ -2,7 +2,7 @@ import express, { Request, Response } from 'express'; import http from 'http'; import { StringValue } from 'ms'; import { MeetRoomHelper } from '../../src/helpers'; -import { MeetRoom } from '../../src/typings/ce'; +import { MeetRoom, MeetRoomPreferences } from '../../src/typings/ce'; import { expectValidStartRecordingResponse } from './assertion-helpers'; import { createRoom, @@ -36,9 +36,10 @@ export interface TestContext { * @param withParticipant Whether to join a fake participant in the room. * @returns Room data including secrets and cookies. */ -export const setupSingleRoom = async (withParticipant = false, roomPrefix = 'TEST_ROOM'): Promise => { +export const setupSingleRoom = async (withParticipant = false, roomPrefix = 'TEST_ROOM', preferences?: MeetRoomPreferences): Promise => { const room = await createRoom({ - roomIdPrefix: roomPrefix + roomIdPrefix: roomPrefix, + preferences }); // Extract the room secrets and generate participant tokens, saved as cookies diff --git a/backend/tests/integration/api/rooms/get-room-preferences.test.ts b/backend/tests/integration/api/rooms/get-room-preferences.test.ts new file mode 100644 index 0000000..034b68f --- /dev/null +++ b/backend/tests/integration/api/rooms/get-room-preferences.test.ts @@ -0,0 +1,56 @@ +import { afterEach, beforeAll, describe, it } from '@jest/globals'; +import { MeetRecordingAccess } from '../../../../src/typings/ce/index.js'; +import { expectSuccessRoomPreferencesResponse } from '../../../helpers/assertion-helpers.js'; +import { deleteAllRooms, getRoomPreferences, startTestServer } from '../../../helpers/request-helpers.js'; +import { setupSingleRoom } from '../../../helpers/test-scenarios.js'; + +describe('Room API Tests', () => { + const DEFAULT_PREFERENCES = { + recordingPreferences: { + enabled: true, + allowAccessTo: MeetRecordingAccess.ADMIN_MODERATOR_PUBLISHER + }, + chatPreferences: { enabled: true }, + virtualBackgroundPreferences: { enabled: true } + }; + beforeAll(() => { + startTestServer(); + }); + + afterEach(async () => { + // Remove all rooms created + await deleteAllRooms(); + }); + + describe('Get Room Preferences Tests', () => { + it('should successfully retrieve a room by its ID', async () => { + const roomData = await setupSingleRoom(); + const roomId = roomData.room.roomId; + const cookie = roomData.moderatorCookie; + + const response = await getRoomPreferences(roomId, cookie); + expectSuccessRoomPreferencesResponse(response, DEFAULT_PREFERENCES); + }); + + it('should retrieve custom room preferences', async () => { + const payload = { + roomIdPrefix: 'custom-prefs', + preferences: { + recordingPreferences: { + enabled: true, + allowAccessTo: MeetRecordingAccess.ADMIN_MODERATOR_PUBLISHER + }, + chatPreferences: { enabled: true }, + virtualBackgroundPreferences: { enabled: false } + } + }; + + const roomData = await setupSingleRoom(false, payload.roomIdPrefix, payload.preferences); + const roomId = roomData.room.roomId; + const cookie = roomData.moderatorCookie; + + const response = await getRoomPreferences(roomId, cookie); + expectSuccessRoomPreferencesResponse(response, payload.preferences); + }); + }); +});