backend: enhance appearance configuration handling and validation in global settings
This commit is contained in:
parent
8f6af28bc2
commit
3d8a82a18d
@ -1,11 +1,7 @@
|
|||||||
import { MeetAppearanceConfig } from '@typings-ce';
|
import { MeetAppearanceConfig } from '@typings-ce';
|
||||||
import { Request, Response } from 'express';
|
import { Request, Response } from 'express';
|
||||||
import { container } from '../../config/index.js';
|
import { container } from '../../config/index.js';
|
||||||
import {
|
import { handleError } from '../../models/error.model.js';
|
||||||
errorRoomsAppearanceConfigNotDefined,
|
|
||||||
handleError,
|
|
||||||
rejectRequestFromMeetError
|
|
||||||
} from '../../models/error.model.js';
|
|
||||||
import { LoggerService, MeetStorageService } from '../../services/index.js';
|
import { LoggerService, MeetStorageService } from '../../services/index.js';
|
||||||
|
|
||||||
export const updateRoomsAppearanceConfig = async (req: Request, res: Response) => {
|
export const updateRoomsAppearanceConfig = async (req: Request, res: Response) => {
|
||||||
@ -17,6 +13,18 @@ export const updateRoomsAppearanceConfig = async (req: Request, res: Response) =
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const globalConfig = await storageService.getGlobalConfig();
|
const globalConfig = await storageService.getGlobalConfig();
|
||||||
|
|
||||||
|
if (globalConfig.roomsConfig.appearance.themes.length > 0) {
|
||||||
|
// Preserve existing theme colors if they are not provided in the update
|
||||||
|
const existingTheme = globalConfig.roomsConfig.appearance.themes[0];
|
||||||
|
const newTheme = appearanceConfig.appearance.themes[0];
|
||||||
|
|
||||||
|
newTheme.backgroundColor = newTheme.backgroundColor || existingTheme.backgroundColor;
|
||||||
|
newTheme.primaryColor = newTheme.primaryColor || existingTheme.primaryColor;
|
||||||
|
newTheme.secondaryColor = newTheme.secondaryColor || existingTheme.secondaryColor;
|
||||||
|
newTheme.surfaceColor = newTheme.surfaceColor || existingTheme.surfaceColor;
|
||||||
|
}
|
||||||
|
|
||||||
globalConfig.roomsConfig = appearanceConfig;
|
globalConfig.roomsConfig = appearanceConfig;
|
||||||
await storageService.saveGlobalConfig(globalConfig);
|
await storageService.saveGlobalConfig(globalConfig);
|
||||||
|
|
||||||
@ -34,13 +42,7 @@ export const getRoomsAppearanceConfig = async (_req: Request, res: Response) =>
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const globalConfig = await storageService.getGlobalConfig();
|
const globalConfig = await storageService.getGlobalConfig();
|
||||||
const appearanceConfig = globalConfig.roomsConfig?.appearance;
|
const appearanceConfig = globalConfig.roomsConfig.appearance;
|
||||||
|
|
||||||
if (!appearanceConfig) {
|
|
||||||
const error = errorRoomsAppearanceConfigNotDefined();
|
|
||||||
return rejectRequestFromMeetError(res, error);
|
|
||||||
}
|
|
||||||
|
|
||||||
return res.status(200).json({ appearance: appearanceConfig });
|
return res.status(200).json({ appearance: appearanceConfig });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
handleError(res, error, 'getting rooms appearance config');
|
handleError(res, error, 'getting rooms appearance config');
|
||||||
|
|||||||
@ -95,8 +95,12 @@ const ThemeModeSchema: z.ZodType<MeetRoomThemeMode> = z.enum([MeetRoomThemeMode.
|
|||||||
const hexColorSchema = z.string().regex(/^#([0-9A-Fa-f]{6}|[0-9A-Fa-f]{3})$/, 'Must be a valid hex color code');
|
const hexColorSchema = z.string().regex(/^#([0-9A-Fa-f]{6}|[0-9A-Fa-f]{3})$/, 'Must be a valid hex color code');
|
||||||
|
|
||||||
const RoomThemeSchema = z.object({
|
const RoomThemeSchema = z.object({
|
||||||
|
name: z
|
||||||
|
.string()
|
||||||
|
.min(1, 'Theme name cannot be empty')
|
||||||
|
.max(50, 'Theme name cannot exceed 50 characters')
|
||||||
|
.regex(/^[a-z0-9_-]+$/, 'Theme name can only contain lowercase letters, numbers, hyphens and underscores'),
|
||||||
enabled: z.boolean(),
|
enabled: z.boolean(),
|
||||||
name: z.string().min(1, 'Theme name cannot be empty').max(50, 'Theme name cannot exceed 50 characters'),
|
|
||||||
baseTheme: ThemeModeSchema,
|
baseTheme: ThemeModeSchema,
|
||||||
backgroundColor: hexColorSchema.optional(),
|
backgroundColor: hexColorSchema.optional(),
|
||||||
primaryColor: hexColorSchema.optional(),
|
primaryColor: hexColorSchema.optional(),
|
||||||
|
|||||||
@ -247,12 +247,6 @@ export const errorParticipantIdentityNotProvided = (): OpenViduMeetError => {
|
|||||||
return new OpenViduMeetError('Participant Error', 'No participant identity provided', 400);
|
return new OpenViduMeetError('Participant Error', 'No participant identity provided', 400);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Global config errors
|
|
||||||
|
|
||||||
export const errorRoomsAppearanceConfigNotDefined = (): OpenViduMeetError => {
|
|
||||||
return new OpenViduMeetError('Global Config Error', 'Rooms appearance config not defined', 404);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Webhook errors
|
// Webhook errors
|
||||||
|
|
||||||
export const errorInvalidWebhookUrl = (url: string, reason: string): OpenViduMeetError => {
|
export const errorInvalidWebhookUrl = (url: string, reason: string): OpenViduMeetError => {
|
||||||
|
|||||||
@ -11,7 +11,7 @@ export class GCSStorageProvider implements StorageProvider {
|
|||||||
constructor(
|
constructor(
|
||||||
@inject(LoggerService) protected logger: LoggerService,
|
@inject(LoggerService) protected logger: LoggerService,
|
||||||
@inject(GCSService) protected gcsService: GCSService
|
@inject(GCSService) protected gcsService: GCSService
|
||||||
) { }
|
) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves an object from GCS Storage as a JSON object.
|
* Retrieves an object from GCS Storage as a JSON object.
|
||||||
|
|||||||
@ -163,6 +163,7 @@ export class GCSService {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const [nextFiles] = await bucketObj.getFiles(nextOptions);
|
const [nextFiles] = await bucketObj.getFiles(nextOptions);
|
||||||
|
|
||||||
if (nextFiles.length === 0) {
|
if (nextFiles.length === 0) {
|
||||||
NextContinuationToken = undefined;
|
NextContinuationToken = undefined;
|
||||||
isTruncated = false;
|
isTruncated = false;
|
||||||
|
|||||||
@ -711,10 +711,10 @@ export class MeetStorageService<
|
|||||||
* @returns {GConfig}
|
* @returns {GConfig}
|
||||||
*/
|
*/
|
||||||
protected getDefaultConfig(): GConfig {
|
protected getDefaultConfig(): GConfig {
|
||||||
return {
|
const defaultConfig: GlobalConfig = {
|
||||||
projectId: MEET_NAME_ID,
|
projectId: MEET_NAME_ID,
|
||||||
webhooksConfig: {
|
webhooksConfig: {
|
||||||
enabled: MEET_INITIAL_WEBHOOK_ENABLED === 'true' && MEET_INITIAL_API_KEY,
|
enabled: MEET_INITIAL_WEBHOOK_ENABLED === 'true' && !!MEET_INITIAL_API_KEY,
|
||||||
url: MEET_INITIAL_WEBHOOK_URL
|
url: MEET_INITIAL_WEBHOOK_URL
|
||||||
},
|
},
|
||||||
securityConfig: {
|
securityConfig: {
|
||||||
@ -724,8 +724,14 @@ export class MeetStorageService<
|
|||||||
},
|
},
|
||||||
authModeToAccessRoom: AuthMode.NONE
|
authModeToAccessRoom: AuthMode.NONE
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
roomsConfig: {
|
||||||
|
appearance: {
|
||||||
|
themes: []
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} as GConfig;
|
};
|
||||||
|
return defaultConfig as GConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -8,7 +8,7 @@ export interface GlobalConfig {
|
|||||||
projectId: string;
|
projectId: string;
|
||||||
securityConfig: SecurityConfig;
|
securityConfig: SecurityConfig;
|
||||||
webhooksConfig: WebhookConfig;
|
webhooksConfig: WebhookConfig;
|
||||||
roomsConfig?: {
|
roomsConfig: {
|
||||||
appearance: MeetAppearanceConfig;
|
appearance: MeetAppearanceConfig;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,49 +2,49 @@
|
|||||||
* Interface representing the config for a room.
|
* Interface representing the config for a room.
|
||||||
*/
|
*/
|
||||||
export interface MeetRoomConfig {
|
export interface MeetRoomConfig {
|
||||||
chat: MeetChatConfig;
|
chat: MeetChatConfig;
|
||||||
recording: MeetRecordingConfig;
|
recording: MeetRecordingConfig;
|
||||||
virtualBackground: MeetVirtualBackgroundConfig;
|
virtualBackground: MeetVirtualBackgroundConfig;
|
||||||
// appearance?: MeetAppearanceConfig;
|
// appearance: MeetAppearanceConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface representing the config for recordings in a room.
|
* Interface representing the config for recordings in a room.
|
||||||
*/
|
*/
|
||||||
export interface MeetRecordingConfig {
|
export interface MeetRecordingConfig {
|
||||||
enabled: boolean;
|
enabled: boolean;
|
||||||
allowAccessTo?: MeetRecordingAccess;
|
allowAccessTo?: MeetRecordingAccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const enum MeetRecordingAccess {
|
export const enum MeetRecordingAccess {
|
||||||
ADMIN = 'admin', // Only admins can access the recording
|
ADMIN = 'admin', // Only admins can access the recording
|
||||||
ADMIN_MODERATOR = 'admin_moderator', // Admins and moderators can access
|
ADMIN_MODERATOR = 'admin_moderator', // Admins and moderators can access
|
||||||
ADMIN_MODERATOR_SPEAKER = 'admin_moderator_speaker', // Admins, moderators and speakers can access
|
ADMIN_MODERATOR_SPEAKER = 'admin_moderator_speaker' // Admins, moderators and speakers can access
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MeetChatConfig {
|
export interface MeetChatConfig {
|
||||||
enabled: boolean;
|
enabled: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MeetVirtualBackgroundConfig {
|
export interface MeetVirtualBackgroundConfig {
|
||||||
enabled: boolean;
|
enabled: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MeetAppearanceConfig {
|
export interface MeetAppearanceConfig {
|
||||||
themes: MeetRoomTheme[];
|
themes: MeetRoomTheme[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MeetRoomTheme {
|
export interface MeetRoomTheme {
|
||||||
enabled: boolean;
|
name: string;
|
||||||
name: string;
|
enabled: boolean;
|
||||||
baseTheme: MeetRoomThemeMode;
|
baseTheme: MeetRoomThemeMode;
|
||||||
backgroundColor?: string;
|
backgroundColor?: string;
|
||||||
primaryColor?: string;
|
primaryColor?: string;
|
||||||
secondaryColor?: string;
|
secondaryColor?: string;
|
||||||
surfaceColor?: string;
|
surfaceColor?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const enum MeetRoomThemeMode {
|
export const enum MeetRoomThemeMode {
|
||||||
LIGHT = 'light',
|
LIGHT = 'light',
|
||||||
DARK = 'dark',
|
DARK = 'dark'
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user