Rename room preferences to room config
This commit is contained in:
parent
686af46102
commit
40742d22f8
@ -0,0 +1,16 @@
|
||||
description: New room config
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
config:
|
||||
$ref: '../schemas/meet-room-config.yaml#/MeetRoomConfig'
|
||||
example:
|
||||
config:
|
||||
chatConfig:
|
||||
enabled: true
|
||||
recordingConfig:
|
||||
enabled: false
|
||||
virtualBackgroundConfig:
|
||||
enabled: true
|
||||
@ -1,16 +0,0 @@
|
||||
description: New room preferences
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
preferences:
|
||||
$ref: '../schemas/meet-room-preferences.yaml#/MeetRoomPreferences'
|
||||
example:
|
||||
preferences:
|
||||
chatPreferences:
|
||||
enabled: true
|
||||
recordingPreferences:
|
||||
enabled: false
|
||||
virtualBackgroundPreferences:
|
||||
enabled: true
|
||||
@ -0,0 +1,5 @@
|
||||
description: Success response for retrieving the room config
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '../schemas/meet-room-config.yaml#/MeetRoomConfig'
|
||||
@ -1,5 +0,0 @@
|
||||
description: Success response for retrieving the room preferences
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '../schemas/meet-room-preferences.yaml#/MeetRoomPreferences'
|
||||
@ -14,12 +14,12 @@ content:
|
||||
autoDeletionPolicy:
|
||||
withMeeting: when_meeting_ends
|
||||
withRecordings: close
|
||||
preferences:
|
||||
chatPreferences:
|
||||
config:
|
||||
chatConfig:
|
||||
enabled: true
|
||||
recordingPreferences:
|
||||
recordingConfig:
|
||||
enabled: false
|
||||
virtualBackgroundPreferences:
|
||||
virtualBackgroundConfig:
|
||||
enabled: true
|
||||
moderatorUrl: 'http://localhost:6080/room/room-123?secret=123456'
|
||||
speakerUrl: 'http://localhost:6080/room/room-123?secret=654321'
|
||||
@ -31,19 +31,19 @@ content:
|
||||
value:
|
||||
roomId: 'room-123'
|
||||
|
||||
fields=roomId,roomName,creationDate,autoDeletionDate,preferences:
|
||||
summary: Room details with roomId, roomName, creationDate, autoDeletionDate, and preferences
|
||||
fields=roomId,roomName,creationDate,autoDeletionDate,config:
|
||||
summary: Room details with roomId, roomName, creationDate, autoDeletionDate, and config
|
||||
value:
|
||||
roomId: 'room-123'
|
||||
roomName: 'room'
|
||||
creationDate: 1620000000000
|
||||
autoDeletionDate: 1900000000000
|
||||
preferences:
|
||||
chatPreferences:
|
||||
config:
|
||||
chatConfig:
|
||||
enabled: true
|
||||
recordingPreferences:
|
||||
recordingConfig:
|
||||
enabled: false
|
||||
virtualBackgroundPreferences:
|
||||
virtualBackgroundConfig:
|
||||
enabled: true
|
||||
|
||||
fields=moderatorUrl,speakerUrl:
|
||||
|
||||
@ -23,12 +23,12 @@ content:
|
||||
autoDeletionPolicy:
|
||||
withMeeting: when_meeting_ends
|
||||
withRecordings: close
|
||||
preferences:
|
||||
chatPreferences:
|
||||
config:
|
||||
chatConfig:
|
||||
enabled: true
|
||||
recordingPreferences:
|
||||
recordingConfig:
|
||||
enabled: false
|
||||
virtualBackgroundPreferences:
|
||||
virtualBackgroundConfig:
|
||||
enabled: true
|
||||
moderatorUrl: 'http://localhost:6080/room/room-123?secret=123456'
|
||||
speakerUrl: 'http://localhost:6080/room/room-123?secret=654321'
|
||||
@ -41,12 +41,12 @@ content:
|
||||
autoDeletionPolicy:
|
||||
withMeeting: when_meeting_ends
|
||||
withRecordings: close
|
||||
preferences:
|
||||
chatPreferences:
|
||||
config:
|
||||
chatConfig:
|
||||
enabled: false
|
||||
recordingPreferences:
|
||||
recordingConfig:
|
||||
enabled: true
|
||||
virtualBackgroundPreferences:
|
||||
virtualBackgroundConfig:
|
||||
enabled: false
|
||||
moderatorUrl: 'http://localhost:6080/room/room-456?secret=789012'
|
||||
speakerUrl: 'http://localhost:6080/room/room-456?secret=210987'
|
||||
@ -65,31 +65,31 @@ content:
|
||||
isTruncated: false
|
||||
maxItems: 10
|
||||
|
||||
fields=roomId,roomName,creationDate,autoDeletionDate,preferences:
|
||||
summary: Room details including preferences but no URLs
|
||||
fields=roomId,roomName,creationDate,autoDeletionDate,config:
|
||||
summary: Room details including config but no URLs
|
||||
value:
|
||||
rooms:
|
||||
- roomId: 'room-123'
|
||||
roomName: 'room'
|
||||
creationDate: 1620000000000
|
||||
autoDeletionDate: 1900000000000
|
||||
preferences:
|
||||
chatPreferences:
|
||||
config:
|
||||
chatConfig:
|
||||
enabled: true
|
||||
recordingPreferences:
|
||||
recordingConfig:
|
||||
enabled: false
|
||||
virtualBackgroundPreferences:
|
||||
virtualBackgroundConfig:
|
||||
enabled: true
|
||||
- roomId: 'room-456'
|
||||
roomName: 'room'
|
||||
creationDate: 1620001000000
|
||||
autoDeletionDate: 1900000000000
|
||||
preferences:
|
||||
chatPreferences:
|
||||
config:
|
||||
chatConfig:
|
||||
enabled: false
|
||||
recordingPreferences:
|
||||
recordingConfig:
|
||||
enabled: true
|
||||
virtualBackgroundPreferences:
|
||||
virtualBackgroundConfig:
|
||||
enabled: false
|
||||
pagination:
|
||||
isTruncated: true
|
||||
|
||||
@ -40,12 +40,12 @@ content:
|
||||
roomId: room-123
|
||||
roomName: room
|
||||
creationDate: 1620000000000
|
||||
preferences:
|
||||
chatPreferences:
|
||||
config:
|
||||
chatConfig:
|
||||
enabled: true
|
||||
recordingPreferences:
|
||||
recordingConfig:
|
||||
enabled: false
|
||||
virtualBackgroundPreferences:
|
||||
virtualBackgroundConfig:
|
||||
enabled: true
|
||||
moderatorUrl: 'http://localhost:6080/room/room-123?secret=123456'
|
||||
speakerUrl: 'http://localhost:6080/room/room-123?secret=654321'
|
||||
@ -63,12 +63,12 @@ content:
|
||||
roomId: room-123
|
||||
roomName: room
|
||||
creationDate: 1620000000000
|
||||
preferences:
|
||||
chatPreferences:
|
||||
config:
|
||||
chatConfig:
|
||||
enabled: true
|
||||
recordingPreferences:
|
||||
recordingConfig:
|
||||
enabled: false
|
||||
virtualBackgroundPreferences:
|
||||
virtualBackgroundConfig:
|
||||
enabled: true
|
||||
moderatorUrl: 'http://localhost:6080/room/room-123?secret=123456'
|
||||
speakerUrl: 'http://localhost:6080/room/room-123?secret=654321'
|
||||
|
||||
@ -25,12 +25,12 @@ content:
|
||||
roomId: room-123
|
||||
roomName: room
|
||||
creationDate: 1620000000000
|
||||
preferences:
|
||||
chatPreferences:
|
||||
config:
|
||||
chatConfig:
|
||||
enabled: true
|
||||
recordingPreferences:
|
||||
recordingConfig:
|
||||
enabled: false
|
||||
virtualBackgroundPreferences:
|
||||
virtualBackgroundConfig:
|
||||
enabled: true
|
||||
moderatorUrl: 'http://localhost:6080/room/room-123?secret=123456'
|
||||
speakerUrl: 'http://localhost:6080/room/room-123?secret=654321'
|
||||
@ -44,12 +44,12 @@ content:
|
||||
roomId: room-123
|
||||
roomName: room
|
||||
creationDate: 1620000000000
|
||||
preferences:
|
||||
chatPreferences:
|
||||
config:
|
||||
chatConfig:
|
||||
enabled: true
|
||||
recordingPreferences:
|
||||
recordingConfig:
|
||||
enabled: false
|
||||
virtualBackgroundPreferences:
|
||||
virtualBackgroundConfig:
|
||||
enabled: true
|
||||
moderatorUrl: 'http://localhost:6080/room/room-123?secret=123456'
|
||||
speakerUrl: 'http://localhost:6080/room/room-123?secret=654321'
|
||||
@ -63,12 +63,12 @@ content:
|
||||
roomId: room-123
|
||||
roomName: room
|
||||
creationDate: 1620000000000
|
||||
preferences:
|
||||
chatPreferences:
|
||||
config:
|
||||
chatConfig:
|
||||
enabled: true
|
||||
recordingPreferences:
|
||||
recordingConfig:
|
||||
enabled: false
|
||||
virtualBackgroundPreferences:
|
||||
virtualBackgroundConfig:
|
||||
enabled: true
|
||||
moderatorUrl: 'http://localhost:6080/room/room-123?secret=123456'
|
||||
speakerUrl: 'http://localhost:6080/room/room-123?secret=654321'
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
description: Success response for updating room preferences
|
||||
description: Success response for updating room config
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
@ -7,4 +7,4 @@ content:
|
||||
message:
|
||||
type: string
|
||||
example:
|
||||
message: Room preferences for room 'room-123' updated successfully
|
||||
message: Room config for room 'room-123' updated successfully
|
||||
@ -1,16 +1,16 @@
|
||||
MeetRoomPreferences:
|
||||
MeetRoomConfig:
|
||||
type: object
|
||||
properties:
|
||||
chatPreferences:
|
||||
$ref: '#/MeetChatPreferences'
|
||||
description: Preferences for the chat feature in the room.
|
||||
recordingPreferences:
|
||||
$ref: '#/MeetRecordingPreferences'
|
||||
description: Preferences for recording the room.
|
||||
virtualBackgroundPreferences:
|
||||
$ref: '#/MeetVirtualBackgroundPreferences'
|
||||
description: Preferences for virtual background in the room.
|
||||
MeetChatPreferences:
|
||||
chatConfig:
|
||||
$ref: '#/MeetChatConfig'
|
||||
description: Config for the chat feature in the room.
|
||||
recordingConfig:
|
||||
$ref: '#/MeetRecordingConfig'
|
||||
description: Config for recording the room.
|
||||
virtualBackgroundConfig:
|
||||
$ref: '#/MeetVirtualBackgroundConfig'
|
||||
description: Config for virtual background in the room.
|
||||
MeetChatConfig:
|
||||
type: object
|
||||
properties:
|
||||
enabled:
|
||||
@ -18,7 +18,7 @@ MeetChatPreferences:
|
||||
default: true
|
||||
example: true
|
||||
description: If true, the room will be allowed to send and receive chat messages.
|
||||
MeetRecordingPreferences:
|
||||
MeetRecordingConfig:
|
||||
type: object
|
||||
properties:
|
||||
enabled:
|
||||
@ -39,7 +39,7 @@ MeetRecordingPreferences:
|
||||
- `admin`: Only administrators can access the recording.
|
||||
- `admin_moderator`: Administrators and moderators can access the recording.
|
||||
- `admin_moderator_speaker`: Administrators, moderators and speakers can access the recording.
|
||||
MeetVirtualBackgroundPreferences:
|
||||
MeetVirtualBackgroundConfig:
|
||||
type: object
|
||||
properties:
|
||||
enabled:
|
||||
@ -54,7 +54,7 @@ properties:
|
||||
# description: >
|
||||
# The maximum number of participants allowed in the room. If the number of participants exceeds
|
||||
# this limit, new participants will not be allowed to join.
|
||||
preferences:
|
||||
$ref: './meet-room-preferences.yaml#/MeetRoomPreferences'
|
||||
config:
|
||||
$ref: './meet-room-config.yaml#/MeetRoomConfig'
|
||||
description: >
|
||||
The preferences for the room. These preferences will be used to configure the room's settings.
|
||||
The config for the room. These config will be used to configure the room's settings.
|
||||
|
||||
@ -58,9 +58,9 @@ properties:
|
||||
Policy for automatic deletion when the room has recordings. Options are:
|
||||
- force: The room and its recordings will be deleted.
|
||||
- close: The room will be closed instead of deleted, maintaining its recordings.
|
||||
preferences:
|
||||
$ref: meet-room-preferences.yaml#/MeetRoomPreferences
|
||||
description: The preferences for the room.
|
||||
config:
|
||||
$ref: meet-room-config.yaml#/MeetRoomConfig
|
||||
description: The config for the room.
|
||||
# maxParticipants:
|
||||
# type: integer
|
||||
# example: 10
|
||||
|
||||
@ -13,8 +13,8 @@ paths:
|
||||
$ref: './paths/rooms.yaml#/~1rooms'
|
||||
/rooms/{roomId}:
|
||||
$ref: './paths/rooms.yaml#/~1rooms~1{roomId}'
|
||||
/rooms/{roomId}/preferences:
|
||||
$ref: './paths/rooms.yaml#/~1rooms~1{roomId}~1preferences'
|
||||
/rooms/{roomId}/config:
|
||||
$ref: './paths/rooms.yaml#/~1rooms~1{roomId}~1config'
|
||||
/recordings:
|
||||
$ref: './paths/recordings.yaml#/~1recordings'
|
||||
/recordings/download:
|
||||
@ -33,8 +33,8 @@ components:
|
||||
$ref: components/schemas/meet-room.yaml
|
||||
MeetRoomOptions:
|
||||
$ref: components/schemas/meet-room-options.yaml
|
||||
MeetRoomPreferences:
|
||||
$ref: './components/schemas/meet-room-preferences.yaml#/MeetRoomPreferences'
|
||||
MeetRoomConfig:
|
||||
$ref: './components/schemas/meet-room-config.yaml#/MeetRoomConfig'
|
||||
MeetRecording:
|
||||
$ref: components/schemas/meet-recording.yaml
|
||||
Error:
|
||||
|
||||
@ -63,8 +63,8 @@ components:
|
||||
$ref: components/schemas/meet-room.yaml
|
||||
MeetRoomOptions:
|
||||
$ref: components/schemas/meet-room-options.yaml
|
||||
MeetRoomPreferences:
|
||||
$ref: components/schemas/meet-room-preferences.yaml#/MeetRoomPreferences
|
||||
MeetRoomConfig:
|
||||
$ref: components/schemas/meet-room-config.yaml#/MeetRoomConfig
|
||||
MeetRoomRoleAndPermissions:
|
||||
$ref: components/schemas/internal/meet-room-role-permissions.yaml
|
||||
MeetRecording:
|
||||
|
||||
@ -151,12 +151,12 @@
|
||||
$ref: '../components/responses/validation-error.yaml'
|
||||
'500':
|
||||
$ref: '../components/responses/internal-server-error.yaml'
|
||||
/rooms/{roomId}/preferences:
|
||||
/rooms/{roomId}/config:
|
||||
get:
|
||||
operationId: getRoomPreferences
|
||||
summary: Get room preferences
|
||||
operationId: getRoomConfig
|
||||
summary: Get room config
|
||||
description: >
|
||||
Retrieves the preferences of an OpenVidu Meet room with the specified room ID.
|
||||
Retrieves the config of an OpenVidu Meet room with the specified room ID.
|
||||
tags:
|
||||
- OpenVidu Meet - Rooms
|
||||
security:
|
||||
@ -168,7 +168,7 @@
|
||||
- $ref: '../components/parameters/internal/x-participant-role.yaml'
|
||||
responses:
|
||||
'200':
|
||||
$ref: '../components/responses/success-get-room-preferences.yaml'
|
||||
$ref: '../components/responses/success-get-room-config.yaml'
|
||||
'400':
|
||||
$ref: '../components/responses/internal/error-invalid-participant-role.yaml'
|
||||
'401':
|
||||
@ -182,10 +182,10 @@
|
||||
'500':
|
||||
$ref: '../components/responses/internal-server-error.yaml'
|
||||
put:
|
||||
operationId: updateRoomPreferences
|
||||
summary: Update room preferences
|
||||
operationId: updateRoomConfig
|
||||
summary: Update room config
|
||||
description: >
|
||||
Updates the preferences of an OpenVidu Meet room with the specified room ID.
|
||||
Updates the config of an OpenVidu Meet room with the specified room ID.
|
||||
tags:
|
||||
- OpenVidu Meet - Rooms
|
||||
security:
|
||||
@ -194,10 +194,10 @@
|
||||
parameters:
|
||||
- $ref: '../components/parameters/room-id-path.yaml'
|
||||
requestBody:
|
||||
$ref: '../components/requestBodies/update-room-preferences-request.yaml'
|
||||
$ref: '../components/requestBodies/update-room-config-request.yaml'
|
||||
responses:
|
||||
'200':
|
||||
$ref: '../components/responses/success-update-room-preferences.yaml'
|
||||
$ref: '../components/responses/success-update-room-config.yaml'
|
||||
'401':
|
||||
$ref: '../components/responses/unauthorized-error.yaml'
|
||||
'403':
|
||||
|
||||
@ -128,34 +128,34 @@ export const bulkDeleteRooms = async (req: Request, res: Response) => {
|
||||
}
|
||||
};
|
||||
|
||||
export const getRoomPreferences = async (req: Request, res: Response) => {
|
||||
export const getRoomConfig = 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}'`);
|
||||
logger.verbose(`Getting room config for room '${roomId}'`);
|
||||
|
||||
try {
|
||||
const { preferences } = await roomService.getMeetRoom(roomId);
|
||||
return res.status(200).json(preferences);
|
||||
const { config } = await roomService.getMeetRoom(roomId);
|
||||
return res.status(200).json(config);
|
||||
} catch (error) {
|
||||
handleError(res, error, `getting room preferences for room '${roomId}'`);
|
||||
handleError(res, error, `getting room config for room '${roomId}'`);
|
||||
}
|
||||
};
|
||||
|
||||
export const updateRoomPreferences = async (req: Request, res: Response) => {
|
||||
export const updateRoomConfig = async (req: Request, res: Response) => {
|
||||
const logger = container.get(LoggerService);
|
||||
const roomService = container.get(RoomService);
|
||||
const { preferences } = req.body;
|
||||
const { config } = req.body;
|
||||
const { roomId } = req.params;
|
||||
|
||||
logger.verbose(`Updating room preferences for room '${roomId}'`);
|
||||
logger.verbose(`Updating room config for room '${roomId}'`);
|
||||
|
||||
try {
|
||||
await roomService.updateMeetRoomPreferences(roomId, preferences);
|
||||
return res.status(200).json({ message: `Room preferences for room '${roomId}' updated successfully` });
|
||||
await roomService.updateMeetRoomConfig(roomId, config);
|
||||
return res.status(200).json({ message: `Room config for room '${roomId}' updated successfully` });
|
||||
} catch (error) {
|
||||
handleError(res, error, `updating room preferences for room '${roomId}'`);
|
||||
handleError(res, error, `updating room config for room '${roomId}'`);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -17,7 +17,7 @@ export class MeetRoomHelper {
|
||||
roomName: room.roomName,
|
||||
autoDeletionDate: room.autoDeletionDate,
|
||||
autoDeletionPolicy: room.autoDeletionPolicy,
|
||||
preferences: room.preferences
|
||||
config: room.config
|
||||
// maxParticipants: room.maxParticipants
|
||||
};
|
||||
}
|
||||
|
||||
@ -27,7 +27,7 @@ export const withRecordingEnabled = async (req: Request, res: Response, next: Ne
|
||||
const roomId = extractRoomIdFromRequest(req);
|
||||
const room: MeetRoom = await roomService.getMeetRoom(roomId!);
|
||||
|
||||
if (!room.preferences?.recordingPreferences?.enabled) {
|
||||
if (!room.config?.recordingConfig?.enabled) {
|
||||
logger.debug(`Recording is disabled for room '${roomId}'`);
|
||||
const error = errorRecordingDisabled(roomId!);
|
||||
return rejectRequestFromMeetError(res, error);
|
||||
@ -35,7 +35,7 @@ export const withRecordingEnabled = async (req: Request, res: Response, next: Ne
|
||||
|
||||
return next();
|
||||
} catch (error) {
|
||||
handleError(res, error, 'checking recording preferences');
|
||||
handleError(res, error, 'checking recording config');
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -1,15 +1,15 @@
|
||||
import {
|
||||
MeetChatPreferences,
|
||||
MeetChatConfig,
|
||||
MeetRecordingAccess,
|
||||
MeetRecordingPreferences,
|
||||
MeetRecordingConfig,
|
||||
MeetRoomAutoDeletionPolicy,
|
||||
MeetRoomConfig,
|
||||
MeetRoomDeletionPolicyWithMeeting,
|
||||
MeetRoomDeletionPolicyWithRecordings,
|
||||
MeetRoomFilters,
|
||||
MeetRoomOptions,
|
||||
MeetRoomPreferences,
|
||||
MeetRoomStatus,
|
||||
MeetVirtualBackgroundPreferences,
|
||||
MeetVirtualBackgroundConfig,
|
||||
ParticipantRole,
|
||||
RecordingPermissions
|
||||
} from '@typings-ce';
|
||||
@ -65,7 +65,7 @@ const RecordingAccessSchema: z.ZodType<MeetRecordingAccess> = z.enum([
|
||||
MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER
|
||||
]);
|
||||
|
||||
const RecordingPreferencesSchema: z.ZodType<MeetRecordingPreferences> = z
|
||||
const RecordingConfigSchema: z.ZodType<MeetRecordingConfig> = z
|
||||
.object({
|
||||
enabled: z.boolean(),
|
||||
allowAccessTo: RecordingAccessSchema.optional()
|
||||
@ -81,18 +81,18 @@ const RecordingPreferencesSchema: z.ZodType<MeetRecordingPreferences> = z
|
||||
}
|
||||
);
|
||||
|
||||
const ChatPreferencesSchema: z.ZodType<MeetChatPreferences> = z.object({
|
||||
const ChatConfigSchema: z.ZodType<MeetChatConfig> = z.object({
|
||||
enabled: z.boolean()
|
||||
});
|
||||
|
||||
const VirtualBackgroundPreferencesSchema: z.ZodType<MeetVirtualBackgroundPreferences> = z.object({
|
||||
const VirtualBackgroundConfigSchema: z.ZodType<MeetVirtualBackgroundConfig> = z.object({
|
||||
enabled: z.boolean()
|
||||
});
|
||||
|
||||
const RoomPreferencesSchema: z.ZodType<MeetRoomPreferences> = z.object({
|
||||
recordingPreferences: RecordingPreferencesSchema,
|
||||
chatPreferences: ChatPreferencesSchema,
|
||||
virtualBackgroundPreferences: VirtualBackgroundPreferencesSchema
|
||||
const RoomConfigSchema: z.ZodType<MeetRoomConfig> = z.object({
|
||||
recordingConfig: RecordingConfigSchema,
|
||||
chatConfig: ChatConfigSchema,
|
||||
virtualBackgroundConfig: VirtualBackgroundConfigSchema
|
||||
});
|
||||
|
||||
const RoomDeletionPolicyWithMeetingSchema: z.ZodType<MeetRoomDeletionPolicyWithMeeting> = z.enum([
|
||||
@ -150,10 +150,10 @@ const RoomRequestOptionsSchema: z.ZodType<MeetRoomOptions> = z.object({
|
||||
path: ['withRecordings']
|
||||
}
|
||||
),
|
||||
preferences: RoomPreferencesSchema.optional().default({
|
||||
recordingPreferences: { enabled: true, allowAccessTo: MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER },
|
||||
chatPreferences: { enabled: true },
|
||||
virtualBackgroundPreferences: { enabled: true }
|
||||
config: RoomConfigSchema.optional().default({
|
||||
recordingConfig: { enabled: true, allowAccessTo: MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER },
|
||||
chatConfig: { enabled: true },
|
||||
virtualBackgroundConfig: { enabled: true }
|
||||
})
|
||||
// maxParticipants: z
|
||||
// .number()
|
||||
@ -223,8 +223,8 @@ const BulkDeleteRoomsSchema = z.object({
|
||||
withRecordings: RoomDeletionPolicyWithRecordingsSchema.optional().default(MeetRoomDeletionPolicyWithRecordings.FAIL)
|
||||
});
|
||||
|
||||
const UpdateRoomPreferencesSchema = z.object({
|
||||
preferences: RoomPreferencesSchema
|
||||
const UpdateRoomConfigSchema = z.object({
|
||||
config: RoomConfigSchema
|
||||
});
|
||||
|
||||
const UpdateRoomStatusSchema = z.object({
|
||||
@ -270,8 +270,8 @@ export const withValidRoomFiltersRequest = (req: Request, res: Response, next: N
|
||||
next();
|
||||
};
|
||||
|
||||
export const withValidRoomPreferences = (req: Request, res: Response, next: NextFunction) => {
|
||||
const { success, error, data } = UpdateRoomPreferencesSchema.safeParse(req.body);
|
||||
export const withValidRoomConfig = (req: Request, res: Response, next: NextFunction) => {
|
||||
const { success, error, data } = UpdateRoomConfigSchema.safeParse(req.body);
|
||||
|
||||
if (!success) {
|
||||
return rejectUnprocessableRequest(res, error);
|
||||
|
||||
@ -62,7 +62,7 @@ export const configureRecordingTokenAuth = async (req: Request, res: Response, n
|
||||
throw errorRoomMetadataNotFound(roomId);
|
||||
}
|
||||
|
||||
const recordingAccess = room.preferences!.recordingPreferences.allowAccessTo;
|
||||
const recordingAccess = room.config!.recordingConfig.allowAccessTo;
|
||||
|
||||
if (!recordingAccess || recordingAccess === MeetRecordingAccess.ADMIN) {
|
||||
// Deny request if the room is configured to allow access to recordings only for admins
|
||||
|
||||
@ -11,11 +11,11 @@ import {
|
||||
tokenAndRoleValidator,
|
||||
withAuth,
|
||||
withValidRoomBulkDeleteRequest,
|
||||
withValidRoomConfig,
|
||||
withValidRoomDeleteRequest,
|
||||
withValidRoomFiltersRequest,
|
||||
withValidRoomId,
|
||||
withValidRoomOptions,
|
||||
withValidRoomPreferences,
|
||||
withValidRoomSecret,
|
||||
withValidRoomStatus
|
||||
} from '../middlewares/index.js';
|
||||
@ -59,18 +59,18 @@ roomRouter.delete(
|
||||
);
|
||||
|
||||
roomRouter.get(
|
||||
'/:roomId/preferences',
|
||||
'/:roomId/config',
|
||||
withAuth(apiKeyValidator, tokenAndRoleValidator(UserRole.ADMIN), participantTokenValidator),
|
||||
withValidRoomId,
|
||||
configureRoomAuthorization,
|
||||
roomCtrl.getRoomPreferences
|
||||
roomCtrl.getRoomConfig
|
||||
);
|
||||
roomRouter.put(
|
||||
'/:roomId/preferences',
|
||||
'/:roomId/config',
|
||||
withAuth(apiKeyValidator, tokenAndRoleValidator(UserRole.ADMIN)),
|
||||
withValidRoomId,
|
||||
withValidRoomPreferences,
|
||||
roomCtrl.updateRoomPreferences
|
||||
withValidRoomConfig,
|
||||
roomCtrl.updateRoomConfig
|
||||
);
|
||||
|
||||
roomRouter.put(
|
||||
|
||||
@ -1,14 +1,14 @@
|
||||
import { MeetRoom, MeetRecordingInfo, ParticipantRole } from '@typings-ce';
|
||||
import { MeetRecordingInfo, MeetRoom, ParticipantRole } from '@typings-ce';
|
||||
import { inject, injectable } from 'inversify';
|
||||
import { SendDataOptions } from 'livekit-server-sdk';
|
||||
import { OpenViduComponentsAdapterHelper, OpenViduComponentsSignalPayload } from '../helpers/index.js';
|
||||
import { LiveKitService, LoggerService } from './index.js';
|
||||
import {
|
||||
MeetParticipantRoleUpdatedPayload,
|
||||
MeetRoomPreferencesUpdatedPayload,
|
||||
MeetRoomConfigUpdatedPayload,
|
||||
MeetSignalPayload,
|
||||
MeetSignalType
|
||||
} from '../typings/ce/event.model.js';
|
||||
import { LiveKitService, LoggerService } from './index.js';
|
||||
|
||||
/**
|
||||
* Service responsible for all communication with the frontend
|
||||
@ -67,25 +67,25 @@ export class FrontendEventService {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a signal to notify participants in a room about updated room preferences.
|
||||
* Sends a signal to notify participants in a room about updated room config.
|
||||
*/
|
||||
async sendRoomPreferencesUpdatedSignal(roomId: string, updatedRoom: MeetRoom): Promise<void> {
|
||||
this.logger.debug(`Sending room preferences updated signal for room ${roomId}`);
|
||||
async sendRoomConfigUpdatedSignal(roomId: string, updatedRoom: MeetRoom): Promise<void> {
|
||||
this.logger.debug(`Sending room config updated signal for room ${roomId}`);
|
||||
|
||||
try {
|
||||
const payload: MeetRoomPreferencesUpdatedPayload = {
|
||||
const payload: MeetRoomConfigUpdatedPayload = {
|
||||
roomId,
|
||||
preferences: updatedRoom.preferences!,
|
||||
config: updatedRoom.config!,
|
||||
timestamp: Date.now()
|
||||
};
|
||||
|
||||
const options: SendDataOptions = {
|
||||
topic: MeetSignalType.MEET_ROOM_PREFERENCES_UPDATED
|
||||
topic: MeetSignalType.MEET_ROOM_CONFIG_UPDATED
|
||||
};
|
||||
|
||||
await this.sendSignal(roomId, payload, options);
|
||||
} catch (error) {
|
||||
this.logger.error(`Error sending room preferences updated signal for room ${roomId}:`, error);
|
||||
this.logger.error(`Error sending room config updated signal for room ${roomId}:`, error);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -2,13 +2,13 @@ import {
|
||||
MeetingEndAction,
|
||||
MeetRecordingAccess,
|
||||
MeetRoom,
|
||||
MeetRoomConfig,
|
||||
MeetRoomDeletionErrorCode,
|
||||
MeetRoomDeletionPolicyWithMeeting,
|
||||
MeetRoomDeletionPolicyWithRecordings,
|
||||
MeetRoomDeletionSuccessCode,
|
||||
MeetRoomFilters,
|
||||
MeetRoomOptions,
|
||||
MeetRoomPreferences,
|
||||
MeetRoomStatus,
|
||||
ParticipantRole,
|
||||
RecordingPermissions
|
||||
@ -80,7 +80,7 @@ export class RoomService {
|
||||
*
|
||||
*/
|
||||
async createMeetRoom(baseUrl: string, roomOptions: MeetRoomOptions): Promise<MeetRoom> {
|
||||
const { roomName, autoDeletionDate, autoDeletionPolicy, preferences } = roomOptions;
|
||||
const { roomName, autoDeletionDate, autoDeletionPolicy, config } = roomOptions;
|
||||
const roomIdPrefix = roomName!.replace(/\s+/g, ''); // Remove all spaces
|
||||
const roomId = `${roomIdPrefix}-${uid(15)}`; // Generate a unique room ID based on the room name
|
||||
|
||||
@ -91,7 +91,7 @@ export class RoomService {
|
||||
// maxParticipants,
|
||||
autoDeletionDate,
|
||||
autoDeletionPolicy,
|
||||
preferences: preferences!,
|
||||
config: config!,
|
||||
moderatorUrl: `${baseUrl}/room/${roomId}?secret=${secureUid(10)}`,
|
||||
speakerUrl: `${baseUrl}/room/${roomId}?secret=${secureUid(10)}`,
|
||||
status: MeetRoomStatus.OPEN,
|
||||
@ -135,21 +135,21 @@ export class RoomService {
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the preferences of a specific meeting room.
|
||||
* Updates the config of a specific meeting room.
|
||||
*
|
||||
* @param roomId - The unique identifier of the meeting room to update
|
||||
* @param preferences - The new preferences to apply to the meeting room
|
||||
* @param config - The new config to apply to the meeting room
|
||||
* @returns A Promise that resolves to the updated MeetRoom object
|
||||
*/
|
||||
async updateMeetRoomPreferences(roomId: string, preferences: MeetRoomPreferences): Promise<MeetRoom> {
|
||||
async updateMeetRoomConfig(roomId: string, config: MeetRoomConfig): Promise<MeetRoom> {
|
||||
const room = await this.getMeetRoom(roomId);
|
||||
room.preferences = preferences;
|
||||
room.config = config;
|
||||
|
||||
await this.storageService.saveMeetRoom(room);
|
||||
// Update the archived room metadata if it exists
|
||||
await Promise.all([
|
||||
this.storageService.archiveRoomMetadata(roomId, true),
|
||||
this.frontendEventService.sendRoomPreferencesUpdatedSignal(roomId, room)
|
||||
this.frontendEventService.sendRoomConfigUpdatedSignal(roomId, room)
|
||||
]);
|
||||
return room;
|
||||
}
|
||||
@ -684,7 +684,7 @@ export class RoomService {
|
||||
}
|
||||
|
||||
protected getRecordingPermissions(room: Partial<MeetRoom>, role: ParticipantRole): RecordingPermissions {
|
||||
const recordingAccess = room.preferences!.recordingPreferences.allowAccessTo;
|
||||
const recordingAccess = room.config!.recordingConfig.allowAccessTo;
|
||||
|
||||
// A participant can delete recordings if they are a moderator and the recording access is not set to admin
|
||||
const canDeleteRecordings = role === ParticipantRole.MODERATOR && recordingAccess !== MeetRecordingAccess.ADMIN;
|
||||
|
||||
@ -269,7 +269,7 @@ export class MeetStorageService<
|
||||
* Archives room metadata by storing essential room information in both cache and persistent storage.
|
||||
*
|
||||
* This method retrieves the room data, extracts key metadata (moderator/speaker URLs and
|
||||
* recording preferences), and saves it to an archived location for future reference.
|
||||
* recording config), and saves it to an archived location for future reference.
|
||||
*
|
||||
* If `updateOnlyIfExists` is true, it will only save the archived metadata if it already exists,
|
||||
* updating the existing entry.
|
||||
@ -302,8 +302,8 @@ export class MeetStorageService<
|
||||
const archivedRoom: Partial<MRoom> = {
|
||||
moderatorUrl: room.moderatorUrl,
|
||||
speakerUrl: room.speakerUrl,
|
||||
preferences: {
|
||||
recordingPreferences: room.preferences?.recordingPreferences
|
||||
config: {
|
||||
recordingConfig: room.config?.recordingConfig
|
||||
}
|
||||
} as Partial<MRoom>;
|
||||
|
||||
|
||||
@ -9,9 +9,9 @@ import {
|
||||
MeetRecordingStatus,
|
||||
MeetRoom,
|
||||
MeetRoomAutoDeletionPolicy,
|
||||
MeetRoomConfig,
|
||||
MeetRoomDeletionPolicyWithMeeting,
|
||||
MeetRoomDeletionPolicyWithRecordings,
|
||||
MeetRoomPreferences,
|
||||
MeetRoomStatus,
|
||||
ParticipantPermissions,
|
||||
ParticipantRole
|
||||
@ -93,22 +93,22 @@ export const expectSuccessRoomResponse = (
|
||||
response: any,
|
||||
roomName: string,
|
||||
autoDeletionDate?: number,
|
||||
preferences?: MeetRoomPreferences
|
||||
config?: MeetRoomConfig
|
||||
) => {
|
||||
expect(response.status).toBe(200);
|
||||
expectValidRoom(response.body, roomName, preferences, autoDeletionDate);
|
||||
expectValidRoom(response.body, roomName, config, autoDeletionDate);
|
||||
};
|
||||
|
||||
export const expectSuccessRoomPreferencesResponse = (response: any, preferences: MeetRoomPreferences) => {
|
||||
export const expectSuccessRoomConfigResponse = (response: any, config: MeetRoomConfig) => {
|
||||
expect(response.status).toBe(200);
|
||||
expect(response.body).toBeDefined();
|
||||
expect(response.body).toEqual(preferences);
|
||||
expect(response.body).toEqual(config);
|
||||
};
|
||||
|
||||
export const expectValidRoom = (
|
||||
room: MeetRoom,
|
||||
name: string,
|
||||
preferences?: MeetRoomPreferences,
|
||||
config?: MeetRoomConfig,
|
||||
autoDeletionDate?: number,
|
||||
autoDeletionPolicy?: MeetRoomAutoDeletionPolicy,
|
||||
status?: MeetRoomStatus,
|
||||
@ -140,18 +140,18 @@ export const expectValidRoom = (
|
||||
});
|
||||
}
|
||||
|
||||
expect(room.preferences).toBeDefined();
|
||||
expect(room.config).toBeDefined();
|
||||
|
||||
if (preferences !== undefined) {
|
||||
expect(room.preferences).toEqual(preferences);
|
||||
if (config !== undefined) {
|
||||
expect(room.config).toEqual(config);
|
||||
} else {
|
||||
expect(room.preferences).toEqual({
|
||||
recordingPreferences: {
|
||||
expect(room.config).toEqual({
|
||||
recordingConfig: {
|
||||
enabled: true,
|
||||
allowAccessTo: MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER
|
||||
},
|
||||
chatPreferences: { enabled: true },
|
||||
virtualBackgroundPreferences: { enabled: true }
|
||||
chatConfig: { enabled: true },
|
||||
virtualBackgroundConfig: { enabled: true }
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -243,34 +243,34 @@ export const getRoom = async (roomId: string, fields?: string, cookie?: string,
|
||||
return await req;
|
||||
};
|
||||
|
||||
export const getRoomPreferences = async (roomId: string) => {
|
||||
export const getRoomConfig = async (roomId: string) => {
|
||||
checkAppIsRunning();
|
||||
|
||||
return await request(app)
|
||||
.get(`${INTERNAL_CONFIG.API_BASE_PATH_V1}/rooms/${roomId}/preferences`)
|
||||
.get(`${INTERNAL_CONFIG.API_BASE_PATH_V1}/rooms/${roomId}/config`)
|
||||
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY)
|
||||
.send();
|
||||
};
|
||||
|
||||
export const updateRoomPreferences = async (roomId: string, preferences: any) => {
|
||||
export const updateRoomConfig = async (roomId: string, config: any) => {
|
||||
checkAppIsRunning();
|
||||
|
||||
return await request(app)
|
||||
.put(`${INTERNAL_CONFIG.API_BASE_PATH_V1}/rooms/${roomId}/preferences`)
|
||||
.put(`${INTERNAL_CONFIG.API_BASE_PATH_V1}/rooms/${roomId}/config`)
|
||||
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY)
|
||||
.send({ preferences });
|
||||
.send({ config });
|
||||
};
|
||||
|
||||
export const updateRecordingAccessPreferencesInRoom = async (roomId: string, recordingAccess: MeetRecordingAccess) => {
|
||||
const response = await updateRoomPreferences(roomId, {
|
||||
recordingPreferences: {
|
||||
export const updateRecordingAccessConfigInRoom = async (roomId: string, recordingAccess: MeetRecordingAccess) => {
|
||||
const response = await updateRoomConfig(roomId, {
|
||||
recordingConfig: {
|
||||
enabled: true,
|
||||
allowAccessTo: recordingAccess
|
||||
},
|
||||
chatPreferences: {
|
||||
chatConfig: {
|
||||
enabled: true
|
||||
},
|
||||
virtualBackgroundPreferences: {
|
||||
virtualBackgroundConfig: {
|
||||
enabled: true
|
||||
}
|
||||
});
|
||||
@ -297,11 +297,7 @@ export const deleteRoom = async (roomId: string, query: Record<string, any> = {}
|
||||
return result;
|
||||
};
|
||||
|
||||
export const bulkDeleteRooms = async (
|
||||
roomIds: any[],
|
||||
withMeeting?: string,
|
||||
withRecordings?: string
|
||||
) => {
|
||||
export const bulkDeleteRooms = async (roomIds: any[], withMeeting?: string, withRecordings?: string) => {
|
||||
checkAppIsRunning();
|
||||
|
||||
const result = await request(app)
|
||||
|
||||
@ -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, MeetRoomPreferences } from '../../src/typings/ce';
|
||||
import { MeetRoom, MeetRoomConfig } from '../../src/typings/ce';
|
||||
import { expectValidStartRecordingResponse } from './assertion-helpers';
|
||||
import {
|
||||
createRoom,
|
||||
@ -35,17 +35,17 @@ export interface TestContext {
|
||||
*
|
||||
* @param withParticipant Whether to join a fake participant in the room.
|
||||
* @param roomName Name of the room to create.
|
||||
* @param preferences Optional room preferences.
|
||||
* @param config Optional room config.
|
||||
* @returns Room data including secrets and cookies.
|
||||
*/
|
||||
export const setupSingleRoom = async (
|
||||
withParticipant = false,
|
||||
roomName = 'TEST_ROOM',
|
||||
preferences?: MeetRoomPreferences
|
||||
config?: MeetRoomConfig
|
||||
): Promise<RoomData> => {
|
||||
const room = await createRoom({
|
||||
roomName,
|
||||
preferences
|
||||
config
|
||||
});
|
||||
|
||||
// Extract the room secrets and generate participant tokens, saved as cookies
|
||||
|
||||
@ -73,7 +73,7 @@ describe('Recording API Tests', () => {
|
||||
expect(archivedRoom).toBeDefined();
|
||||
expect(archivedRoom?.moderatorUrl).toBeDefined();
|
||||
expect(archivedRoom?.speakerUrl).toBeDefined();
|
||||
expect(archivedRoom?.preferences).toBeDefined();
|
||||
expect(archivedRoom?.config).toBeDefined();
|
||||
|
||||
const secretsResponse = await stopRecording(recordingId, moderatorCookie);
|
||||
expectValidStopRecordingResponse(secretsResponse, recordingId, room.roomId, room.roomName);
|
||||
|
||||
@ -58,25 +58,19 @@ describe('Room API Tests', () => {
|
||||
withMeeting: MeetRoomDeletionPolicyWithMeeting.FORCE,
|
||||
withRecordings: MeetRoomDeletionPolicyWithRecordings.FORCE
|
||||
},
|
||||
preferences: {
|
||||
recordingPreferences: {
|
||||
config: {
|
||||
recordingConfig: {
|
||||
enabled: false,
|
||||
allowAccessTo: MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER
|
||||
},
|
||||
chatPreferences: { enabled: false },
|
||||
virtualBackgroundPreferences: { enabled: true }
|
||||
chatConfig: { enabled: false },
|
||||
virtualBackgroundConfig: { enabled: true }
|
||||
}
|
||||
};
|
||||
|
||||
const room = await createRoom(payload);
|
||||
|
||||
expectValidRoom(
|
||||
room,
|
||||
'Example Room',
|
||||
payload.preferences,
|
||||
validAutoDeletionDate,
|
||||
payload.autoDeletionPolicy
|
||||
);
|
||||
expectValidRoom(room, 'Example Room', payload.config, validAutoDeletionDate, payload.autoDeletionPolicy);
|
||||
});
|
||||
});
|
||||
|
||||
@ -180,7 +174,9 @@ describe('Room API Tests', () => {
|
||||
|
||||
const response = await request(app).post(ROOMS_PATH).set('Cookie', adminCookie).send(payload).expect(422);
|
||||
|
||||
expect(JSON.stringify(response.body.details)).toContain('FAIL policy is not allowed for withMeeting auto-deletion policy');
|
||||
expect(JSON.stringify(response.body.details)).toContain(
|
||||
'FAIL policy is not allowed for withMeeting auto-deletion policy'
|
||||
);
|
||||
});
|
||||
|
||||
it('should fail when autoDeletionPolicy.withRecordings has FAIL policy', async () => {
|
||||
@ -195,7 +191,9 @@ describe('Room API Tests', () => {
|
||||
|
||||
const response = await request(app).post(ROOMS_PATH).set('Cookie', adminCookie).send(payload).expect(422);
|
||||
|
||||
expect(JSON.stringify(response.body.details)).toContain('FAIL policy is not allowed for withRecordings auto-deletion policy');
|
||||
expect(JSON.stringify(response.body.details)).toContain(
|
||||
'FAIL policy is not allowed for withRecordings auto-deletion policy'
|
||||
);
|
||||
});
|
||||
|
||||
it('should fail when roomName is not a string (number provided)', async () => {
|
||||
@ -220,11 +218,11 @@ describe('Room API Tests', () => {
|
||||
expect(JSON.stringify(response.body.details)).toContain('Expected string');
|
||||
});
|
||||
|
||||
it('should fail when preferences is not an object (string provided)', async () => {
|
||||
it('should fail when config is not an object (string provided)', async () => {
|
||||
const payload = {
|
||||
roomName: 'TestRoom',
|
||||
autoDeletionDate: validAutoDeletionDate,
|
||||
preferences: 'invalid-preferences'
|
||||
config: 'invalid-config'
|
||||
};
|
||||
|
||||
const response = await request(app).post(ROOMS_PATH).set('Cookie', adminCookie).send(payload).expect(422);
|
||||
@ -232,19 +230,19 @@ describe('Room API Tests', () => {
|
||||
expect(JSON.stringify(response.body.details)).toContain('Expected object');
|
||||
});
|
||||
|
||||
it('should fail when preferences has an invalid structure', async () => {
|
||||
// Assuming preferences expects each sub-property to be an object with a boolean "enabled",
|
||||
it('should fail when config has an invalid structure', async () => {
|
||||
// Assuming config expects each sub-property to be an object with a boolean "enabled",
|
||||
// here we deliberately use an invalid structure.
|
||||
const payload = {
|
||||
roomName: 'TestRoom',
|
||||
autoDeletionDate: validAutoDeletionDate,
|
||||
preferences: {
|
||||
recordingPreferences: {
|
||||
config: {
|
||||
recordingConfig: {
|
||||
enabled: 'yes', // invalid boolean
|
||||
allowAccessTo: MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER
|
||||
},
|
||||
chatPreferences: { enabled: true },
|
||||
virtualBackgroundPreferences: { enabled: true }
|
||||
chatConfig: { enabled: true },
|
||||
virtualBackgroundConfig: { enabled: true }
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { afterAll, beforeAll, describe, expect, it } from '@jest/globals';
|
||||
import { ParticipantRole } from '../../../../src/typings/ce/participant.js';
|
||||
import { MeetRecordingAccess } from '../../../../src/typings/ce/room-preferences.js';
|
||||
import { MeetRecordingAccess } from '../../../../src/typings/ce/room-config.js';
|
||||
import { expectValidRecordingTokenResponse } from '../../../helpers/assertion-helpers.js';
|
||||
import {
|
||||
deleteAllRecordings,
|
||||
@ -9,7 +9,7 @@ import {
|
||||
disconnectFakeParticipants,
|
||||
generateRecordingToken,
|
||||
startTestServer,
|
||||
updateRecordingAccessPreferencesInRoom
|
||||
updateRecordingAccessConfigInRoom
|
||||
} from '../../../helpers/request-helpers.js';
|
||||
import { RoomData, setupSingleRoomWithRecording } from '../../../helpers/test-scenarios.js';
|
||||
|
||||
@ -28,44 +28,35 @@ describe('Room API Tests', () => {
|
||||
|
||||
describe('Generate Recording Token Tests', () => {
|
||||
it('should generate a recording token with canRetrieve and canDelete permissions when using the moderator secret and recording access is admin_moderator', async () => {
|
||||
await updateRecordingAccessPreferencesInRoom(roomData.room.roomId, MeetRecordingAccess.ADMIN_MODERATOR);
|
||||
await updateRecordingAccessConfigInRoom(roomData.room.roomId, MeetRecordingAccess.ADMIN_MODERATOR);
|
||||
|
||||
const response = await generateRecordingToken(roomData.room.roomId, roomData.moderatorSecret);
|
||||
expectValidRecordingTokenResponse(response, roomData.room.roomId, ParticipantRole.MODERATOR, true, true);
|
||||
});
|
||||
|
||||
it('should generate a recording token with canRetrieve and canDelete permissions when using the moderator secret and recording access is admin_moderator_speaker', async () => {
|
||||
await updateRecordingAccessPreferencesInRoom(
|
||||
roomData.room.roomId,
|
||||
MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER
|
||||
);
|
||||
await updateRecordingAccessConfigInRoom(roomData.room.roomId, MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER);
|
||||
|
||||
const response = await generateRecordingToken(roomData.room.roomId, roomData.moderatorSecret);
|
||||
expectValidRecordingTokenResponse(response, roomData.room.roomId, ParticipantRole.MODERATOR, true, true);
|
||||
});
|
||||
|
||||
it('should generate a recording token without any permissions when using the speaker secret and recording access is admin_moderator', async () => {
|
||||
await updateRecordingAccessPreferencesInRoom(roomData.room.roomId, MeetRecordingAccess.ADMIN_MODERATOR);
|
||||
await updateRecordingAccessConfigInRoom(roomData.room.roomId, MeetRecordingAccess.ADMIN_MODERATOR);
|
||||
|
||||
const response = await generateRecordingToken(roomData.room.roomId, roomData.speakerSecret);
|
||||
expectValidRecordingTokenResponse(response, roomData.room.roomId, ParticipantRole.SPEAKER, false, false);
|
||||
});
|
||||
|
||||
it('should generate a recording token with canRetrieve permission but not canDelete when using the speaker secret and recording access is admin_moderator_speaker', async () => {
|
||||
await updateRecordingAccessPreferencesInRoom(
|
||||
roomData.room.roomId,
|
||||
MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER
|
||||
);
|
||||
await updateRecordingAccessConfigInRoom(roomData.room.roomId, MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER);
|
||||
|
||||
const response = await generateRecordingToken(roomData.room.roomId, roomData.speakerSecret);
|
||||
expectValidRecordingTokenResponse(response, roomData.room.roomId, ParticipantRole.SPEAKER, true, false);
|
||||
});
|
||||
|
||||
it('should succeed even if the room is deleted', async () => {
|
||||
await updateRecordingAccessPreferencesInRoom(
|
||||
roomData.room.roomId,
|
||||
MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER
|
||||
);
|
||||
await updateRecordingAccessConfigInRoom(roomData.room.roomId, MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER);
|
||||
await deleteRoom(roomData.room.roomId);
|
||||
|
||||
const response = await generateRecordingToken(roomData.room.roomId, roomData.moderatorSecret);
|
||||
|
||||
@ -1,17 +1,17 @@
|
||||
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 { expectSuccessRoomConfigResponse } from '../../../helpers/assertion-helpers.js';
|
||||
import { deleteAllRooms, getRoomConfig, startTestServer } from '../../../helpers/request-helpers.js';
|
||||
import { setupSingleRoom } from '../../../helpers/test-scenarios.js';
|
||||
|
||||
describe('Room API Tests', () => {
|
||||
const DEFAULT_PREFERENCES = {
|
||||
recordingPreferences: {
|
||||
const DEFAULT_CONFIG = {
|
||||
recordingConfig: {
|
||||
enabled: true,
|
||||
allowAccessTo: MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER
|
||||
},
|
||||
chatPreferences: { enabled: true },
|
||||
virtualBackgroundPreferences: { enabled: true }
|
||||
chatConfig: { enabled: true },
|
||||
virtualBackgroundConfig: { enabled: true }
|
||||
};
|
||||
|
||||
beforeAll(() => {
|
||||
@ -23,33 +23,33 @@ describe('Room API Tests', () => {
|
||||
await deleteAllRooms();
|
||||
});
|
||||
|
||||
describe('Get Room Preferences Tests', () => {
|
||||
describe('Get Room Config Tests', () => {
|
||||
it('should successfully retrieve a room by its ID', async () => {
|
||||
const roomData = await setupSingleRoom();
|
||||
const roomId = roomData.room.roomId;
|
||||
|
||||
const response = await getRoomPreferences(roomId);
|
||||
expectSuccessRoomPreferencesResponse(response, DEFAULT_PREFERENCES);
|
||||
const response = await getRoomConfig(roomId);
|
||||
expectSuccessRoomConfigResponse(response, DEFAULT_CONFIG);
|
||||
});
|
||||
|
||||
it('should retrieve custom room preferences', async () => {
|
||||
it('should retrieve custom room config', async () => {
|
||||
const payload = {
|
||||
roomName: 'custom-prefs',
|
||||
preferences: {
|
||||
recordingPreferences: {
|
||||
config: {
|
||||
recordingConfig: {
|
||||
enabled: true,
|
||||
allowAccessTo: MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER
|
||||
},
|
||||
chatPreferences: { enabled: true },
|
||||
virtualBackgroundPreferences: { enabled: false }
|
||||
chatConfig: { enabled: true },
|
||||
virtualBackgroundConfig: { enabled: false }
|
||||
}
|
||||
};
|
||||
|
||||
const roomData = await setupSingleRoom(false, payload.roomName, payload.preferences);
|
||||
const roomData = await setupSingleRoom(false, payload.roomName, payload.config);
|
||||
const roomId = roomData.room.roomId;
|
||||
|
||||
const response = await getRoomPreferences(roomId);
|
||||
expectSuccessRoomPreferencesResponse(response, payload.preferences);
|
||||
const response = await getRoomConfig(roomId);
|
||||
expectSuccessRoomConfigResponse(response, payload.config);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -32,25 +32,25 @@ describe('Room API Tests', () => {
|
||||
expectSuccessRoomResponse(response, 'test-room');
|
||||
});
|
||||
|
||||
it('should retrieve a room with custom preferences', async () => {
|
||||
it('should retrieve a room with custom config', async () => {
|
||||
const payload = {
|
||||
roomName: 'custom-prefs',
|
||||
preferences: {
|
||||
recordingPreferences: {
|
||||
config: {
|
||||
recordingConfig: {
|
||||
enabled: true,
|
||||
allowAccessTo: MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER
|
||||
},
|
||||
chatPreferences: { enabled: true },
|
||||
virtualBackgroundPreferences: { enabled: false }
|
||||
chatConfig: { enabled: true },
|
||||
virtualBackgroundConfig: { enabled: false }
|
||||
}
|
||||
};
|
||||
// Create a room with custom preferences
|
||||
// Create a room with custom config
|
||||
const { roomId } = await createRoom(payload);
|
||||
|
||||
// Retrieve the room by its ID
|
||||
const response = await getRoom(roomId);
|
||||
|
||||
expectSuccessRoomResponse(response, 'custom-prefs', undefined, payload.preferences);
|
||||
expectSuccessRoomResponse(response, 'custom-prefs', undefined, payload.config);
|
||||
});
|
||||
|
||||
it('should retrieve only specified fields when using fields parameter', async () => {
|
||||
|
||||
@ -1,15 +1,15 @@
|
||||
import { afterEach, beforeAll, describe, expect, it, jest } from '@jest/globals';
|
||||
import { container } from '../../../../src/config/index.js';
|
||||
import { FrontendEventService } from '../../../../src/services/index.js';
|
||||
import { MeetSignalType } from '../../../../src/typings/ce/event.model.js';
|
||||
import { MeetRecordingAccess } from '../../../../src/typings/ce/index.js';
|
||||
import {
|
||||
createRoom,
|
||||
deleteAllRooms,
|
||||
getRoom,
|
||||
startTestServer,
|
||||
updateRoomPreferences
|
||||
updateRoomConfig
|
||||
} from '../../../helpers/request-helpers.js';
|
||||
import { FrontendEventService } from '../../../../src/services/index.js';
|
||||
import { container } from '../../../../src/config/index.js';
|
||||
import { MeetSignalType } from '../../../../src/typings/ce/event.model.js';
|
||||
|
||||
describe('Room API Tests', () => {
|
||||
beforeAll(() => {
|
||||
@ -21,7 +21,7 @@ describe('Room API Tests', () => {
|
||||
await deleteAllRooms();
|
||||
});
|
||||
|
||||
describe('Update Room Preferences Tests', () => {
|
||||
describe('Update Room Config Tests', () => {
|
||||
let frontendEventService: FrontendEventService;
|
||||
|
||||
beforeAll(() => {
|
||||
@ -29,41 +29,41 @@ describe('Room API Tests', () => {
|
||||
frontendEventService = container.get(FrontendEventService);
|
||||
});
|
||||
|
||||
it('should successfully update room preferences', async () => {
|
||||
it('should successfully update room config', async () => {
|
||||
const sendSignalSpy = jest.spyOn(frontendEventService as any, 'sendSignal');
|
||||
const createdRoom = await createRoom({
|
||||
roomName: 'update-test',
|
||||
preferences: {
|
||||
recordingPreferences: {
|
||||
config: {
|
||||
recordingConfig: {
|
||||
enabled: true,
|
||||
allowAccessTo: MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER
|
||||
},
|
||||
chatPreferences: { enabled: true },
|
||||
virtualBackgroundPreferences: { enabled: true }
|
||||
chatConfig: { enabled: true },
|
||||
virtualBackgroundConfig: { enabled: true }
|
||||
}
|
||||
});
|
||||
|
||||
// Update the room preferences
|
||||
const updatedPreferences = {
|
||||
recordingPreferences: {
|
||||
// Update the room config
|
||||
const updatedConfig = {
|
||||
recordingConfig: {
|
||||
enabled: false,
|
||||
allowAccessTo: MeetRecordingAccess.ADMIN
|
||||
},
|
||||
chatPreferences: { enabled: false },
|
||||
virtualBackgroundPreferences: { enabled: false }
|
||||
chatConfig: { enabled: false },
|
||||
virtualBackgroundConfig: { enabled: false }
|
||||
};
|
||||
const updateResponse = await updateRoomPreferences(createdRoom.roomId, updatedPreferences);
|
||||
const updateResponse = await updateRoomConfig(createdRoom.roomId, updatedConfig);
|
||||
|
||||
// Verify a method of frontend event service is called
|
||||
expect(sendSignalSpy).toHaveBeenCalledWith(
|
||||
createdRoom.roomId,
|
||||
{
|
||||
roomId: createdRoom.roomId,
|
||||
preferences: updatedPreferences,
|
||||
config: updatedConfig,
|
||||
timestamp: expect.any(Number)
|
||||
},
|
||||
{
|
||||
topic: MeetSignalType.MEET_ROOM_PREFERENCES_UPDATED
|
||||
topic: MeetSignalType.MEET_ROOM_CONFIG_UPDATED
|
||||
}
|
||||
);
|
||||
|
||||
@ -74,33 +74,33 @@ describe('Room API Tests', () => {
|
||||
// Verify with a get request
|
||||
const getResponse = await getRoom(createdRoom.roomId);
|
||||
expect(getResponse.status).toBe(200);
|
||||
expect(getResponse.body.preferences).toEqual(updatedPreferences);
|
||||
expect(getResponse.body.config).toEqual(updatedConfig);
|
||||
});
|
||||
|
||||
it('should allow partial preference updates', async () => {
|
||||
// Create a room first with all preferences enabled
|
||||
// Create a room first with all config enabled
|
||||
const createdRoom = await createRoom({
|
||||
roomName: 'partial-update',
|
||||
preferences: {
|
||||
recordingPreferences: {
|
||||
config: {
|
||||
recordingConfig: {
|
||||
enabled: true,
|
||||
allowAccessTo: MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER
|
||||
},
|
||||
chatPreferences: { enabled: true },
|
||||
virtualBackgroundPreferences: { enabled: true }
|
||||
chatConfig: { enabled: true },
|
||||
virtualBackgroundConfig: { enabled: true }
|
||||
}
|
||||
});
|
||||
|
||||
// Update only one preference
|
||||
const partialPreferences = {
|
||||
recordingPreferences: {
|
||||
const partialConfig = {
|
||||
recordingConfig: {
|
||||
enabled: false,
|
||||
allowAccessTo: MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER
|
||||
},
|
||||
chatPreferences: { enabled: true },
|
||||
virtualBackgroundPreferences: { enabled: true }
|
||||
chatConfig: { enabled: true },
|
||||
virtualBackgroundConfig: { enabled: true }
|
||||
};
|
||||
const updateResponse = await updateRoomPreferences(createdRoom.roomId, partialPreferences);
|
||||
const updateResponse = await updateRoomConfig(createdRoom.roomId, partialConfig);
|
||||
|
||||
// Verify update response
|
||||
expect(updateResponse.status).toBe(200);
|
||||
@ -109,59 +109,59 @@ describe('Room API Tests', () => {
|
||||
// Verify with a get request
|
||||
const getResponse = await getRoom(createdRoom.roomId);
|
||||
expect(getResponse.status).toBe(200);
|
||||
expect(getResponse.body.preferences).toEqual(partialPreferences);
|
||||
expect(getResponse.body.config).toEqual(partialConfig);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Update Room Preferences Validation failures', () => {
|
||||
it('should fail when preferences have incorrect structure', async () => {
|
||||
describe('Update Room Config Validation failures', () => {
|
||||
it('should fail when config has incorrect structure', async () => {
|
||||
const { roomId } = await createRoom({
|
||||
roomName: 'validation-test'
|
||||
});
|
||||
|
||||
// Invalid preferences (missing required fields)
|
||||
const invalidPreferences = {
|
||||
recordingPreferences: {
|
||||
// Invalid config (missing required fields)
|
||||
const invalidConfig = {
|
||||
recordingConfig: {
|
||||
enabled: false
|
||||
},
|
||||
// Missing chatPreferences
|
||||
virtualBackgroundPreferences: { enabled: false }
|
||||
// Missing chatConfig
|
||||
virtualBackgroundConfig: { enabled: false }
|
||||
};
|
||||
const response = await updateRoomPreferences(roomId, invalidPreferences);
|
||||
const response = await updateRoomConfig(roomId, invalidConfig);
|
||||
|
||||
expect(response.status).toBe(422);
|
||||
expect(response.body.error).toContain('Unprocessable Entity');
|
||||
expect(JSON.stringify(response.body.details)).toContain('chatPreferences');
|
||||
expect(JSON.stringify(response.body.details)).toContain('chatConfig');
|
||||
});
|
||||
|
||||
it('should fail when preferences have incorrect types', async () => {
|
||||
it('should fail when config has incorrect types', async () => {
|
||||
const createdRoom = await createRoom({
|
||||
roomName: 'type-test'
|
||||
});
|
||||
|
||||
// Invalid preferences (wrong types)
|
||||
const invalidPreferences = {
|
||||
recordingPreferences: {
|
||||
// Invalid config (wrong types)
|
||||
const invalidConfig = {
|
||||
recordingConfig: {
|
||||
enabled: 'true', // String instead of boolean
|
||||
allowAccessTo: MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER
|
||||
},
|
||||
chatPreferences: { enabled: false },
|
||||
virtualBackgroundPreferences: { enabled: false }
|
||||
chatConfig: { enabled: false },
|
||||
virtualBackgroundConfig: { enabled: false }
|
||||
};
|
||||
const response = await updateRoomPreferences(createdRoom.roomId, invalidPreferences);
|
||||
const response = await updateRoomConfig(createdRoom.roomId, invalidConfig);
|
||||
|
||||
expect(response.status).toBe(422);
|
||||
expect(response.body.error).toContain('Unprocessable Entity');
|
||||
expect(JSON.stringify(response.body.details)).toContain('recordingPreferences.enabled');
|
||||
expect(JSON.stringify(response.body.details)).toContain('recordingConfig.enabled');
|
||||
});
|
||||
|
||||
it('should fail when preferences are missing required properties', async () => {
|
||||
it('should fail when config is missing required properties', async () => {
|
||||
const createdRoom = await createRoom({
|
||||
roomName: 'missing-props'
|
||||
});
|
||||
|
||||
const emptyPreferences = {};
|
||||
const response = await updateRoomPreferences(createdRoom.roomId, emptyPreferences);
|
||||
const emptyConfig = {};
|
||||
const response = await updateRoomConfig(createdRoom.roomId, emptyConfig);
|
||||
|
||||
expect(response.status).toBe(422);
|
||||
expect(response.body.error).toContain('Unprocessable Entity');
|
||||
@ -172,32 +172,32 @@ describe('Room API Tests', () => {
|
||||
roomName: 'missing-access'
|
||||
});
|
||||
|
||||
const invalidPreferences = {
|
||||
recordingPreferences: {
|
||||
const invalidConfig = {
|
||||
recordingConfig: {
|
||||
enabled: true // Missing allowAccessTo
|
||||
},
|
||||
chatPreferences: { enabled: false },
|
||||
virtualBackgroundPreferences: { enabled: false }
|
||||
chatConfig: { enabled: false },
|
||||
virtualBackgroundConfig: { enabled: false }
|
||||
};
|
||||
const response = await updateRoomPreferences(createdRoom.roomId, invalidPreferences);
|
||||
const response = await updateRoomConfig(createdRoom.roomId, invalidConfig);
|
||||
|
||||
expect(response.status).toBe(422);
|
||||
expect(response.body.error).toContain('Unprocessable Entity');
|
||||
expect(JSON.stringify(response.body.details)).toContain('recordingPreferences.allowAccessTo');
|
||||
expect(JSON.stringify(response.body.details)).toContain('recordingConfig.allowAccessTo');
|
||||
});
|
||||
|
||||
it('should return 404 when updating non-existent room', async () => {
|
||||
const nonExistentRoomId = 'non-existent-room';
|
||||
|
||||
const preferences = {
|
||||
recordingPreferences: {
|
||||
const config = {
|
||||
recordingConfig: {
|
||||
enabled: false,
|
||||
allowAccessTo: MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER
|
||||
},
|
||||
chatPreferences: { enabled: false },
|
||||
virtualBackgroundPreferences: { enabled: false }
|
||||
chatConfig: { enabled: false },
|
||||
virtualBackgroundConfig: { enabled: false }
|
||||
};
|
||||
const response = await updateRoomPreferences(nonExistentRoomId, preferences);
|
||||
const response = await updateRoomConfig(nonExistentRoomId, config);
|
||||
|
||||
expect(response.status).toBe(404);
|
||||
expect(response.body.message).toContain(`'${nonExistentRoomId}' does not exist`);
|
||||
|
||||
@ -15,7 +15,7 @@ import {
|
||||
startTestServer,
|
||||
stopAllRecordings,
|
||||
stopRecording,
|
||||
updateRecordingAccessPreferencesInRoom
|
||||
updateRecordingAccessConfigInRoom
|
||||
} from '../../../helpers/request-helpers.js';
|
||||
import { RoomData, setupSingleRoom, setupSingleRoomWithRecording } from '../../../helpers/test-scenarios.js';
|
||||
|
||||
@ -170,7 +170,7 @@ describe('Recording API Security Tests', () => {
|
||||
});
|
||||
|
||||
it('should succeed when recording access is admin_moderator_speaker and participant is speaker', async () => {
|
||||
await updateRecordingAccessPreferencesInRoom(
|
||||
await updateRecordingAccessConfigInRoom(
|
||||
roomData.room.roomId,
|
||||
MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER
|
||||
);
|
||||
@ -184,7 +184,7 @@ describe('Recording API Security Tests', () => {
|
||||
});
|
||||
|
||||
it('should succeed when recording access is admin_moderator_speaker and participant is moderator', async () => {
|
||||
await updateRecordingAccessPreferencesInRoom(
|
||||
await updateRecordingAccessConfigInRoom(
|
||||
roomData.room.roomId,
|
||||
MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER
|
||||
);
|
||||
@ -198,7 +198,7 @@ describe('Recording API Security Tests', () => {
|
||||
});
|
||||
|
||||
it('should fail when recording access is admin_moderator and participant is speaker', async () => {
|
||||
await updateRecordingAccessPreferencesInRoom(roomData.room.roomId, MeetRecordingAccess.ADMIN_MODERATOR);
|
||||
await updateRecordingAccessConfigInRoom(roomData.room.roomId, MeetRecordingAccess.ADMIN_MODERATOR);
|
||||
const recordingCookie = await generateRecordingTokenCookie(
|
||||
roomData.room.roomId,
|
||||
roomData.speakerSecret
|
||||
@ -209,7 +209,7 @@ describe('Recording API Security Tests', () => {
|
||||
});
|
||||
|
||||
it('should succeed when recording access is admin_moderator and participant is moderator', async () => {
|
||||
await updateRecordingAccessPreferencesInRoom(roomData.room.roomId, MeetRecordingAccess.ADMIN_MODERATOR);
|
||||
await updateRecordingAccessConfigInRoom(roomData.room.roomId, MeetRecordingAccess.ADMIN_MODERATOR);
|
||||
const recordingCookie = await generateRecordingTokenCookie(
|
||||
roomData.room.roomId,
|
||||
roomData.moderatorSecret
|
||||
@ -234,7 +234,7 @@ describe('Recording API Security Tests', () => {
|
||||
});
|
||||
|
||||
it('should succeed when recording access is admin_moderator_speaker and participant is speaker', async () => {
|
||||
await updateRecordingAccessPreferencesInRoom(
|
||||
await updateRecordingAccessConfigInRoom(
|
||||
roomData.room.roomId,
|
||||
MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER
|
||||
);
|
||||
@ -250,7 +250,7 @@ describe('Recording API Security Tests', () => {
|
||||
});
|
||||
|
||||
it('should succeed when recording access is admin_moderator_speaker and participant is moderator', async () => {
|
||||
await updateRecordingAccessPreferencesInRoom(
|
||||
await updateRecordingAccessConfigInRoom(
|
||||
roomData.room.roomId,
|
||||
MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER
|
||||
);
|
||||
@ -266,7 +266,7 @@ describe('Recording API Security Tests', () => {
|
||||
});
|
||||
|
||||
it('should fail when recording access is admin_moderator and participant is speaker', async () => {
|
||||
await updateRecordingAccessPreferencesInRoom(roomData.room.roomId, MeetRecordingAccess.ADMIN_MODERATOR);
|
||||
await updateRecordingAccessConfigInRoom(roomData.room.roomId, MeetRecordingAccess.ADMIN_MODERATOR);
|
||||
const recordingCookie = await generateRecordingTokenCookie(
|
||||
roomData.room.roomId,
|
||||
roomData.speakerSecret
|
||||
@ -279,7 +279,7 @@ describe('Recording API Security Tests', () => {
|
||||
});
|
||||
|
||||
it('should succeed when recording access is admin_moderator and participant is moderator', async () => {
|
||||
await updateRecordingAccessPreferencesInRoom(roomData.room.roomId, MeetRecordingAccess.ADMIN_MODERATOR);
|
||||
await updateRecordingAccessConfigInRoom(roomData.room.roomId, MeetRecordingAccess.ADMIN_MODERATOR);
|
||||
const recordingCookie = await generateRecordingTokenCookie(
|
||||
roomData.room.roomId,
|
||||
roomData.moderatorSecret
|
||||
@ -363,7 +363,7 @@ describe('Recording API Security Tests', () => {
|
||||
});
|
||||
|
||||
it('should fail when recording access is admin_moderator_speaker and participant is speaker', async () => {
|
||||
await updateRecordingAccessPreferencesInRoom(
|
||||
await updateRecordingAccessConfigInRoom(
|
||||
roomData.room.roomId,
|
||||
MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER
|
||||
);
|
||||
@ -379,7 +379,7 @@ describe('Recording API Security Tests', () => {
|
||||
});
|
||||
|
||||
it('should succeed when recording access is admin_moderator_speaker and participant is moderator', async () => {
|
||||
await updateRecordingAccessPreferencesInRoom(
|
||||
await updateRecordingAccessConfigInRoom(
|
||||
roomData.room.roomId,
|
||||
MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER
|
||||
);
|
||||
@ -395,7 +395,7 @@ describe('Recording API Security Tests', () => {
|
||||
});
|
||||
|
||||
it('should fail when recording access is admin_moderator and participant is speaker', async () => {
|
||||
await updateRecordingAccessPreferencesInRoom(roomData.room.roomId, MeetRecordingAccess.ADMIN_MODERATOR);
|
||||
await updateRecordingAccessConfigInRoom(roomData.room.roomId, MeetRecordingAccess.ADMIN_MODERATOR);
|
||||
const recordingCookie = await generateRecordingTokenCookie(
|
||||
roomData.room.roomId,
|
||||
roomData.speakerSecret
|
||||
@ -408,7 +408,7 @@ describe('Recording API Security Tests', () => {
|
||||
});
|
||||
|
||||
it('should succeed when recording access is admin_moderator and participant is moderator', async () => {
|
||||
await updateRecordingAccessPreferencesInRoom(roomData.room.roomId, MeetRecordingAccess.ADMIN_MODERATOR);
|
||||
await updateRecordingAccessConfigInRoom(roomData.room.roomId, MeetRecordingAccess.ADMIN_MODERATOR);
|
||||
const recordingCookie = await generateRecordingTokenCookie(
|
||||
roomData.room.roomId,
|
||||
roomData.moderatorSecret
|
||||
@ -450,7 +450,7 @@ describe('Recording API Security Tests', () => {
|
||||
});
|
||||
|
||||
it('should fail when recording access is admin_moderator_speaker and participant is speaker', async () => {
|
||||
await updateRecordingAccessPreferencesInRoom(
|
||||
await updateRecordingAccessConfigInRoom(
|
||||
roomData.room.roomId,
|
||||
MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER
|
||||
);
|
||||
@ -467,7 +467,7 @@ describe('Recording API Security Tests', () => {
|
||||
});
|
||||
|
||||
it('should succeed when recording access is admin_moderator_speaker and participant is moderator', async () => {
|
||||
await updateRecordingAccessPreferencesInRoom(
|
||||
await updateRecordingAccessConfigInRoom(
|
||||
roomData.room.roomId,
|
||||
MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER
|
||||
);
|
||||
@ -484,7 +484,7 @@ describe('Recording API Security Tests', () => {
|
||||
});
|
||||
|
||||
it('should fail when recording access is admin_moderator and participant is speaker', async () => {
|
||||
await updateRecordingAccessPreferencesInRoom(roomData.room.roomId, MeetRecordingAccess.ADMIN_MODERATOR);
|
||||
await updateRecordingAccessConfigInRoom(roomData.room.roomId, MeetRecordingAccess.ADMIN_MODERATOR);
|
||||
const recordingCookie = await generateRecordingTokenCookie(
|
||||
roomData.room.roomId,
|
||||
roomData.speakerSecret
|
||||
@ -498,7 +498,7 @@ describe('Recording API Security Tests', () => {
|
||||
});
|
||||
|
||||
it('should succeed when recording access is admin_moderator and participant is moderator', async () => {
|
||||
await updateRecordingAccessPreferencesInRoom(roomData.room.roomId, MeetRecordingAccess.ADMIN_MODERATOR);
|
||||
await updateRecordingAccessConfigInRoom(roomData.room.roomId, MeetRecordingAccess.ADMIN_MODERATOR);
|
||||
const recordingCookie = await generateRecordingTokenCookie(
|
||||
roomData.room.roomId,
|
||||
roomData.moderatorSecret
|
||||
@ -528,7 +528,7 @@ describe('Recording API Security Tests', () => {
|
||||
});
|
||||
|
||||
it('should succeed when recording access is admin_moderator_speaker and participant is speaker', async () => {
|
||||
await updateRecordingAccessPreferencesInRoom(
|
||||
await updateRecordingAccessConfigInRoom(
|
||||
roomData.room.roomId,
|
||||
MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER
|
||||
);
|
||||
@ -544,7 +544,7 @@ describe('Recording API Security Tests', () => {
|
||||
});
|
||||
|
||||
it('should succeed when recording access is admin_moderator_speaker and participant is moderator', async () => {
|
||||
await updateRecordingAccessPreferencesInRoom(
|
||||
await updateRecordingAccessConfigInRoom(
|
||||
roomData.room.roomId,
|
||||
MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER
|
||||
);
|
||||
@ -560,7 +560,7 @@ describe('Recording API Security Tests', () => {
|
||||
});
|
||||
|
||||
it('should fail when recording access is admin_moderator and participant is speaker', async () => {
|
||||
await updateRecordingAccessPreferencesInRoom(roomData.room.roomId, MeetRecordingAccess.ADMIN_MODERATOR);
|
||||
await updateRecordingAccessConfigInRoom(roomData.room.roomId, MeetRecordingAccess.ADMIN_MODERATOR);
|
||||
const recordingCookie = await generateRecordingTokenCookie(
|
||||
roomData.room.roomId,
|
||||
roomData.speakerSecret
|
||||
@ -573,7 +573,7 @@ describe('Recording API Security Tests', () => {
|
||||
});
|
||||
|
||||
it('should succeed when recording access is admin_moderator and participant is moderator', async () => {
|
||||
await updateRecordingAccessPreferencesInRoom(roomData.room.roomId, MeetRecordingAccess.ADMIN_MODERATOR);
|
||||
await updateRecordingAccessConfigInRoom(roomData.room.roomId, MeetRecordingAccess.ADMIN_MODERATOR);
|
||||
const recordingCookie = await generateRecordingTokenCookie(
|
||||
roomData.room.roomId,
|
||||
roomData.moderatorSecret
|
||||
@ -652,7 +652,7 @@ describe('Recording API Security Tests', () => {
|
||||
});
|
||||
|
||||
it('should succeed when recording access is admin_moderator_speaker and participant is speaker', async () => {
|
||||
await updateRecordingAccessPreferencesInRoom(
|
||||
await updateRecordingAccessConfigInRoom(
|
||||
roomData.room.roomId,
|
||||
MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER
|
||||
);
|
||||
@ -668,7 +668,7 @@ describe('Recording API Security Tests', () => {
|
||||
});
|
||||
|
||||
it('should succeed when recording access is admin_moderator_speaker and participant is moderator', async () => {
|
||||
await updateRecordingAccessPreferencesInRoom(
|
||||
await updateRecordingAccessConfigInRoom(
|
||||
roomData.room.roomId,
|
||||
MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER
|
||||
);
|
||||
@ -684,7 +684,7 @@ describe('Recording API Security Tests', () => {
|
||||
});
|
||||
|
||||
it('should fail when recording access is admin_moderator and participant is speaker', async () => {
|
||||
await updateRecordingAccessPreferencesInRoom(roomData.room.roomId, MeetRecordingAccess.ADMIN_MODERATOR);
|
||||
await updateRecordingAccessConfigInRoom(roomData.room.roomId, MeetRecordingAccess.ADMIN_MODERATOR);
|
||||
const recordingCookie = await generateRecordingTokenCookie(
|
||||
roomData.room.roomId,
|
||||
roomData.speakerSecret
|
||||
@ -697,7 +697,7 @@ describe('Recording API Security Tests', () => {
|
||||
});
|
||||
|
||||
it('should succeed when recording access is admin_moderator and participant is moderator', async () => {
|
||||
await updateRecordingAccessPreferencesInRoom(roomData.room.roomId, MeetRecordingAccess.ADMIN_MODERATOR);
|
||||
await updateRecordingAccessConfigInRoom(roomData.room.roomId, MeetRecordingAccess.ADMIN_MODERATOR);
|
||||
const recordingCookie = await generateRecordingTokenCookie(
|
||||
roomData.room.roomId,
|
||||
roomData.moderatorSecret
|
||||
@ -728,7 +728,7 @@ describe('Recording API Security Tests', () => {
|
||||
});
|
||||
|
||||
it('should succeed when recording access is admin_moderator_speaker and participant is speaker', async () => {
|
||||
await updateRecordingAccessPreferencesInRoom(
|
||||
await updateRecordingAccessConfigInRoom(
|
||||
roomData.room.roomId,
|
||||
MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER
|
||||
);
|
||||
@ -745,7 +745,7 @@ describe('Recording API Security Tests', () => {
|
||||
});
|
||||
|
||||
it('should succeed when recording access is admin_moderator_speaker and participant is moderator', async () => {
|
||||
await updateRecordingAccessPreferencesInRoom(
|
||||
await updateRecordingAccessConfigInRoom(
|
||||
roomData.room.roomId,
|
||||
MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER
|
||||
);
|
||||
@ -762,7 +762,7 @@ describe('Recording API Security Tests', () => {
|
||||
});
|
||||
|
||||
it('should fail when recording access is admin_moderator and participant is speaker', async () => {
|
||||
await updateRecordingAccessPreferencesInRoom(roomData.room.roomId, MeetRecordingAccess.ADMIN_MODERATOR);
|
||||
await updateRecordingAccessConfigInRoom(roomData.room.roomId, MeetRecordingAccess.ADMIN_MODERATOR);
|
||||
const recordingCookie = await generateRecordingTokenCookie(
|
||||
roomData.room.roomId,
|
||||
roomData.speakerSecret
|
||||
@ -776,7 +776,7 @@ describe('Recording API Security Tests', () => {
|
||||
});
|
||||
|
||||
it('should succeed when recording access is admin_moderator and participant is moderator', async () => {
|
||||
await updateRecordingAccessPreferencesInRoom(roomData.room.roomId, MeetRecordingAccess.ADMIN_MODERATOR);
|
||||
await updateRecordingAccessConfigInRoom(roomData.room.roomId, MeetRecordingAccess.ADMIN_MODERATOR);
|
||||
const recordingCookie = await generateRecordingTokenCookie(
|
||||
roomData.room.roomId,
|
||||
roomData.moderatorSecret
|
||||
|
||||
@ -12,7 +12,7 @@ import {
|
||||
disconnectFakeParticipants,
|
||||
loginUser,
|
||||
startTestServer,
|
||||
updateRecordingAccessPreferencesInRoom
|
||||
updateRecordingAccessConfigInRoom
|
||||
} from '../../../helpers/request-helpers.js';
|
||||
import { RoomData, setupSingleRoom, setupSingleRoomWithRecording } from '../../../helpers/test-scenarios.js';
|
||||
|
||||
@ -179,7 +179,7 @@ describe('Room API Security Tests', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('Get Room Preferences Tests', () => {
|
||||
describe('Get Room Config Tests', () => {
|
||||
let roomData: RoomData;
|
||||
|
||||
beforeAll(async () => {
|
||||
@ -188,26 +188,26 @@ describe('Room API Security Tests', () => {
|
||||
|
||||
it('should succeed when request includes API key', async () => {
|
||||
const response = await request(app)
|
||||
.get(`${ROOMS_PATH}/${roomData.room.roomId}/preferences`)
|
||||
.get(`${ROOMS_PATH}/${roomData.room.roomId}/config`)
|
||||
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY);
|
||||
expect(response.status).toBe(200);
|
||||
});
|
||||
|
||||
it('should succeed when user is authenticated as admin', async () => {
|
||||
const response = await request(app)
|
||||
.get(`${ROOMS_PATH}/${roomData.room.roomId}/preferences`)
|
||||
.get(`${ROOMS_PATH}/${roomData.room.roomId}/config`)
|
||||
.set('Cookie', adminCookie);
|
||||
expect(response.status).toBe(200);
|
||||
});
|
||||
|
||||
it('should fail when user is not authenticated', async () => {
|
||||
const response = await request(app).get(`${ROOMS_PATH}/${roomData.room.roomId}/preferences`);
|
||||
const response = await request(app).get(`${ROOMS_PATH}/${roomData.room.roomId}/config`);
|
||||
expect(response.status).toBe(401);
|
||||
});
|
||||
|
||||
it('should succeed when participant is moderator', async () => {
|
||||
const response = await request(app)
|
||||
.get(`${ROOMS_PATH}/${roomData.room.roomId}/preferences`)
|
||||
.get(`${ROOMS_PATH}/${roomData.room.roomId}/config`)
|
||||
.set('Cookie', roomData.moderatorCookie)
|
||||
.set(INTERNAL_CONFIG.PARTICIPANT_ROLE_HEADER, ParticipantRole.MODERATOR);
|
||||
expect(response.status).toBe(200);
|
||||
@ -217,7 +217,7 @@ describe('Room API Security Tests', () => {
|
||||
const newRoomData = await setupSingleRoom();
|
||||
|
||||
const response = await request(app)
|
||||
.get(`${ROOMS_PATH}/${roomData.room.roomId}/preferences`)
|
||||
.get(`${ROOMS_PATH}/${roomData.room.roomId}/config`)
|
||||
.set('Cookie', newRoomData.moderatorCookie)
|
||||
.set(INTERNAL_CONFIG.PARTICIPANT_ROLE_HEADER, ParticipantRole.MODERATOR);
|
||||
expect(response.status).toBe(403);
|
||||
@ -225,7 +225,7 @@ describe('Room API Security Tests', () => {
|
||||
|
||||
it('should succeed when participant is speaker', async () => {
|
||||
const response = await request(app)
|
||||
.get(`${ROOMS_PATH}/${roomData.room.roomId}/preferences`)
|
||||
.get(`${ROOMS_PATH}/${roomData.room.roomId}/config`)
|
||||
.set('Cookie', roomData.speakerCookie)
|
||||
.set(INTERNAL_CONFIG.PARTICIPANT_ROLE_HEADER, ParticipantRole.SPEAKER);
|
||||
expect(response.status).toBe(200);
|
||||
@ -235,21 +235,21 @@ describe('Room API Security Tests', () => {
|
||||
const newRoomData = await setupSingleRoom();
|
||||
|
||||
const response = await request(app)
|
||||
.get(`${ROOMS_PATH}/${roomData.room.roomId}/preferences`)
|
||||
.get(`${ROOMS_PATH}/${roomData.room.roomId}/config`)
|
||||
.set('Cookie', newRoomData.speakerCookie)
|
||||
.set(INTERNAL_CONFIG.PARTICIPANT_ROLE_HEADER, ParticipantRole.SPEAKER);
|
||||
expect(response.status).toBe(403);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Update Room Preferences Tests', () => {
|
||||
const roomPreferences = {
|
||||
recordingPreferences: {
|
||||
describe('Update Room Config Tests', () => {
|
||||
const roomConfig = {
|
||||
recordingConfig: {
|
||||
enabled: false,
|
||||
allowAccessTo: MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER
|
||||
},
|
||||
chatPreferences: { enabled: true },
|
||||
virtualBackgroundPreferences: { enabled: true }
|
||||
chatConfig: { enabled: true },
|
||||
virtualBackgroundConfig: { enabled: true }
|
||||
};
|
||||
|
||||
let roomId: string;
|
||||
@ -261,24 +261,22 @@ describe('Room API Security Tests', () => {
|
||||
|
||||
it('should succeed when request includes API key', async () => {
|
||||
const response = await request(app)
|
||||
.put(`${ROOMS_PATH}/${roomId}/preferences`)
|
||||
.put(`${ROOMS_PATH}/${roomId}/config`)
|
||||
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY)
|
||||
.send({ preferences: roomPreferences });
|
||||
.send({ config: roomConfig });
|
||||
expect(response.status).toBe(200);
|
||||
});
|
||||
|
||||
it('should succeed when user is authenticated as admin', async () => {
|
||||
const response = await request(app)
|
||||
.put(`${ROOMS_PATH}/${roomId}/preferences`)
|
||||
.put(`${ROOMS_PATH}/${roomId}/config`)
|
||||
.set('Cookie', adminCookie)
|
||||
.send({ preferences: roomPreferences });
|
||||
.send({ config: roomConfig });
|
||||
expect(response.status).toBe(200);
|
||||
});
|
||||
|
||||
it('should fail when user is not authenticated', async () => {
|
||||
const response = await request(app)
|
||||
.put(`${ROOMS_PATH}/${roomId}/preferences`)
|
||||
.send({ preferences: roomPreferences });
|
||||
const response = await request(app).put(`${ROOMS_PATH}/${roomId}/config`).send({ config: roomConfig });
|
||||
expect(response.status).toBe(401);
|
||||
});
|
||||
});
|
||||
@ -308,9 +306,7 @@ describe('Room API Security Tests', () => {
|
||||
});
|
||||
|
||||
it('should fail when user is not authenticated', async () => {
|
||||
const response = await request(app)
|
||||
.put(`${ROOMS_PATH}/${roomId}/status`)
|
||||
.send({ status: 'open' });
|
||||
const response = await request(app).put(`${ROOMS_PATH}/${roomId}/status`).send({ status: 'open' });
|
||||
expect(response.status).toBe(401);
|
||||
});
|
||||
});
|
||||
@ -323,10 +319,7 @@ describe('Room API Security Tests', () => {
|
||||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
await updateRecordingAccessPreferencesInRoom(
|
||||
roomData.room.roomId,
|
||||
MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER
|
||||
);
|
||||
await updateRecordingAccessConfigInRoom(roomData.room.roomId, MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER);
|
||||
});
|
||||
|
||||
it('should succeed when no authentication is required and participant is speaker', async () => {
|
||||
@ -414,7 +407,7 @@ describe('Room API Security Tests', () => {
|
||||
});
|
||||
|
||||
it('should fail when recording access is set to admin only', async () => {
|
||||
await updateRecordingAccessPreferencesInRoom(roomData.room.roomId, MeetRecordingAccess.ADMIN);
|
||||
await updateRecordingAccessConfigInRoom(roomData.room.roomId, MeetRecordingAccess.ADMIN);
|
||||
|
||||
const response = await request(app)
|
||||
.post(`${INTERNAL_ROOMS_PATH}/${roomData.room.roomId}/recording-token`)
|
||||
|
||||
@ -212,12 +212,12 @@
|
||||
|
||||
.auto-deletion-expired {
|
||||
font-weight: var(--ov-meet-font-weight-semibold);
|
||||
color: var(--ov-meet-color-error);
|
||||
color: var(--ov-meet-color-error);
|
||||
|
||||
.deletion-icon {
|
||||
color: var(--ov-meet-color-error);
|
||||
}
|
||||
}
|
||||
.deletion-icon {
|
||||
color: var(--ov-meet-color-error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.no-data {
|
||||
@ -240,7 +240,7 @@
|
||||
color: var(--ov-meet-color-primary);
|
||||
}
|
||||
|
||||
&.room-preferences-btn {
|
||||
&.room-config-btn {
|
||||
color: var(--ov-meet-icon-settings);
|
||||
}
|
||||
|
||||
|
||||
@ -56,7 +56,7 @@
|
||||
<ov-room-wizard-room-details></ov-room-wizard-room-details>
|
||||
}
|
||||
@case ('recording') {
|
||||
<ov-recording-preferences></ov-recording-preferences>
|
||||
<ov-recording-config></ov-recording-config>
|
||||
}
|
||||
@case ('recordingTrigger') {
|
||||
<ov-recording-trigger></ov-recording-trigger>
|
||||
@ -64,8 +64,8 @@
|
||||
@case ('recordingLayout') {
|
||||
<ov-recording-layout></ov-recording-layout>
|
||||
}
|
||||
@case ('preferences') {
|
||||
<ov-room-preferences></ov-room-preferences>
|
||||
@case ('config') {
|
||||
<ov-room-config></ov-room-config>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -10,11 +10,11 @@ import { WizardNavigationConfig, WizardStep } from '@lib/models';
|
||||
import { NavigationService, NotificationService, RoomService, RoomWizardStateService } from '@lib/services';
|
||||
import { MeetRoomOptions } from '@lib/typings/ce';
|
||||
import { RoomBasicCreationComponent } from '../room-basic-creation/room-basic-creation.component';
|
||||
import { RecordingConfigComponent } from './steps/recording-config/recording-config.component';
|
||||
import { RecordingLayoutComponent } from './steps/recording-layout/recording-layout.component';
|
||||
import { RecordingPreferencesComponent } from './steps/recording-preferences/recording-preferences.component';
|
||||
import { RecordingTriggerComponent } from './steps/recording-trigger/recording-trigger.component';
|
||||
import { RoomConfigComponent } from './steps/room-config/room-config.component';
|
||||
import { RoomWizardRoomDetailsComponent } from './steps/room-details/room-details.component';
|
||||
import { RoomPreferencesComponent } from './steps/room-preferences/room-preferences.component';
|
||||
|
||||
@Component({
|
||||
selector: 'ov-room-wizard',
|
||||
@ -29,10 +29,10 @@ import { RoomPreferencesComponent } from './steps/room-preferences/room-preferen
|
||||
MatSlideToggleModule,
|
||||
RoomBasicCreationComponent,
|
||||
RoomWizardRoomDetailsComponent,
|
||||
RecordingPreferencesComponent,
|
||||
RecordingConfigComponent,
|
||||
RecordingTriggerComponent,
|
||||
RecordingLayoutComponent,
|
||||
RoomPreferencesComponent
|
||||
RoomConfigComponent
|
||||
],
|
||||
templateUrl: './room-wizard.component.html',
|
||||
styleUrl: './room-wizard.component.scss'
|
||||
@ -89,8 +89,8 @@ export class RoomWizardComponent implements OnInit {
|
||||
if (!this.roomId) return;
|
||||
|
||||
try {
|
||||
const { roomName, autoDeletionDate, preferences } = await this.roomService.getRoom(this.roomId);
|
||||
this.existingRoomData = { roomName, autoDeletionDate, preferences };
|
||||
const { roomName, autoDeletionDate, config } = await this.roomService.getRoom(this.roomId);
|
||||
this.existingRoomData = { roomName, autoDeletionDate, config };
|
||||
if (this.existingRoomData) {
|
||||
this.isBasicCreation.set(false);
|
||||
}
|
||||
@ -154,8 +154,8 @@ export class RoomWizardComponent implements OnInit {
|
||||
this.isCreatingRoom.set(true);
|
||||
|
||||
try {
|
||||
if (this.editMode && this.roomId && roomOptions.preferences) {
|
||||
await this.roomService.updateRoomPreferences(this.roomId, roomOptions.preferences);
|
||||
if (this.editMode && this.roomId && roomOptions.config) {
|
||||
await this.roomService.updateRoomConfig(this.roomId, roomOptions.config);
|
||||
await this.navigationService.navigateTo('rooms', undefined, true);
|
||||
this.notificationService.showSnackbar('Room updated successfully');
|
||||
} else {
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
<div class="recording-preferences-step fade-in">
|
||||
<div class="recording-config-step fade-in">
|
||||
<!-- Header Section -->
|
||||
<header class="step-header">
|
||||
<mat-icon class="ov-recording-icon step-icon">video_library</mat-icon>
|
||||
<div class="step-title-group">
|
||||
<h3 class="step-title">Recording Preferences</h3>
|
||||
<h3 class="step-title">Recording Config</h3>
|
||||
<p class="step-description">Choose whether to enable recording capabilities for this room</p>
|
||||
</div>
|
||||
</header>
|
||||
@ -1,6 +1,6 @@
|
||||
@import '../../../../../../../../../../src/assets/styles/design-tokens';
|
||||
|
||||
.recording-preferences-step {
|
||||
.recording-config-step {
|
||||
@include ov-page-content;
|
||||
@include ov-container;
|
||||
|
||||
@ -50,7 +50,6 @@
|
||||
padding: var(--ov-meet-spacing-lg) var(--ov-meet-spacing-lg) 0 var(--ov-meet-spacing-lg);
|
||||
overflow: hidden;
|
||||
|
||||
|
||||
.access-header {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
@ -18,7 +18,7 @@ interface RecordingAccessOption {
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'ov-recording-preferences',
|
||||
selector: 'ov-recording-config',
|
||||
standalone: true,
|
||||
imports: [
|
||||
CommonModule,
|
||||
@ -31,10 +31,10 @@ interface RecordingAccessOption {
|
||||
MatFormFieldModule,
|
||||
SelectableCardComponent
|
||||
],
|
||||
templateUrl: './recording-preferences.component.html',
|
||||
styleUrl: './recording-preferences.component.scss'
|
||||
templateUrl: './recording-config.component.html',
|
||||
styleUrl: './recording-config.component.scss'
|
||||
})
|
||||
export class RecordingPreferencesComponent implements OnDestroy {
|
||||
export class RecordingConfigComponent implements OnDestroy {
|
||||
recordingForm: FormGroup;
|
||||
isAnimatingOut = false;
|
||||
|
||||
@ -89,8 +89,8 @@ export class RecordingPreferencesComponent implements OnDestroy {
|
||||
const enabled = formValue.recordingEnabled === 'enabled';
|
||||
|
||||
const stepData: any = {
|
||||
preferences: {
|
||||
recordingPreferences: {
|
||||
config: {
|
||||
recordingConfig: {
|
||||
enabled,
|
||||
...(enabled && { allowAccessTo: formValue.allowAccessTo })
|
||||
}
|
||||
@ -1,18 +1,18 @@
|
||||
<div class="room-preferences-step fade-in">
|
||||
<div class="room-config-step fade-in">
|
||||
<!-- Header Section -->
|
||||
<header class="step-header">
|
||||
<mat-icon class="ov-room-icon step-icon">video_chat</mat-icon>
|
||||
<div class="step-title-group">
|
||||
<h3 class="step-title">Room Preferences</h3>
|
||||
<h3 class="step-title">Room Config</h3>
|
||||
<p class="step-description">Configure additional features and functionality for your room</p>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<!-- Form Section -->
|
||||
<main class="step-content">
|
||||
<form [formGroup]="preferencesForm" class="preferences-form">
|
||||
<!-- Preferences Cards Grid -->
|
||||
<div class="preferences-grid">
|
||||
<form [formGroup]="configForm" class="config-form">
|
||||
<!-- Config Cards Grid -->
|
||||
<div class="config-grid">
|
||||
<!-- Chat Settings Card -->
|
||||
<mat-card class="preference-card">
|
||||
<mat-card-content>
|
||||
@ -1,6 +1,6 @@
|
||||
@import '../../../../../../../../../../src/assets/styles/design-tokens';
|
||||
|
||||
.room-preferences-step {
|
||||
.room-config-step {
|
||||
@include ov-page-content;
|
||||
@include ov-container;
|
||||
|
||||
@ -41,13 +41,13 @@
|
||||
.step-content {
|
||||
margin-bottom: var(--ov-meet-spacing-md);
|
||||
|
||||
.preferences-form {
|
||||
.config-form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
|
||||
.preferences-grid {
|
||||
.config-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(350px, 1fr));
|
||||
gap: var(--ov-meet-spacing-md);
|
||||
@ -123,7 +123,7 @@
|
||||
|
||||
// Responsive design
|
||||
@media (max-width: 1024px) {
|
||||
.room-preferences-step {
|
||||
.room-config-step {
|
||||
// padding: var(--ov-meet-spacing-xs);
|
||||
|
||||
.step-header {
|
||||
@ -131,14 +131,14 @@
|
||||
margin-bottom: var(--ov-meet-spacing-md);
|
||||
}
|
||||
|
||||
.preferences-grid {
|
||||
.config-grid {
|
||||
gap: var(--ov-meet-spacing-sm);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.room-preferences-step {
|
||||
.room-config-step {
|
||||
.step-header {
|
||||
.step-title-group {
|
||||
.step-title {
|
||||
@ -151,7 +151,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
.preferences-grid {
|
||||
.config-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
@ -170,7 +170,7 @@
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.room-preferences-step {
|
||||
.room-config-step {
|
||||
.preference-card {
|
||||
.card-header {
|
||||
.icon-title-group {
|
||||
@ -7,22 +7,22 @@ import { RoomWizardStateService } from '@lib/services';
|
||||
import { Subject, takeUntil } from 'rxjs';
|
||||
|
||||
@Component({
|
||||
selector: 'ov-room-preferences',
|
||||
selector: 'ov-room-config',
|
||||
standalone: true,
|
||||
imports: [ReactiveFormsModule, MatCardModule, MatIconModule, MatSlideToggleModule],
|
||||
templateUrl: './room-preferences.component.html',
|
||||
styleUrl: './room-preferences.component.scss'
|
||||
templateUrl: './room-config.component.html',
|
||||
styleUrl: './room-config.component.scss'
|
||||
})
|
||||
export class RoomPreferencesComponent implements OnDestroy {
|
||||
preferencesForm: FormGroup;
|
||||
export class RoomConfigComponent implements OnDestroy {
|
||||
configForm: FormGroup;
|
||||
|
||||
private destroy$ = new Subject<void>();
|
||||
|
||||
constructor(private wizardService: RoomWizardStateService) {
|
||||
const currentStep = this.wizardService.currentStep();
|
||||
this.preferencesForm = currentStep!.formGroup;
|
||||
this.configForm = currentStep!.formGroup;
|
||||
|
||||
this.preferencesForm.valueChanges.pipe(takeUntil(this.destroy$)).subscribe((value) => {
|
||||
this.configForm.valueChanges.pipe(takeUntil(this.destroy$)).subscribe((value) => {
|
||||
this.saveFormData(value);
|
||||
});
|
||||
}
|
||||
@ -34,34 +34,34 @@ export class RoomPreferencesComponent implements OnDestroy {
|
||||
|
||||
private saveFormData(formValue: any): void {
|
||||
const stepData: any = {
|
||||
preferences: {
|
||||
chatPreferences: {
|
||||
config: {
|
||||
chatConfig: {
|
||||
enabled: formValue.chatEnabled
|
||||
},
|
||||
virtualBackgroundPreferences: {
|
||||
virtualBackgroundConfig: {
|
||||
enabled: formValue.virtualBackgroundsEnabled
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
this.wizardService.updateStepData('preferences', stepData);
|
||||
this.wizardService.updateStepData('config', stepData);
|
||||
}
|
||||
|
||||
onChatToggleChange(event: any): void {
|
||||
const isEnabled = event.checked;
|
||||
this.preferencesForm.patchValue({ chatEnabled: isEnabled });
|
||||
this.configForm.patchValue({ chatEnabled: isEnabled });
|
||||
}
|
||||
|
||||
onVirtualBackgroundToggleChange(event: any): void {
|
||||
const isEnabled = event.checked;
|
||||
this.preferencesForm.patchValue({ virtualBackgroundsEnabled: isEnabled });
|
||||
this.configForm.patchValue({ virtualBackgroundsEnabled: isEnabled });
|
||||
}
|
||||
|
||||
get chatEnabled(): boolean {
|
||||
return this.preferencesForm.value.chatEnabled || false;
|
||||
return this.configForm.value.chatEnabled || false;
|
||||
}
|
||||
|
||||
get virtualBackgroundsEnabled(): boolean {
|
||||
return this.preferencesForm.value.virtualBackgroundsEnabled || false;
|
||||
return this.configForm.value.virtualBackgroundsEnabled || false;
|
||||
}
|
||||
}
|
||||
@ -31,7 +31,7 @@ import {
|
||||
import { ILogger, LoggerService } from 'openvidu-components-angular';
|
||||
|
||||
@Component({
|
||||
selector: 'ov-room-preferences',
|
||||
selector: 'ov-room-config',
|
||||
standalone: true,
|
||||
imports: [
|
||||
MatListModule,
|
||||
@ -109,7 +109,7 @@ export class RoomsComponent implements OnInit {
|
||||
this.openRoom(action.rooms[0]);
|
||||
break;
|
||||
case 'edit':
|
||||
await this.editRoomPreferences(action.rooms[0]);
|
||||
await this.editRoomConfig(action.rooms[0]);
|
||||
break;
|
||||
case 'copyModeratorLink':
|
||||
this.copyModeratorLink(action.rooms[0]);
|
||||
@ -254,12 +254,12 @@ export class RoomsComponent implements OnInit {
|
||||
window.open(room.moderatorUrl, '_blank');
|
||||
}
|
||||
|
||||
private async editRoomPreferences(room: MeetRoom) {
|
||||
private async editRoomConfig(room: MeetRoom) {
|
||||
try {
|
||||
await this.navigationService.navigateTo(`rooms/${room.roomId}/edit`);
|
||||
} catch (error) {
|
||||
this.notificationService.showSnackbar('Error navigating to room preferences');
|
||||
this.log.e('Error navigating to room preferences:', error);
|
||||
this.notificationService.showSnackbar('Error navigating to room config');
|
||||
this.log.e('Error navigating to room config:', error);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -39,7 +39,7 @@ import {
|
||||
} from '@lib/typings/ce';
|
||||
import {
|
||||
MeetParticipantRoleUpdatedPayload,
|
||||
MeetRoomPreferencesUpdatedPayload,
|
||||
MeetRoomConfigUpdatedPayload,
|
||||
MeetSignalType
|
||||
} from '@lib/typings/ce/event.model';
|
||||
import {
|
||||
@ -270,7 +270,7 @@ export class MeetingComponent implements OnInit {
|
||||
try {
|
||||
await this.generateParticipantToken();
|
||||
await this.addParticipantNameToUrl();
|
||||
await this.roomService.loadRoomPreferences(this.roomId);
|
||||
await this.roomService.loadRoomConfig(this.roomId);
|
||||
this.showMeeting = true;
|
||||
|
||||
// Subscribe to remote participants updates
|
||||
@ -357,13 +357,13 @@ export class MeetingComponent implements OnInit {
|
||||
|
||||
break;
|
||||
}
|
||||
case MeetSignalType.MEET_ROOM_PREFERENCES_UPDATED: {
|
||||
// Update room preferences
|
||||
const { preferences } = event as MeetRoomPreferencesUpdatedPayload;
|
||||
this.featureConfService.setRoomPreferences(preferences);
|
||||
case MeetSignalType.MEET_ROOM_CONFIG_UPDATED: {
|
||||
// Update room config
|
||||
const { config } = event as MeetRoomConfigUpdatedPayload;
|
||||
this.featureConfService.setRoomConfig(config);
|
||||
|
||||
// Refresh recording token if recording is enabled
|
||||
if (preferences.recordingPreferences.enabled) {
|
||||
if (config.recordingConfig.enabled) {
|
||||
try {
|
||||
await this.recordingService.generateRecordingToken(this.roomId, this.roomSecret);
|
||||
} catch (error) {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { computed, Injectable, signal } from '@angular/core';
|
||||
import {
|
||||
MeetRoomPreferences,
|
||||
MeetRoomConfig,
|
||||
ParticipantPermissions,
|
||||
ParticipantRole,
|
||||
RecordingPermissions,
|
||||
@ -57,7 +57,7 @@ const DEFAULT_FEATURES: ApplicationFeatures = {
|
||||
|
||||
/**
|
||||
* Centralized service to manage feature configuration
|
||||
* based on room preferences and participant permissions
|
||||
* based on room config and participant permissions
|
||||
*/
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
@ -66,7 +66,7 @@ export class FeatureConfigurationService {
|
||||
protected log;
|
||||
|
||||
// Signals to handle reactive
|
||||
protected roomPreferences = signal<MeetRoomPreferences | undefined>(undefined);
|
||||
protected roomConfig = signal<MeetRoomConfig | undefined>(undefined);
|
||||
protected participantPermissions = signal<ParticipantPermissions | undefined>(undefined);
|
||||
protected participantRole = signal<ParticipantRole | undefined>(undefined);
|
||||
protected recordingPermissions = signal<RecordingPermissions | undefined>(undefined);
|
||||
@ -74,7 +74,7 @@ export class FeatureConfigurationService {
|
||||
// Computed signal to derive features based on current configurations
|
||||
public readonly features = computed<ApplicationFeatures>(() =>
|
||||
this.calculateFeatures(
|
||||
this.roomPreferences(),
|
||||
this.roomConfig(),
|
||||
this.participantPermissions(),
|
||||
this.participantRole(),
|
||||
this.recordingPermissions()
|
||||
@ -86,11 +86,11 @@ export class FeatureConfigurationService {
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates room preferences
|
||||
* Updates room config
|
||||
*/
|
||||
setRoomPreferences(preferences: MeetRoomPreferences): void {
|
||||
this.log.d('Updating room preferences', preferences);
|
||||
this.roomPreferences.set(preferences);
|
||||
setRoomConfig(config: MeetRoomConfig): void {
|
||||
this.log.d('Updating room config', config);
|
||||
this.roomConfig.set(config);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -128,7 +128,7 @@ export class FeatureConfigurationService {
|
||||
* Core logic to calculate features based on all configurations
|
||||
*/
|
||||
protected calculateFeatures(
|
||||
roomPrefs?: MeetRoomPreferences,
|
||||
roomPrefs?: MeetRoomConfig,
|
||||
participantPerms?: ParticipantPermissions,
|
||||
role?: ParticipantRole,
|
||||
recordingPerms?: RecordingPermissions
|
||||
@ -138,9 +138,9 @@ export class FeatureConfigurationService {
|
||||
|
||||
// Apply room configurations
|
||||
if (roomPrefs) {
|
||||
features.showRecordingPanel = roomPrefs.recordingPreferences.enabled;
|
||||
features.showChat = roomPrefs.chatPreferences.enabled;
|
||||
features.showBackgrounds = roomPrefs.virtualBackgroundPreferences.enabled;
|
||||
features.showRecordingPanel = roomPrefs.recordingConfig.enabled;
|
||||
features.showChat = roomPrefs.chatConfig.enabled;
|
||||
features.showBackgrounds = roomPrefs.virtualBackgroundConfig.enabled;
|
||||
}
|
||||
|
||||
// Apply participant permissions (these can restrict enabled features)
|
||||
@ -184,7 +184,7 @@ export class FeatureConfigurationService {
|
||||
* Resets all configurations to their initial values
|
||||
*/
|
||||
reset(): void {
|
||||
this.roomPreferences.set(undefined);
|
||||
this.roomConfig.set(undefined);
|
||||
this.participantPermissions.set(undefined);
|
||||
this.participantRole.set(undefined);
|
||||
}
|
||||
|
||||
@ -2,12 +2,12 @@ import { Injectable } from '@angular/core';
|
||||
import { FeatureConfigurationService, HttpService, ParticipantService, SessionStorageService } from '@lib/services';
|
||||
import {
|
||||
MeetRoom,
|
||||
MeetRoomConfig,
|
||||
MeetRoomDeletionPolicyWithMeeting,
|
||||
MeetRoomDeletionPolicyWithRecordings,
|
||||
MeetRoomDeletionSuccessCode,
|
||||
MeetRoomFilters,
|
||||
MeetRoomOptions,
|
||||
MeetRoomPreferences,
|
||||
MeetRoomRoleAndPermissions,
|
||||
MeetRoomStatus
|
||||
} from '@lib/typings/ce';
|
||||
@ -176,52 +176,52 @@ export class RoomService {
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the preferences for a specific room.
|
||||
* Retrieves the config for a specific room.
|
||||
*
|
||||
* @param roomId - The unique identifier of the room
|
||||
* @return A promise that resolves to the MeetRoomPreferences object
|
||||
* @return A promise that resolves to the MeetRoomConfig object
|
||||
*/
|
||||
async getRoomPreferences(roomId: string): Promise<MeetRoomPreferences> {
|
||||
this.log.d('Fetching room preferences for roomId:', roomId);
|
||||
async getRoomConfig(roomId: string): Promise<MeetRoomConfig> {
|
||||
this.log.d('Fetching room config for roomId:', roomId);
|
||||
|
||||
try {
|
||||
const path = `${this.ROOMS_API}/${roomId}/preferences`;
|
||||
const path = `${this.ROOMS_API}/${roomId}/config`;
|
||||
const headers = this.participantService.getParticipantRoleHeader();
|
||||
const preferences = await this.httpService.getRequest<MeetRoomPreferences>(path, headers);
|
||||
return preferences;
|
||||
const config = await this.httpService.getRequest<MeetRoomConfig>(path, headers);
|
||||
return config;
|
||||
} catch (error) {
|
||||
this.log.e('Error fetching room preferences', error);
|
||||
throw new Error(`Failed to fetch room preferences for roomId: ${roomId}`);
|
||||
this.log.e('Error fetching room config', error);
|
||||
throw new Error(`Failed to fetch room config for roomId: ${roomId}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the room preferences and updates the feature configuration service.
|
||||
* Loads the room config and updates the feature configuration service.
|
||||
*
|
||||
* @param roomId - The unique identifier of the room
|
||||
*/
|
||||
async loadRoomPreferences(roomId: string): Promise<void> {
|
||||
async loadRoomConfig(roomId: string): Promise<void> {
|
||||
try {
|
||||
const preferences = await this.getRoomPreferences(roomId);
|
||||
this.featureConfService.setRoomPreferences(preferences);
|
||||
console.log('Room preferences loaded:', preferences);
|
||||
const config = await this.getRoomConfig(roomId);
|
||||
this.featureConfService.setRoomConfig(config);
|
||||
console.log('Room config loaded:', config);
|
||||
} catch (error) {
|
||||
this.log.e('Error loading room preferences', error);
|
||||
throw new Error('Failed to load room preferences');
|
||||
this.log.e('Error loading room config', error);
|
||||
throw new Error('Failed to load room config');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves new room preferences.
|
||||
* Saves new room config.
|
||||
*
|
||||
* @param roomId - The unique identifier of the room
|
||||
* @param preferences - The room preferences to be saved.
|
||||
* @returns A promise that resolves when the preferences have been saved.
|
||||
* @param config - The room config to be saved.
|
||||
* @returns A promise that resolves when the config have been saved.
|
||||
*/
|
||||
async updateRoomPreferences(roomId: string, preferences: MeetRoomPreferences): Promise<void> {
|
||||
this.log.d('Saving room preferences', preferences);
|
||||
const path = `${this.ROOMS_API}/${roomId}/preferences`;
|
||||
await this.httpService.putRequest(path, { preferences });
|
||||
async updateRoomConfig(roomId: string, config: MeetRoomConfig): Promise<void> {
|
||||
this.log.d('Saving room config', config);
|
||||
const path = `${this.ROOMS_API}/${roomId}/config`;
|
||||
await this.httpService.putRequest(path, { config });
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -3,20 +3,20 @@ import { AbstractControl, FormBuilder, ValidationErrors, Validators } from '@ang
|
||||
import { WizardNavigationConfig, WizardStep } from '@lib/models';
|
||||
import {
|
||||
MeetRecordingAccess,
|
||||
MeetRoomConfig,
|
||||
MeetRoomDeletionPolicyWithMeeting,
|
||||
MeetRoomDeletionPolicyWithRecordings,
|
||||
MeetRoomOptions,
|
||||
MeetRoomPreferences
|
||||
MeetRoomOptions
|
||||
} from '@lib/typings/ce';
|
||||
|
||||
// Default room preferences following the app's defaults
|
||||
const DEFAULT_PREFERENCES: MeetRoomPreferences = {
|
||||
recordingPreferences: {
|
||||
// Default room config following the app's defaults
|
||||
const DEFAULT_CONFIG: MeetRoomConfig = {
|
||||
recordingConfig: {
|
||||
enabled: true,
|
||||
allowAccessTo: MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER
|
||||
},
|
||||
chatPreferences: { enabled: true },
|
||||
virtualBackgroundPreferences: { enabled: true }
|
||||
chatConfig: { enabled: true },
|
||||
virtualBackgroundConfig: { enabled: true }
|
||||
};
|
||||
|
||||
/**
|
||||
@ -32,7 +32,7 @@ export class RoomWizardStateService {
|
||||
private _visibleSteps = computed(() => this._steps().filter((step) => step.isVisible));
|
||||
private _currentStepIndex = signal<number>(0);
|
||||
private _roomOptions = signal<MeetRoomOptions>({
|
||||
preferences: DEFAULT_PREFERENCES
|
||||
config: DEFAULT_CONFIG
|
||||
});
|
||||
|
||||
public readonly steps = computed(() => this._steps());
|
||||
@ -60,9 +60,9 @@ export class RoomWizardStateService {
|
||||
// Initialize room options with defaults merged with existing data
|
||||
const initialRoomOptions: MeetRoomOptions = {
|
||||
...existingData,
|
||||
preferences: {
|
||||
...DEFAULT_PREFERENCES,
|
||||
...(existingData?.preferences || {})
|
||||
config: {
|
||||
...DEFAULT_CONFIG,
|
||||
...(existingData?.config || {})
|
||||
}
|
||||
};
|
||||
|
||||
@ -156,10 +156,8 @@ export class RoomWizardStateService {
|
||||
isActive: editMode, // Only active in edit mode
|
||||
isVisible: true,
|
||||
formGroup: this.formBuilder.group({
|
||||
recordingEnabled: initialRoomOptions.preferences!.recordingPreferences.enabled
|
||||
? 'enabled'
|
||||
: 'disabled',
|
||||
allowAccessTo: initialRoomOptions.preferences!.recordingPreferences.allowAccessTo
|
||||
recordingEnabled: initialRoomOptions.config!.recordingConfig.enabled ? 'enabled' : 'disabled',
|
||||
allowAccessTo: initialRoomOptions.config!.recordingConfig.allowAccessTo
|
||||
})
|
||||
},
|
||||
{
|
||||
@ -183,14 +181,14 @@ export class RoomWizardStateService {
|
||||
})
|
||||
},
|
||||
{
|
||||
id: 'preferences',
|
||||
id: 'config',
|
||||
label: 'Room Features',
|
||||
isCompleted: editMode, // In edit mode, all editable steps are completed
|
||||
isActive: false,
|
||||
isVisible: true,
|
||||
formGroup: this.formBuilder.group({
|
||||
chatEnabled: initialRoomOptions.preferences!.chatPreferences.enabled,
|
||||
virtualBackgroundsEnabled: initialRoomOptions.preferences!.virtualBackgroundPreferences.enabled
|
||||
chatEnabled: initialRoomOptions.config!.chatConfig.enabled,
|
||||
virtualBackgroundsEnabled: initialRoomOptions.config!.virtualBackgroundConfig.enabled
|
||||
})
|
||||
}
|
||||
];
|
||||
@ -234,13 +232,13 @@ export class RoomWizardStateService {
|
||||
case 'recording':
|
||||
updatedOptions = {
|
||||
...currentOptions,
|
||||
preferences: {
|
||||
...currentOptions.preferences,
|
||||
recordingPreferences: {
|
||||
...currentOptions.preferences?.recordingPreferences,
|
||||
...stepData.preferences?.recordingPreferences
|
||||
config: {
|
||||
...currentOptions.config,
|
||||
recordingConfig: {
|
||||
...currentOptions.config?.recordingConfig,
|
||||
...stepData.config?.recordingConfig
|
||||
}
|
||||
} as MeetRoomPreferences
|
||||
} as MeetRoomConfig
|
||||
};
|
||||
break;
|
||||
case 'recordingTrigger':
|
||||
@ -248,24 +246,24 @@ export class RoomWizardStateService {
|
||||
// These steps don't update room options
|
||||
updatedOptions = { ...currentOptions };
|
||||
break;
|
||||
case 'preferences':
|
||||
case 'config':
|
||||
updatedOptions = {
|
||||
...currentOptions,
|
||||
preferences: {
|
||||
...currentOptions.preferences,
|
||||
chatPreferences: {
|
||||
...currentOptions.preferences?.chatPreferences,
|
||||
...stepData.preferences?.chatPreferences
|
||||
config: {
|
||||
...currentOptions.config,
|
||||
chatConfig: {
|
||||
...currentOptions.config?.chatConfig,
|
||||
...stepData.config?.chatConfig
|
||||
},
|
||||
virtualBackgroundPreferences: {
|
||||
...currentOptions.preferences?.virtualBackgroundPreferences,
|
||||
...stepData.preferences?.virtualBackgroundPreferences
|
||||
virtualBackgroundConfig: {
|
||||
...currentOptions.config?.virtualBackgroundConfig,
|
||||
...stepData.config?.virtualBackgroundConfig
|
||||
},
|
||||
recordingPreferences: {
|
||||
...currentOptions.preferences?.recordingPreferences,
|
||||
...stepData.preferences?.recordingPreferences
|
||||
recordingConfig: {
|
||||
...currentOptions.config?.recordingConfig,
|
||||
...stepData.config?.recordingConfig
|
||||
}
|
||||
} as MeetRoomPreferences
|
||||
} as MeetRoomConfig
|
||||
};
|
||||
break;
|
||||
default:
|
||||
@ -284,8 +282,8 @@ export class RoomWizardStateService {
|
||||
private updateStepsVisibility(): void {
|
||||
const currentSteps = this._steps();
|
||||
const currentOptions = this._roomOptions();
|
||||
// TODO: Uncomment when recording preferences are implemented
|
||||
const recordingEnabled = false; // currentOptions.preferences?.recordingPreferences.enabled ?? false;
|
||||
// TODO: Uncomment when recording config is fully implemented
|
||||
const recordingEnabled = false; // currentOptions.config?.recordingConfig.enabled ?? false;
|
||||
|
||||
// Update recording steps visibility based on recordingEnabled
|
||||
const updatedSteps = currentSteps.map((step) => {
|
||||
@ -414,7 +412,7 @@ export class RoomWizardStateService {
|
||||
*/
|
||||
resetWizard(): void {
|
||||
const defaultOptions: MeetRoomOptions = {
|
||||
preferences: DEFAULT_PREFERENCES
|
||||
config: DEFAULT_CONFIG
|
||||
};
|
||||
this._roomOptions.set(defaultOptions);
|
||||
this._steps.set([]);
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
"test:e2e-core-room": "playwright test tests/e2e/core/room.test.ts",
|
||||
"test:e2e-core-events": "playwright test tests/e2e/core/events.test.ts",
|
||||
"test:e2e-core-webhooks": "playwright test tests/e2e/core/webhooks.test.ts",
|
||||
"test:e2e-ui-features": "playwright test tests/e2e/ui-feature-preferences.test.ts",
|
||||
"test:e2e-ui-features": "playwright test tests/e2e/ui-feature-config.test.ts",
|
||||
"test:e2e-recording-access": "playwright test tests/e2e/recording-access.test.ts",
|
||||
"lint": "eslint 'src/**/*.ts'"
|
||||
},
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { test } from '@playwright/test';
|
||||
import { MeetRecordingAccess } from '../../../../typings/src/room-preferences';
|
||||
import { MeetRecordingAccess } from '../../../../typings/src/room-config';
|
||||
import { MEET_TESTAPP_URL } from '../config';
|
||||
import {
|
||||
accessRoomAs,
|
||||
@ -11,7 +11,7 @@ import {
|
||||
loginAsAdmin,
|
||||
prepareForJoiningRoom,
|
||||
startStopRecording,
|
||||
updateRoomPreferences,
|
||||
updateRoomConfig,
|
||||
viewRecordingsAs,
|
||||
waitForElementInIframe
|
||||
} from '../helpers/function-helpers';
|
||||
@ -72,15 +72,15 @@ test.describe('Recording Access Tests', () => {
|
||||
});
|
||||
|
||||
test('should moderator not be able to access recording when access level is set to admin', async ({ page }) => {
|
||||
await updateRoomPreferences(
|
||||
await updateRoomConfig(
|
||||
roomId,
|
||||
{
|
||||
chatPreferences: { enabled: true },
|
||||
recordingPreferences: {
|
||||
chatConfig: { enabled: true },
|
||||
recordingConfig: {
|
||||
enabled: true,
|
||||
allowAccessTo: MeetRecordingAccess.ADMIN
|
||||
},
|
||||
virtualBackgroundPreferences: { enabled: true }
|
||||
virtualBackgroundConfig: { enabled: true }
|
||||
},
|
||||
adminCookie
|
||||
);
|
||||
@ -93,15 +93,15 @@ test.describe('Recording Access Tests', () => {
|
||||
});
|
||||
|
||||
test('should speaker not be able to access recording when access level is set to admin', async ({ page }) => {
|
||||
await updateRoomPreferences(
|
||||
await updateRoomConfig(
|
||||
roomId,
|
||||
{
|
||||
chatPreferences: { enabled: true },
|
||||
recordingPreferences: {
|
||||
chatConfig: { enabled: true },
|
||||
recordingConfig: {
|
||||
enabled: true,
|
||||
allowAccessTo: MeetRecordingAccess.ADMIN
|
||||
},
|
||||
virtualBackgroundPreferences: { enabled: true }
|
||||
virtualBackgroundConfig: { enabled: true }
|
||||
},
|
||||
adminCookie
|
||||
);
|
||||
@ -114,15 +114,15 @@ test.describe('Recording Access Tests', () => {
|
||||
});
|
||||
|
||||
test('should allow moderator to access recording when access level is set to moderator', async ({ page }) => {
|
||||
await updateRoomPreferences(
|
||||
await updateRoomConfig(
|
||||
roomId,
|
||||
{
|
||||
chatPreferences: { enabled: true },
|
||||
recordingPreferences: {
|
||||
chatConfig: { enabled: true },
|
||||
recordingConfig: {
|
||||
enabled: true,
|
||||
allowAccessTo: MeetRecordingAccess.ADMIN_MODERATOR
|
||||
},
|
||||
virtualBackgroundPreferences: { enabled: true }
|
||||
virtualBackgroundConfig: { enabled: true }
|
||||
},
|
||||
adminCookie
|
||||
);
|
||||
@ -135,15 +135,15 @@ test.describe('Recording Access Tests', () => {
|
||||
});
|
||||
|
||||
test('should speaker not be able to access recording when access level is set to moderator', async ({ page }) => {
|
||||
await updateRoomPreferences(
|
||||
await updateRoomConfig(
|
||||
roomId,
|
||||
{
|
||||
chatPreferences: { enabled: true },
|
||||
recordingPreferences: {
|
||||
chatConfig: { enabled: true },
|
||||
recordingConfig: {
|
||||
enabled: true,
|
||||
allowAccessTo: MeetRecordingAccess.ADMIN_MODERATOR
|
||||
},
|
||||
virtualBackgroundPreferences: { enabled: true }
|
||||
virtualBackgroundConfig: { enabled: true }
|
||||
},
|
||||
adminCookie
|
||||
);
|
||||
@ -156,15 +156,15 @@ test.describe('Recording Access Tests', () => {
|
||||
});
|
||||
|
||||
test('should allow moderators to access recording when access level is set to speaker', async ({ page }) => {
|
||||
await updateRoomPreferences(
|
||||
await updateRoomConfig(
|
||||
roomId,
|
||||
{
|
||||
chatPreferences: { enabled: true },
|
||||
recordingPreferences: {
|
||||
chatConfig: { enabled: true },
|
||||
recordingConfig: {
|
||||
enabled: true,
|
||||
allowAccessTo: MeetRecordingAccess.ADMIN_MODERATOR
|
||||
},
|
||||
virtualBackgroundPreferences: { enabled: true }
|
||||
virtualBackgroundConfig: { enabled: true }
|
||||
},
|
||||
adminCookie
|
||||
);
|
||||
@ -177,15 +177,15 @@ test.describe('Recording Access Tests', () => {
|
||||
});
|
||||
|
||||
test('should allow speaker to access recording when access level is set to speaker', async ({ page }) => {
|
||||
await updateRoomPreferences(
|
||||
await updateRoomConfig(
|
||||
roomId,
|
||||
{
|
||||
chatPreferences: { enabled: true },
|
||||
recordingPreferences: {
|
||||
chatConfig: { enabled: true },
|
||||
recordingConfig: {
|
||||
enabled: true,
|
||||
allowAccessTo: MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER
|
||||
},
|
||||
virtualBackgroundPreferences: { enabled: true }
|
||||
virtualBackgroundConfig: { enabled: true }
|
||||
},
|
||||
adminCookie
|
||||
);
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { expect, test } from '@playwright/test';
|
||||
import { MeetRecordingAccess } from '../../../../typings/src/room-preferences';
|
||||
import { MeetRecordingAccess } from '../../../../typings/src/room-config';
|
||||
import { MEET_TESTAPP_URL } from '../config';
|
||||
import {
|
||||
applyVirtualBackground,
|
||||
@ -14,14 +14,14 @@ import {
|
||||
loginAsAdmin,
|
||||
openMoreOptionsMenu,
|
||||
prepareForJoiningRoom,
|
||||
updateRoomPreferences,
|
||||
updateRoomConfig,
|
||||
waitForElementInIframe,
|
||||
waitForVirtualBackgroundToApply
|
||||
} from '../helpers/function-helpers';
|
||||
|
||||
let subscribedToAppErrors = false;
|
||||
|
||||
test.describe('UI Feature Preferences Tests', () => {
|
||||
test.describe('UI Feature Config Tests', () => {
|
||||
let roomId: string;
|
||||
let participantName: string;
|
||||
let adminCookie: string;
|
||||
@ -73,15 +73,15 @@ test.describe('UI Feature Preferences Tests', () => {
|
||||
});
|
||||
|
||||
test('should show chat button when chat is enabled', async ({ page }) => {
|
||||
await updateRoomPreferences(
|
||||
await updateRoomConfig(
|
||||
roomId,
|
||||
{
|
||||
chatPreferences: { enabled: true },
|
||||
recordingPreferences: {
|
||||
chatConfig: { enabled: true },
|
||||
recordingConfig: {
|
||||
enabled: true,
|
||||
allowAccessTo: MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER
|
||||
},
|
||||
virtualBackgroundPreferences: { enabled: true }
|
||||
virtualBackgroundConfig: { enabled: true }
|
||||
},
|
||||
adminCookie
|
||||
);
|
||||
@ -97,15 +97,15 @@ test.describe('UI Feature Preferences Tests', () => {
|
||||
|
||||
test('should hide chat button when chat is disabled', async ({ page }) => {
|
||||
// Disable chat via API
|
||||
await updateRoomPreferences(
|
||||
await updateRoomConfig(
|
||||
roomId,
|
||||
{
|
||||
chatPreferences: { enabled: false },
|
||||
recordingPreferences: {
|
||||
chatConfig: { enabled: false },
|
||||
recordingConfig: {
|
||||
enabled: true,
|
||||
allowAccessTo: MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER
|
||||
},
|
||||
virtualBackgroundPreferences: { enabled: true }
|
||||
virtualBackgroundConfig: { enabled: true }
|
||||
},
|
||||
adminCookie
|
||||
);
|
||||
@ -126,15 +126,15 @@ test.describe('UI Feature Preferences Tests', () => {
|
||||
|
||||
test.describe('Recording Feature', () => {
|
||||
test('should show recording button for moderators', async ({ page }) => {
|
||||
await updateRoomPreferences(
|
||||
await updateRoomConfig(
|
||||
roomId,
|
||||
{
|
||||
chatPreferences: { enabled: true },
|
||||
recordingPreferences: {
|
||||
chatConfig: { enabled: true },
|
||||
recordingConfig: {
|
||||
enabled: true,
|
||||
allowAccessTo: MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER
|
||||
},
|
||||
virtualBackgroundPreferences: { enabled: true }
|
||||
virtualBackgroundConfig: { enabled: true }
|
||||
},
|
||||
adminCookie
|
||||
);
|
||||
@ -160,15 +160,15 @@ test.describe('UI Feature Preferences Tests', () => {
|
||||
});
|
||||
|
||||
test('should not show recording button for speaker', async ({ page }) => {
|
||||
await updateRoomPreferences(
|
||||
await updateRoomConfig(
|
||||
roomId,
|
||||
{
|
||||
chatPreferences: { enabled: true },
|
||||
recordingPreferences: {
|
||||
chatConfig: { enabled: true },
|
||||
recordingConfig: {
|
||||
enabled: true,
|
||||
allowAccessTo: MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER
|
||||
},
|
||||
virtualBackgroundPreferences: { enabled: true }
|
||||
virtualBackgroundConfig: { enabled: true }
|
||||
},
|
||||
adminCookie
|
||||
);
|
||||
@ -185,15 +185,15 @@ test.describe('UI Feature Preferences Tests', () => {
|
||||
|
||||
test('should not show recording button for moderators when recording is disabled', async ({ page }) => {
|
||||
// Disable recording via API
|
||||
await updateRoomPreferences(
|
||||
await updateRoomConfig(
|
||||
roomId,
|
||||
{
|
||||
chatPreferences: { enabled: true },
|
||||
recordingPreferences: {
|
||||
chatConfig: { enabled: true },
|
||||
recordingConfig: {
|
||||
enabled: false,
|
||||
allowAccessTo: MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER
|
||||
},
|
||||
virtualBackgroundPreferences: { enabled: true }
|
||||
virtualBackgroundConfig: { enabled: true }
|
||||
},
|
||||
adminCookie
|
||||
);
|
||||
@ -226,15 +226,15 @@ test.describe('UI Feature Preferences Tests', () => {
|
||||
});
|
||||
test('should show virtual background button when enabled', async ({ page }) => {
|
||||
// Ensure virtual backgrounds are enabled
|
||||
await updateRoomPreferences(
|
||||
await updateRoomConfig(
|
||||
roomId,
|
||||
{
|
||||
chatPreferences: { enabled: true },
|
||||
recordingPreferences: {
|
||||
chatConfig: { enabled: true },
|
||||
recordingConfig: {
|
||||
enabled: true,
|
||||
allowAccessTo: MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER
|
||||
},
|
||||
virtualBackgroundPreferences: { enabled: true }
|
||||
virtualBackgroundConfig: { enabled: true }
|
||||
},
|
||||
adminCookie
|
||||
);
|
||||
@ -255,15 +255,15 @@ test.describe('UI Feature Preferences Tests', () => {
|
||||
|
||||
test('should hide virtual background button when disabled', async ({ page }) => {
|
||||
// Disable virtual backgrounds via API
|
||||
await updateRoomPreferences(
|
||||
await updateRoomConfig(
|
||||
roomId,
|
||||
{
|
||||
chatPreferences: { enabled: true },
|
||||
recordingPreferences: {
|
||||
chatConfig: { enabled: true },
|
||||
recordingConfig: {
|
||||
enabled: true,
|
||||
allowAccessTo: MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER
|
||||
},
|
||||
virtualBackgroundPreferences: { enabled: false }
|
||||
virtualBackgroundConfig: { enabled: false }
|
||||
},
|
||||
adminCookie
|
||||
);
|
||||
@ -284,15 +284,15 @@ test.describe('UI Feature Preferences Tests', () => {
|
||||
page
|
||||
}) => {
|
||||
// Ensure virtual backgrounds are enabled
|
||||
await updateRoomPreferences(
|
||||
await updateRoomConfig(
|
||||
roomId,
|
||||
{
|
||||
chatPreferences: { enabled: true },
|
||||
recordingPreferences: {
|
||||
chatConfig: { enabled: true },
|
||||
recordingConfig: {
|
||||
enabled: true,
|
||||
allowAccessTo: MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER
|
||||
},
|
||||
virtualBackgroundPreferences: { enabled: true }
|
||||
virtualBackgroundConfig: { enabled: true }
|
||||
},
|
||||
adminCookie
|
||||
);
|
||||
@ -305,15 +305,15 @@ test.describe('UI Feature Preferences Tests', () => {
|
||||
await waitForVirtualBackgroundToApply(page);
|
||||
|
||||
// Now disable virtual backgrounds
|
||||
await updateRoomPreferences(
|
||||
await updateRoomConfig(
|
||||
roomId,
|
||||
{
|
||||
chatPreferences: { enabled: true },
|
||||
recordingPreferences: {
|
||||
chatConfig: { enabled: true },
|
||||
recordingConfig: {
|
||||
enabled: true,
|
||||
allowAccessTo: MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER
|
||||
},
|
||||
virtualBackgroundPreferences: { enabled: false }
|
||||
virtualBackgroundConfig: { enabled: false }
|
||||
},
|
||||
adminCookie
|
||||
);
|
||||
@ -1,7 +1,7 @@
|
||||
import { expect, FrameLocator, Locator, Page } from '@playwright/test';
|
||||
import * as fs from 'fs';
|
||||
import { PNG } from 'pngjs';
|
||||
import { MeetRecordingAccess, MeetRoomPreferences } from '../../../../typings/src/room-preferences';
|
||||
import { MeetRecordingAccess, MeetRoomConfig } from '../../../../typings/src/room-config';
|
||||
import { MEET_ADMIN_PASSWORD, MEET_ADMIN_USER, MEET_API_KEY, MEET_API_URL, MEET_TESTAPP_URL } from '../config';
|
||||
|
||||
/**
|
||||
@ -88,21 +88,18 @@ export async function interactWithElementInIframe(
|
||||
}
|
||||
}
|
||||
|
||||
// Helper function to get default room preferences
|
||||
const getDefaultRoomPreferences = (): MeetRoomPreferences => ({
|
||||
recordingPreferences: {
|
||||
// Helper function to get default room config
|
||||
const getDefaultRoomConfig = (): MeetRoomConfig => ({
|
||||
recordingConfig: {
|
||||
enabled: true,
|
||||
allowAccessTo: MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER
|
||||
},
|
||||
chatPreferences: { enabled: true },
|
||||
virtualBackgroundPreferences: { enabled: true }
|
||||
chatConfig: { enabled: true },
|
||||
virtualBackgroundConfig: { enabled: true }
|
||||
});
|
||||
|
||||
// Helper function to create a room for testing
|
||||
export const createTestRoom = async (
|
||||
roomName: string,
|
||||
preferences: MeetRoomPreferences = getDefaultRoomPreferences()
|
||||
) => {
|
||||
export const createTestRoom = async (roomName: string, config: MeetRoomConfig = getDefaultRoomConfig()) => {
|
||||
const response = await fetch(`${MEET_API_URL}/api/v1/rooms`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
@ -112,7 +109,7 @@ export const createTestRoom = async (
|
||||
body: JSON.stringify({
|
||||
roomName,
|
||||
autoDeletionDate: new Date(Date.now() + 61 * 60 * 1000).getTime(), // 1 hour from now
|
||||
preferences
|
||||
config
|
||||
})
|
||||
});
|
||||
|
||||
@ -126,19 +123,19 @@ export const createTestRoom = async (
|
||||
return room.roomId;
|
||||
};
|
||||
|
||||
// Helper function to update room preferences via REST API
|
||||
export const updateRoomPreferences = async (roomId: string, preferences: any, adminCookie: string) => {
|
||||
const response = await fetch(`${MEET_API_URL}/api/v1/rooms/${roomId}/preferences`, {
|
||||
// Helper function to update room config via REST API
|
||||
export const updateRoomConfig = async (roomId: string, config: any, adminCookie: string) => {
|
||||
const response = await fetch(`${MEET_API_URL}/api/v1/rooms/${roomId}/config`, {
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Cookie: adminCookie
|
||||
},
|
||||
body: JSON.stringify({ preferences })
|
||||
body: JSON.stringify({ config })
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed to update room preferences: ${response.status} ${await response.text()}`);
|
||||
throw new Error(`Failed to update room config: ${response.status} ${await response.text()}`);
|
||||
}
|
||||
|
||||
return response.json();
|
||||
|
||||
@ -1,168 +1,168 @@
|
||||
:root {
|
||||
--primary-color: #4a90e2;
|
||||
--secondary-color: #f4f4f4;
|
||||
--primary-color: #4a90e2;
|
||||
--secondary-color: #f4f4f4;
|
||||
}
|
||||
|
||||
body,
|
||||
html {
|
||||
height: 100vh;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
background-color: #f8f9fa;
|
||||
padding: 0px;
|
||||
box-sizing: border-box;
|
||||
height: 100vh;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
background-color: #f8f9fa;
|
||||
padding: 0px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.container {
|
||||
width: 100%;
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
display: flex;
|
||||
gap: 25px;
|
||||
min-height: calc(80vh - 40px);
|
||||
max-height: calc(80vh - 40px);
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
width: 100%;
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
display: flex;
|
||||
gap: 25px;
|
||||
min-height: calc(80vh - 40px);
|
||||
max-height: calc(80vh - 40px);
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
|
||||
.action-buttons-container {
|
||||
display: inline-flex;
|
||||
gap: 2px;
|
||||
display: inline-flex;
|
||||
gap: 2px;
|
||||
}
|
||||
.rooms-container {
|
||||
flex: 2;
|
||||
background: white;
|
||||
padding: 20px;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
flex: 2;
|
||||
background: white;
|
||||
padding: 20px;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.create-room {
|
||||
flex: 1;
|
||||
background: var(--secondary-color);
|
||||
padding: 15px;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
flex: 1;
|
||||
background: var(--secondary-color);
|
||||
padding: 15px;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
}
|
||||
.create-room p,
|
||||
.create-room h2 {
|
||||
margin-bottom: 0 !important ;
|
||||
font-size: 0.9rem;
|
||||
margin-bottom: 0 !important ;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
.create-room h2 {
|
||||
font-size: 1.1rem; /* Smaller title */
|
||||
font-size: 1.1rem; /* Smaller title */
|
||||
}
|
||||
|
||||
/* Collapsible sections for room creation form */
|
||||
.preferences-accordion {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
.config-accordion {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.accordion-item {
|
||||
border: none;
|
||||
margin-bottom: 0.25rem;
|
||||
border: none;
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
|
||||
.accordion-button {
|
||||
background-color: var(--primary-color);
|
||||
color: white;
|
||||
border-radius: 0.25rem !important; /* Smaller radius */
|
||||
font-weight: 500; /* Less bold */
|
||||
font-size: 0.8rem; /* Smaller text */
|
||||
padding: 0.4rem 0.8rem; /* Much smaller padding */
|
||||
min-height: auto; /* Remove default height */
|
||||
background-color: var(--primary-color);
|
||||
color: white;
|
||||
border-radius: 0.25rem !important; /* Smaller radius */
|
||||
font-weight: 500; /* Less bold */
|
||||
font-size: 0.8rem; /* Smaller text */
|
||||
padding: 0.4rem 0.8rem; /* Much smaller padding */
|
||||
min-height: auto; /* Remove default height */
|
||||
}
|
||||
|
||||
.accordion-button:not(.collapsed) {
|
||||
background-color: var(--primary-color);
|
||||
color: white;
|
||||
box-shadow: none;
|
||||
background-color: var(--primary-color);
|
||||
color: white;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.accordion-button:focus {
|
||||
box-shadow: 0 0 0 0.25rem rgba(74, 144, 226, 0.25);
|
||||
box-shadow: 0 0 0 0.25rem rgba(74, 144, 226, 0.25);
|
||||
}
|
||||
|
||||
.accordion-body {
|
||||
padding: 0.5rem; /* Much smaller padding */
|
||||
background-color: #f8f9fa;
|
||||
font-size: 0.8rem; /* Smaller text */
|
||||
padding: 0.5rem; /* Much smaller padding */
|
||||
background-color: #f8f9fa;
|
||||
font-size: 0.8rem; /* Smaller text */
|
||||
}
|
||||
|
||||
form-label {
|
||||
font-size: 0.8rem; /* Smaller labels */
|
||||
margin-bottom: 0.25rem;
|
||||
font-size: 0.8rem; /* Smaller labels */
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
|
||||
.form-control,
|
||||
.form-select {
|
||||
font-size: 0.8rem; /* Smaller inputs */
|
||||
padding: 0.25rem 0.5rem; /* Smaller padding */
|
||||
font-size: 0.8rem; /* Smaller inputs */
|
||||
padding: 0.25rem 0.5rem; /* Smaller padding */
|
||||
}
|
||||
|
||||
.form-check {
|
||||
margin-bottom: 0.25rem; /* Smaller spacing */
|
||||
margin-bottom: 0.25rem; /* Smaller spacing */
|
||||
}
|
||||
|
||||
.form-check-label {
|
||||
font-size: 0.8rem; /* Smaller text */
|
||||
font-size: 0.8rem; /* Smaller text */
|
||||
}
|
||||
|
||||
.form-text {
|
||||
font-size: 0.7rem !important; /* Much smaller help text */
|
||||
margin-top: 0.125rem;
|
||||
font-size: 0.7rem !important; /* Much smaller help text */
|
||||
margin-top: 0.125rem;
|
||||
}
|
||||
|
||||
#recording-access-section {
|
||||
background-color: rgba(13, 110, 253, 0.1);
|
||||
padding: 0.4rem; /* Smaller padding */
|
||||
border-radius: 0.25rem;
|
||||
border-left: 2px solid var(--primary-color); /* Thinner border */
|
||||
margin-top: 0.25rem;
|
||||
background-color: rgba(13, 110, 253, 0.1);
|
||||
padding: 0.4rem; /* Smaller padding */
|
||||
border-radius: 0.25rem;
|
||||
border-left: 2px solid var(--primary-color); /* Thinner border */
|
||||
margin-top: 0.25rem;
|
||||
}
|
||||
|
||||
/* Compact button */
|
||||
.create-room-btn {
|
||||
font-size: 0.85rem; /* Smaller button text */
|
||||
padding: 0.4rem 0.8rem; /* Smaller button */
|
||||
margin-top: 0.5rem; /* Less top margin */
|
||||
font-size: 0.85rem; /* Smaller button text */
|
||||
padding: 0.4rem 0.8rem; /* Smaller button */
|
||||
margin-top: 0.5rem; /* Less top margin */
|
||||
}
|
||||
|
||||
/* Responsive adjustments */
|
||||
@media (max-height: 600px) {
|
||||
.container {
|
||||
flex-direction: column;
|
||||
max-height: none;
|
||||
min-height: auto;
|
||||
}
|
||||
.container {
|
||||
flex-direction: column;
|
||||
max-height: none;
|
||||
min-height: auto;
|
||||
}
|
||||
|
||||
.create-room {
|
||||
max-height: 350px; /* Smaller max height */
|
||||
}
|
||||
.create-room {
|
||||
max-height: 350px; /* Smaller max height */
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.container {
|
||||
flex-direction: column;
|
||||
max-height: none;
|
||||
gap: 15px;
|
||||
}
|
||||
.container {
|
||||
flex-direction: column;
|
||||
max-height: none;
|
||||
gap: 15px;
|
||||
}
|
||||
|
||||
body,
|
||||
html {
|
||||
padding: 10px;
|
||||
}
|
||||
body,
|
||||
html {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.create-room {
|
||||
padding: 10px; /* Even smaller on mobile */
|
||||
}
|
||||
.create-room {
|
||||
padding: 10px; /* Even smaller on mobile */
|
||||
}
|
||||
}
|
||||
|
||||
@ -181,10 +181,10 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Preferences Accordion -->
|
||||
<div class="preferences-accordion">
|
||||
<div class="accordion" id="preferencesAccordion">
|
||||
<!-- Chat Preferences -->
|
||||
<!-- Config Accordion -->
|
||||
<div class="config-accordion">
|
||||
<div class="accordion" id="configAccordion">
|
||||
<!-- Chat Config -->
|
||||
<div class="accordion-item">
|
||||
<h2 class="accordion-header">
|
||||
<button
|
||||
@ -194,7 +194,7 @@
|
||||
data-bs-target="#chatCollapse"
|
||||
aria-expanded="true"
|
||||
aria-controls="chatCollapse"
|
||||
data-testid="chat-preferences-toggle"
|
||||
data-testid="chat-config-toggle"
|
||||
>
|
||||
Chat Settings
|
||||
</button>
|
||||
@ -202,13 +202,13 @@
|
||||
<div
|
||||
id="chatCollapse"
|
||||
class="accordion-collapse collapse show"
|
||||
data-bs-parent="#preferencesAccordion"
|
||||
data-bs-parent="#configAccordion"
|
||||
>
|
||||
<div class="accordion-body">
|
||||
<div class="form-check">
|
||||
<input
|
||||
type="checkbox"
|
||||
name="preferences.chatPreferences.enabled"
|
||||
name="config.chatConfig.enabled"
|
||||
id="chat-enabled"
|
||||
class="form-check-input"
|
||||
checked
|
||||
@ -222,7 +222,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Recording Preferences -->
|
||||
<!-- Recording Config -->
|
||||
<div class="accordion-item">
|
||||
<h2 class="accordion-header">
|
||||
<button
|
||||
@ -232,7 +232,7 @@
|
||||
data-bs-target="#recordingCollapse"
|
||||
aria-expanded="false"
|
||||
aria-controls="recordingCollapse"
|
||||
data-testid="recording-preferences-toggle"
|
||||
data-testid="recording-config-toggle"
|
||||
>
|
||||
Recording Settings
|
||||
</button>
|
||||
@ -240,13 +240,13 @@
|
||||
<div
|
||||
id="recordingCollapse"
|
||||
class="accordion-collapse collapse"
|
||||
data-bs-parent="#preferencesAccordion"
|
||||
data-bs-parent="#configAccordion"
|
||||
>
|
||||
<div class="accordion-body">
|
||||
<div class="form-check mb-2">
|
||||
<input
|
||||
type="checkbox"
|
||||
name="preferences.recordingPreferences.enabled"
|
||||
name="config.recordingConfig.enabled"
|
||||
id="recording-enabled"
|
||||
class="form-check-input"
|
||||
checked
|
||||
@ -262,7 +262,7 @@
|
||||
>Recording Access Level</label
|
||||
>
|
||||
<select
|
||||
name="preferences.recordingPreferences.allowAccessTo"
|
||||
name="config.recordingConfig.allowAccessTo"
|
||||
id="recording-access"
|
||||
class="form-select"
|
||||
data-testid="recording-access-select"
|
||||
@ -280,7 +280,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Virtual Background Preferences -->
|
||||
<!-- Virtual Background Config -->
|
||||
<div class="accordion-item">
|
||||
<h2 class="accordion-header">
|
||||
<button
|
||||
@ -290,7 +290,7 @@
|
||||
data-bs-target="#backgroundCollapse"
|
||||
aria-expanded="false"
|
||||
aria-controls="backgroundCollapse"
|
||||
data-testid="background-preferences-toggle"
|
||||
data-testid="background-config-toggle"
|
||||
>
|
||||
Virtual Background Settings
|
||||
</button>
|
||||
@ -298,13 +298,13 @@
|
||||
<div
|
||||
id="backgroundCollapse"
|
||||
class="accordion-collapse collapse"
|
||||
data-bs-parent="#preferencesAccordion"
|
||||
data-bs-parent="#configAccordion"
|
||||
>
|
||||
<div class="accordion-body">
|
||||
<div class="form-check">
|
||||
<input
|
||||
type="checkbox"
|
||||
name="preferences.virtualBackgroundPreferences.enabled"
|
||||
name="config.virtualBackgroundConfig.enabled"
|
||||
id="virtual-background-enabled"
|
||||
class="form-check-input"
|
||||
checked
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { Request, Response } from 'express';
|
||||
import { getAllRooms, createRoom, deleteRoom, deleteAllRooms } from '../services/roomService';
|
||||
import { deleteAllRecordings, getAllRecordings } from '../services/recordingService';
|
||||
import { createRoom, deleteAllRooms, deleteRoom, getAllRooms } from '../services/roomService';
|
||||
|
||||
export const getHome = async (_req: Request, res: Response) => {
|
||||
try {
|
||||
@ -38,12 +38,12 @@ export const postCreateRoom = async (req: Request, res: Response) => {
|
||||
try {
|
||||
console.log('Creating room with body:', JSON.stringify(req.body, null, 2));
|
||||
const { roomName, autoDeletionDate } = req.body;
|
||||
const preferences = processFormPreferences(req.body);
|
||||
const config = processFormConfig(req.body);
|
||||
|
||||
console.log('Processed preferences:', JSON.stringify(preferences, null, 2));
|
||||
console.log('Processed config:', JSON.stringify(config, null, 2));
|
||||
console.log('Room creation parameters:', { roomName, autoDeletionDate });
|
||||
|
||||
const result = await createRoom({ roomName, autoDeletionDate, preferences });
|
||||
const result = await createRoom({ roomName, autoDeletionDate, config });
|
||||
console.log('Room created successfully:', result);
|
||||
res.redirect('/');
|
||||
} catch (error) {
|
||||
@ -154,24 +154,24 @@ export const deleteAllRecordingsCtrl = async (_req: Request, res: Response) => {
|
||||
};
|
||||
|
||||
/**
|
||||
* Converts flat form data to nested MeetRoomPreferences object
|
||||
* Converts flat form data to nested MeetRoomConfig object
|
||||
*/
|
||||
const processFormPreferences = (body: any): any => {
|
||||
const preferences = {
|
||||
chatPreferences: {
|
||||
enabled: body['preferences.chatPreferences.enabled'] === 'on'
|
||||
const processFormConfig = (body: any): any => {
|
||||
const config = {
|
||||
chatConfig: {
|
||||
enabled: body['config.chatConfig.enabled'] === 'on'
|
||||
},
|
||||
recordingPreferences: {
|
||||
enabled: body['preferences.recordingPreferences.enabled'] === 'on',
|
||||
recordingConfig: {
|
||||
enabled: body['config.recordingConfig.enabled'] === 'on',
|
||||
// Only include allowAccessTo if recording is enabled
|
||||
...(body['preferences.recordingPreferences.enabled'] === 'on' && {
|
||||
allowAccessTo: body['preferences.recordingPreferences.allowAccessTo'] || 'admin_moderator_speaker'
|
||||
...(body['config.recordingConfig.enabled'] === 'on' && {
|
||||
allowAccessTo: body['config.recordingConfig.allowAccessTo'] || 'admin_moderator_speaker'
|
||||
})
|
||||
},
|
||||
virtualBackgroundPreferences: {
|
||||
enabled: body['preferences.virtualBackgroundPreferences.enabled'] === 'on'
|
||||
virtualBackgroundConfig: {
|
||||
enabled: body['config.virtualBackgroundConfig.enabled'] === 'on'
|
||||
}
|
||||
};
|
||||
|
||||
return preferences;
|
||||
return config;
|
||||
};
|
||||
|
||||
@ -1,14 +1,14 @@
|
||||
import { ParticipantRole } from './participant.js';
|
||||
import { MeetRoomPreferences } from './room-preferences.js';
|
||||
import { MeetRoomConfig } from './room-config.js';
|
||||
|
||||
export enum MeetSignalType {
|
||||
MEET_ROOM_PREFERENCES_UPDATED = 'meet_room_preferences_updated',
|
||||
MEET_ROOM_CONFIG_UPDATED = 'meet_room_config_updated',
|
||||
MEET_PARTICIPANT_ROLE_UPDATED = 'meet_participant_role_updated'
|
||||
}
|
||||
|
||||
export interface MeetRoomPreferencesUpdatedPayload {
|
||||
export interface MeetRoomConfigUpdatedPayload {
|
||||
roomId: string;
|
||||
preferences: MeetRoomPreferences;
|
||||
config: MeetRoomConfig;
|
||||
timestamp: number;
|
||||
}
|
||||
|
||||
@ -20,4 +20,4 @@ export interface MeetParticipantRoleUpdatedPayload {
|
||||
timestamp: number;
|
||||
}
|
||||
|
||||
export type MeetSignalPayload = MeetRoomPreferencesUpdatedPayload | MeetParticipantRoleUpdatedPayload;
|
||||
export type MeetSignalPayload = MeetRoomConfigUpdatedPayload | MeetParticipantRoleUpdatedPayload;
|
||||
|
||||
@ -7,7 +7,7 @@ export * from './permissions/openvidu-permissions.js';
|
||||
export * from './participant.js';
|
||||
export * from './user.js';
|
||||
|
||||
export * from './room-preferences.js';
|
||||
export * from './room-config.js';
|
||||
export * from './room.js';
|
||||
export * from './recording.model.js';
|
||||
export * from './webhook.model.js';
|
||||
|
||||
30
typings/src/room-config.ts
Normal file
30
typings/src/room-config.ts
Normal file
@ -0,0 +1,30 @@
|
||||
/**
|
||||
* Interface representing the config for a room.
|
||||
*/
|
||||
export interface MeetRoomConfig {
|
||||
chatConfig: MeetChatConfig;
|
||||
recordingConfig: MeetRecordingConfig;
|
||||
virtualBackgroundConfig: MeetVirtualBackgroundConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface representing the config for recordings in a room.
|
||||
*/
|
||||
export interface MeetRecordingConfig {
|
||||
enabled: boolean;
|
||||
allowAccessTo?: MeetRecordingAccess;
|
||||
}
|
||||
|
||||
export const enum MeetRecordingAccess {
|
||||
ADMIN = 'admin', // Only admins can access the recording
|
||||
ADMIN_MODERATOR = 'admin_moderator', // Admins and moderators can access
|
||||
ADMIN_MODERATOR_SPEAKER = 'admin_moderator_speaker' // Admins, moderators and speakers can access
|
||||
}
|
||||
|
||||
export interface MeetChatConfig {
|
||||
enabled: boolean;
|
||||
}
|
||||
|
||||
export interface MeetVirtualBackgroundConfig {
|
||||
enabled: boolean;
|
||||
}
|
||||
@ -1,30 +0,0 @@
|
||||
/**
|
||||
* Interface representing the preferences for a room.
|
||||
*/
|
||||
export interface MeetRoomPreferences {
|
||||
chatPreferences: MeetChatPreferences;
|
||||
recordingPreferences: MeetRecordingPreferences;
|
||||
virtualBackgroundPreferences: MeetVirtualBackgroundPreferences;
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface representing the preferences for recording.
|
||||
*/
|
||||
export interface MeetRecordingPreferences {
|
||||
enabled: boolean;
|
||||
allowAccessTo?: MeetRecordingAccess;
|
||||
}
|
||||
|
||||
export const enum MeetRecordingAccess {
|
||||
ADMIN = 'admin', // Only admins can access the recording
|
||||
ADMIN_MODERATOR = 'admin_moderator', // Admins and moderators can access
|
||||
ADMIN_MODERATOR_SPEAKER = 'admin_moderator_speaker' // Admins, moderators and speakers can access
|
||||
}
|
||||
|
||||
export interface MeetChatPreferences {
|
||||
enabled: boolean;
|
||||
}
|
||||
|
||||
export interface MeetVirtualBackgroundPreferences {
|
||||
enabled: boolean;
|
||||
}
|
||||
@ -1,11 +1,11 @@
|
||||
import { ParticipantPermissions, ParticipantRole } from './participant.js';
|
||||
import { MeetRoomPreferences } from './room-preferences.js';
|
||||
import { MeetRoomConfig } from './room-config.js';
|
||||
|
||||
interface BaseRoomOptions {
|
||||
roomName?: string;
|
||||
autoDeletionDate?: number;
|
||||
autoDeletionPolicy?: MeetRoomAutoDeletionPolicy;
|
||||
preferences?: MeetRoomPreferences;
|
||||
config?: MeetRoomConfig;
|
||||
// maxParticipants?: number | null;
|
||||
}
|
||||
|
||||
@ -21,7 +21,7 @@ export interface MeetRoom extends BaseRoomOptions {
|
||||
roomId: string;
|
||||
roomName: string;
|
||||
creationDate: number;
|
||||
preferences: MeetRoomPreferences;
|
||||
config: MeetRoomConfig;
|
||||
moderatorUrl: string;
|
||||
speakerUrl: string;
|
||||
status: MeetRoomStatus;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user