fix(frontend): update app to match backend API changes and restore build
Refactored frontend code to align with recent backend API updates. Adjusted endpoints, data models, and related logic to ensure successful compilation
This commit is contained in:
parent
ae4217a4d4
commit
6c3d87c8bf
@ -2,7 +2,11 @@ import { HttpErrorResponse, HttpEvent } from '@angular/common/http';
|
||||
import { Injectable, inject } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
import { Observable, catchError, from, switchMap } from 'rxjs';
|
||||
import { HttpErrorContext, HttpErrorHandler, HttpErrorNotifierService } from '../../../shared/services/http-error-notifier.service';
|
||||
import {
|
||||
HttpErrorContext,
|
||||
HttpErrorHandler,
|
||||
HttpErrorNotifierService
|
||||
} from '../../../shared/services/http-error-notifier.service';
|
||||
import { TokenStorageService } from '../../../shared/services/token-storage.service';
|
||||
import { AuthService } from '../services/auth.service';
|
||||
|
||||
|
||||
@ -13,8 +13,13 @@
|
||||
<mat-card-content>
|
||||
<form [formGroup]="loginForm" (ngSubmit)="login()" id="login-form">
|
||||
<mat-form-field class="form-input" appearance="outline">
|
||||
<mat-label>Username</mat-label>
|
||||
<input matInput formControlName="username" placeholder="Enter your username" id="username-input" />
|
||||
<mat-label>User ID</mat-label>
|
||||
<input
|
||||
matInput
|
||||
formControlName="userId"
|
||||
placeholder="Enter your user ID"
|
||||
id="userId-input"
|
||||
/>
|
||||
<mat-icon matPrefix>person</mat-icon>
|
||||
</mat-form-field>
|
||||
|
||||
|
||||
@ -12,24 +12,24 @@ import { NavigationService } from '../../../../shared/services/navigation.servic
|
||||
import { AuthService } from '../../services/auth.service';
|
||||
|
||||
@Component({
|
||||
selector: 'ov-login',
|
||||
imports: [
|
||||
MatFormFieldModule,
|
||||
ReactiveFormsModule,
|
||||
MatInputModule,
|
||||
MatButtonModule,
|
||||
FormsModule,
|
||||
MatCardModule,
|
||||
MatIconModule,
|
||||
MatTooltipModule,
|
||||
RouterModule
|
||||
],
|
||||
templateUrl: './login.component.html',
|
||||
styleUrl: './login.component.scss'
|
||||
selector: 'ov-login',
|
||||
imports: [
|
||||
MatFormFieldModule,
|
||||
ReactiveFormsModule,
|
||||
MatInputModule,
|
||||
MatButtonModule,
|
||||
FormsModule,
|
||||
MatCardModule,
|
||||
MatIconModule,
|
||||
MatTooltipModule,
|
||||
RouterModule
|
||||
],
|
||||
templateUrl: './login.component.html',
|
||||
styleUrl: './login.component.scss'
|
||||
})
|
||||
export class LoginComponent implements OnInit {
|
||||
loginForm = new FormGroup({
|
||||
username: new FormControl('', [Validators.required]),
|
||||
userId: new FormControl('', [Validators.required]),
|
||||
password: new FormControl('', [Validators.required])
|
||||
});
|
||||
|
||||
@ -54,16 +54,16 @@ export class LoginComponent implements OnInit {
|
||||
|
||||
async login() {
|
||||
this.loginErrorMessage = undefined;
|
||||
const { username, password } = this.loginForm.value;
|
||||
const { userId, password } = this.loginForm.value;
|
||||
|
||||
try {
|
||||
await this.authService.login(username!, password!);
|
||||
await this.authService.login(userId!, password!);
|
||||
await this.navigationService.redirectTo(this.redirectTo);
|
||||
} catch (error) {
|
||||
if ((error as HttpErrorResponse).status === 429) {
|
||||
this.loginErrorMessage = 'Too many login attempts. Please try again later';
|
||||
} else {
|
||||
this.loginErrorMessage = 'Invalid username or password';
|
||||
this.loginErrorMessage = 'Invalid user ID or password';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,34 +4,54 @@ import { MeetUserDTO, MeetUserRole } from '@openvidu-meet/typings';
|
||||
import { HttpService } from '../../../shared/services/http.service';
|
||||
import { NavigationService } from '../../../shared/services/navigation.service';
|
||||
import { TokenStorageService } from '../../../shared/services/token-storage.service';
|
||||
import { UserService } from '../../users/services/user.service';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class AuthService {
|
||||
protected readonly AUTH_API = `${HttpService.INTERNAL_API_PATH_PREFIX}/auth`;
|
||||
protected readonly USERS_API = `${HttpService.INTERNAL_API_PATH_PREFIX}/users`;
|
||||
|
||||
protected hasCheckAuth = false;
|
||||
protected user: MeetUserDTO | null = null;
|
||||
|
||||
constructor(
|
||||
protected httpService: HttpService,
|
||||
protected userService: UserService,
|
||||
protected tokenStorageService: TokenStorageService,
|
||||
protected navigationService: NavigationService
|
||||
) {}
|
||||
|
||||
async login(username: string, password: string) {
|
||||
/**
|
||||
* Logs in a user with the provided credentials.
|
||||
*
|
||||
* @param userId - The unique identifier of the user
|
||||
* @param password - The user's password
|
||||
* @returns A promise that resolves when the login is successful
|
||||
*/
|
||||
async login(userId: string, password: string) {
|
||||
try {
|
||||
const path = `${this.AUTH_API}/login`;
|
||||
const body = { username, password };
|
||||
const response = await this.httpService.postRequest<any>(path, body);
|
||||
const body = { userId, password };
|
||||
const response = await this.httpService.postRequest<{
|
||||
message: string;
|
||||
accessToken: string;
|
||||
refreshToken?: string;
|
||||
mustChangePassword?: boolean;
|
||||
}>(path, body);
|
||||
|
||||
// Check if we got tokens in the response (header mode)
|
||||
if (response.accessToken && response.refreshToken) {
|
||||
this.tokenStorageService.setAccessToken(response.accessToken);
|
||||
// Save tokens in localStorage
|
||||
this.tokenStorageService.setAccessToken(response.accessToken);
|
||||
if (response.refreshToken) {
|
||||
this.tokenStorageService.setRefreshToken(response.refreshToken);
|
||||
}
|
||||
|
||||
// TODO: Redirect user to profile page in order to change password on first login if required by backend
|
||||
// if (response.mustChangePassword) {
|
||||
// this.navigationService.redirectToProfilePage();
|
||||
// return;
|
||||
// }
|
||||
|
||||
await this.getAuthenticatedUser(true);
|
||||
} catch (err) {
|
||||
const error = err as HttpErrorResponse;
|
||||
@ -40,6 +60,11 @@ export class AuthService {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Refreshes the access token using the refresh token.
|
||||
*
|
||||
* @returns A promise that resolves to the response from the refresh endpoint
|
||||
*/
|
||||
async refreshToken() {
|
||||
const path = `${this.AUTH_API}/refresh`;
|
||||
const refreshToken = this.tokenStorageService.getRefreshToken();
|
||||
@ -61,6 +86,13 @@ export class AuthService {
|
||||
return response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs out the currently authenticated user and clears authentication tokens.
|
||||
* Redirects to the login page after logout, optionally with a query parameter to redirect back after login.
|
||||
*
|
||||
* @param redirectToAfterLogin - Optional path to redirect to after login
|
||||
* @returns A promise that resolves when the logout is successful
|
||||
*/
|
||||
async logout(redirectToAfterLogin?: string) {
|
||||
try {
|
||||
const path = `${this.AUTH_API}/logout`;
|
||||
@ -78,31 +110,67 @@ export class AuthService {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the user is authenticated by attempting to retrieve the authenticated user's information.
|
||||
*
|
||||
* @return A promise that resolves to true if the user is authenticated, false otherwise
|
||||
*/
|
||||
async isUserAuthenticated(): Promise<boolean> {
|
||||
await this.getAuthenticatedUser();
|
||||
return !!this.user;
|
||||
}
|
||||
|
||||
async getUsername(): Promise<string | undefined> {
|
||||
/**
|
||||
* Retrieves the authenticated user's ID.
|
||||
*
|
||||
* @return A promise that resolves to the user's ID if authenticated, undefined otherwise
|
||||
*/
|
||||
async getUserId(): Promise<string | undefined> {
|
||||
await this.getAuthenticatedUser();
|
||||
return this.user?.username;
|
||||
return this.user?.userId;
|
||||
}
|
||||
|
||||
async getUserRoles(): Promise<MeetUserRole[] | undefined> {
|
||||
/**
|
||||
* Retrieves the authenticated user's name.
|
||||
*
|
||||
* @return A promise that resolves to the user's name if authenticated, undefined otherwise
|
||||
*/
|
||||
async getUserName(): Promise<string | undefined> {
|
||||
await this.getAuthenticatedUser();
|
||||
return this.user?.roles;
|
||||
return this.user?.name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the authenticated user's role.
|
||||
*
|
||||
* @return A promise that resolves to the user's role if authenticated, undefined otherwise
|
||||
*/
|
||||
async getUserRole(): Promise<MeetUserRole | undefined> {
|
||||
await this.getAuthenticatedUser();
|
||||
return this.user?.role;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the authenticated user has an admin role.
|
||||
*
|
||||
* @return A promise that resolves to true if the user is an admin, false otherwise
|
||||
*/
|
||||
async isAdmin(): Promise<boolean> {
|
||||
const roles = await this.getUserRoles();
|
||||
return roles ? roles.includes(MeetUserRole.ADMIN) : false;
|
||||
const role = await this.getUserRole();
|
||||
return role === MeetUserRole.ADMIN;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the authenticated user's information and caches it in the service.
|
||||
* If the user information is already cached and force is not true, it returns immediately.
|
||||
* If force is true, it will attempt to fetch the user information again from the server.
|
||||
*
|
||||
* @param force - If true, forces a refresh of the user information from the server
|
||||
*/
|
||||
private async getAuthenticatedUser(force = false) {
|
||||
if (force || (!this.user && !this.hasCheckAuth)) {
|
||||
try {
|
||||
const path = `${this.USERS_API}/profile`;
|
||||
const user = await this.httpService.getRequest<MeetUserDTO>(path);
|
||||
const user = await this.userService.getMe();
|
||||
this.user = user;
|
||||
} catch (error) {
|
||||
this.user = null;
|
||||
@ -111,9 +179,4 @@ export class AuthService {
|
||||
this.hasCheckAuth = true;
|
||||
}
|
||||
}
|
||||
|
||||
async changePassword(currentPassword: string, newPassword: string): Promise<any> {
|
||||
const path = `${this.USERS_API}/change-password`;
|
||||
return this.httpService.postRequest(path, { currentPassword, newPassword });
|
||||
}
|
||||
}
|
||||
|
||||
@ -1 +1,2 @@
|
||||
export * from './console-nav/console-nav.component';
|
||||
export * from './logo-selector/logo-selector.component';
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
@use '../../../../../../src/assets/styles/design-tokens';
|
||||
@use '../../../../../../../../src/assets/styles/design-tokens';
|
||||
|
||||
// Form styling
|
||||
.form-section {
|
||||
|
||||
@ -1,3 +1,2 @@
|
||||
export * from './components';
|
||||
export * from './pages';
|
||||
|
||||
|
||||
@ -53,8 +53,4 @@ export class OverviewComponent implements OnInit {
|
||||
console.error(`Error navigating to ${section}:`, error);
|
||||
}
|
||||
}
|
||||
|
||||
async refreshData() {
|
||||
await this.loadStats();
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,4 +2,3 @@ export * from './hidden-participants-indicator/hidden-participants-indicator.com
|
||||
export * from './meeting-lobby/meeting-lobby.component';
|
||||
export * from './meeting-share-link-overlay/meeting-share-link-overlay.component';
|
||||
export * from './share-meeting-link/share-meeting-link.component';
|
||||
|
||||
|
||||
@ -4,4 +4,3 @@ export * from './models';
|
||||
export * from './pages';
|
||||
export * from './providers';
|
||||
export * from './services';
|
||||
|
||||
|
||||
@ -58,5 +58,5 @@ const extractParticipantRole = (metadata: any): MeetRoomMemberRole => {
|
||||
if (!parsedMetadata || typeof parsedMetadata !== 'object') {
|
||||
return MeetRoomMemberRole.SPEAKER;
|
||||
}
|
||||
return parsedMetadata.role || MeetRoomMemberRole.SPEAKER;
|
||||
return parsedMetadata.baseRole || MeetRoomMemberRole.SPEAKER;
|
||||
};
|
||||
|
||||
@ -2,4 +2,3 @@ export * from './captions.model';
|
||||
export * from './custom-participant.model';
|
||||
export * from './layout.model';
|
||||
export * from './lobby.model';
|
||||
|
||||
|
||||
@ -1,4 +1,2 @@
|
||||
export * from './end-meeting/end-meeting.component';
|
||||
export * from './meeting/meeting.component';
|
||||
|
||||
|
||||
|
||||
@ -5,4 +5,3 @@ export * from './meeting-layout.service';
|
||||
export * from './meeting-lobby.service';
|
||||
export * from './meeting-webcomponent-manager.service';
|
||||
export * from './meeting.service';
|
||||
|
||||
|
||||
@ -271,7 +271,7 @@ export class MeetingEventHandlerService {
|
||||
// Refresh participant token with new role
|
||||
await this.roomMemberService.generateToken(roomId, {
|
||||
secret,
|
||||
grantJoinMeetingPermission: true,
|
||||
joinMeeting: true,
|
||||
participantName,
|
||||
participantIdentity
|
||||
});
|
||||
|
||||
@ -330,7 +330,7 @@ export class MeetingLobbyService {
|
||||
protected async initializeParticipantName(): Promise<void> {
|
||||
// Apply participant name from RoomMemberService if set, otherwise use authenticated username
|
||||
const currentParticipantName = this.roomMemberService.getParticipantName();
|
||||
const username = await this.authService.getUsername();
|
||||
const username = await this.authService.getUserName();
|
||||
const participantName = currentParticipantName || username;
|
||||
|
||||
if (participantName) {
|
||||
@ -351,7 +351,7 @@ export class MeetingLobbyService {
|
||||
roomId!,
|
||||
{
|
||||
secret: roomSecret!,
|
||||
grantJoinMeetingPermission: true,
|
||||
joinMeeting: true,
|
||||
participantName: this.participantName()
|
||||
},
|
||||
this.e2eeKeyValue()
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
export * from './recording-lists/recording-lists.component';
|
||||
export * from './recording-share-dialog/recording-share-dialog.component';
|
||||
export * from './recording-video-player/recording-video-player.component';
|
||||
|
||||
|
||||
@ -3,4 +3,3 @@ export * from './guards';
|
||||
export * from './models';
|
||||
export * from './pages';
|
||||
export * from './services';
|
||||
|
||||
|
||||
@ -76,33 +76,18 @@ export class RecordingService {
|
||||
let path = this.RECORDINGS_API;
|
||||
|
||||
if (filters) {
|
||||
const params = new URLSearchParams();
|
||||
if (filters.roomId) {
|
||||
params.append('roomId', filters.roomId);
|
||||
}
|
||||
if (filters.roomName) {
|
||||
params.append('roomName', filters.roomName);
|
||||
}
|
||||
if (filters.status) {
|
||||
params.append('status', filters.status);
|
||||
}
|
||||
if (filters.fields) {
|
||||
params.append('fields', filters.fields);
|
||||
}
|
||||
if (filters.maxItems) {
|
||||
params.append('maxItems', filters.maxItems.toString());
|
||||
}
|
||||
if (filters.nextPageToken) {
|
||||
params.append('nextPageToken', filters.nextPageToken);
|
||||
}
|
||||
if (filters.sortField) {
|
||||
params.append('sortField', filters.sortField);
|
||||
}
|
||||
if (filters.sortOrder) {
|
||||
params.append('sortOrder', filters.sortOrder);
|
||||
}
|
||||
const queryParams = new URLSearchParams();
|
||||
|
||||
path += `?${params.toString()}`;
|
||||
Object.entries(filters).forEach(([key, value]) => {
|
||||
if (value) {
|
||||
queryParams.set(key, value.toString());
|
||||
}
|
||||
});
|
||||
|
||||
const queryString = queryParams.toString();
|
||||
if (queryString) {
|
||||
path += `?${queryString}`;
|
||||
}
|
||||
}
|
||||
|
||||
return this.httpService.getRequest(path);
|
||||
|
||||
@ -2,4 +2,3 @@ export * from './delete-room-dialog/delete-room-dialog.component';
|
||||
export * from './rooms-lists/rooms-lists.component';
|
||||
export * from './step-indicator/step-indicator.component';
|
||||
export * from './wizard-nav/wizard-nav.component';
|
||||
|
||||
|
||||
@ -51,7 +51,7 @@ const validateRoomAccessInternal = async (pageUrl: string, validateRecordingPerm
|
||||
try {
|
||||
await roomMemberService.generateToken(roomId, {
|
||||
secret,
|
||||
grantJoinMeetingPermission: false
|
||||
joinMeeting: false
|
||||
});
|
||||
|
||||
// Perform recording validation if requested
|
||||
@ -81,4 +81,3 @@ const validateRoomAccessInternal = async (pageUrl: string, validateRecordingPerm
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -5,4 +5,3 @@ export * from './models';
|
||||
export * from './pages';
|
||||
export * from './providers';
|
||||
export * from './services';
|
||||
|
||||
|
||||
@ -1,7 +1,11 @@
|
||||
import { HttpErrorResponse, HttpEvent } from '@angular/common/http';
|
||||
import { Injectable, inject } from '@angular/core';
|
||||
import { Observable, catchError, from, switchMap, throwError } from 'rxjs';
|
||||
import { HttpErrorContext, HttpErrorHandler, HttpErrorNotifierService } from '../../../shared/services/http-error-notifier.service';
|
||||
import {
|
||||
HttpErrorContext,
|
||||
HttpErrorHandler,
|
||||
HttpErrorNotifierService
|
||||
} from '../../../shared/services/http-error-notifier.service';
|
||||
import { TokenStorageService } from '../../../shared/services/token-storage.service';
|
||||
import { MeetingContextService } from '../../meeting/services/meeting-context.service';
|
||||
import { RoomMemberService } from '../services/room-member.service';
|
||||
@ -75,12 +79,12 @@ export class RoomMemberInterceptorErrorHandlerService implements HttpErrorHandle
|
||||
|
||||
const participantName = this.roomMemberService.getParticipantName();
|
||||
const participantIdentity = this.roomMemberService.getParticipantIdentity();
|
||||
const grantJoinMeetingPermission = !!participantIdentity; // Grant join permission if identity is set
|
||||
const joinMeeting = !!participantIdentity; // Grant join permission if identity is set
|
||||
|
||||
return from(
|
||||
this.roomMemberService.generateToken(roomId, {
|
||||
secret,
|
||||
grantJoinMeetingPermission,
|
||||
joinMeeting,
|
||||
participantName,
|
||||
participantIdentity
|
||||
})
|
||||
|
||||
@ -15,6 +15,7 @@ import { getValidDecodedToken } from '../../../shared/utils/token.utils';
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class RoomMemberService {
|
||||
protected readonly ROOM_MEMBERS_API = `${HttpService.INTERNAL_API_PATH_PREFIX}/rooms`;
|
||||
protected readonly PARTICIPANT_NAME_KEY = 'ovMeet-participantName';
|
||||
|
||||
protected participantName?: string;
|
||||
@ -34,6 +35,10 @@ export class RoomMemberService {
|
||||
this.log = this.loggerService.get('OpenVidu Meet - ParticipantTokenService');
|
||||
}
|
||||
|
||||
protected getRoomMemberApiPath(roomId: string): string {
|
||||
return `${this.ROOM_MEMBERS_API}/${roomId}/members`;
|
||||
}
|
||||
|
||||
setParticipantName(participantName: string): void {
|
||||
this.participantName = participantName;
|
||||
localStorage.setItem(this.PARTICIPANT_NAME_KEY, participantName);
|
||||
@ -65,7 +70,7 @@ export class RoomMemberService {
|
||||
tokenOptions.participantName = encryptedName;
|
||||
}
|
||||
|
||||
const path = `${HttpService.INTERNAL_API_PATH_PREFIX}/rooms/${roomId}/token`;
|
||||
const path = `${this.getRoomMemberApiPath(roomId)}/token`;
|
||||
const { token } = await this.httpService.postRequest<{ token: string }>(path, tokenOptions);
|
||||
|
||||
this.tokenStorageService.setRoomMemberToken(token);
|
||||
@ -90,11 +95,8 @@ export class RoomMemberService {
|
||||
this.participantIdentity = decodedToken.sub;
|
||||
}
|
||||
|
||||
this.role = metadata.role;
|
||||
this.permissions = {
|
||||
livekit: decodedToken.video,
|
||||
meet: metadata.permissions
|
||||
};
|
||||
this.role = metadata.baseRole;
|
||||
this.permissions = metadata.effectivePermissions;
|
||||
|
||||
// Update feature configuration
|
||||
this.featureConfService.setRoomMemberRole(this.role);
|
||||
@ -105,17 +107,8 @@ export class RoomMemberService {
|
||||
}
|
||||
}
|
||||
|
||||
setRoomMemberRole(role: MeetRoomMemberRole): void {
|
||||
this.role = role;
|
||||
this.featureConfService.setRoomMemberRole(this.role);
|
||||
}
|
||||
|
||||
getRoomMemberRole(): MeetRoomMemberRole {
|
||||
return this.role;
|
||||
}
|
||||
|
||||
isModerator(): boolean {
|
||||
return this.getRoomMemberRole() === MeetRoomMemberRole.MODERATOR;
|
||||
return this.role === MeetRoomMemberRole.MODERATOR;
|
||||
}
|
||||
|
||||
getRoomMemberPermissions(): MeetRoomMemberPermissions | undefined {
|
||||
@ -123,10 +116,10 @@ export class RoomMemberService {
|
||||
}
|
||||
|
||||
canRetrieveRecordings(): boolean {
|
||||
return this.permissions?.meet.canRetrieveRecordings ?? false;
|
||||
return this.permissions?.canRetrieveRecordings ?? false;
|
||||
}
|
||||
|
||||
canDeleteRecordings(): boolean {
|
||||
return this.permissions?.meet.canDeleteRecordings ?? false;
|
||||
return this.permissions?.canDeleteRecordings ?? false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,40 +1,33 @@
|
||||
import { inject, Injectable } from '@angular/core';
|
||||
import {
|
||||
MeetRoom,
|
||||
MeetRoomAnonymousConfig,
|
||||
MeetRoomConfig,
|
||||
MeetRoomDeletionPolicyWithMeeting,
|
||||
MeetRoomDeletionPolicyWithRecordings,
|
||||
MeetRoomDeletionSuccessCode,
|
||||
MeetRoomFilters,
|
||||
MeetRoomMemberRoleAndPermissions,
|
||||
MeetRoomOptions,
|
||||
MeetRoomRolesConfig,
|
||||
MeetRoomStatus
|
||||
} from '@openvidu-meet/typings';
|
||||
import { ILogger, LoggerService } from 'openvidu-components-angular';
|
||||
import { FeatureConfigurationService } from '../../../shared/services/feature-configuration.service';
|
||||
import { HttpService } from '../../../shared/services/http.service';
|
||||
|
||||
/**
|
||||
* RoomService - Persistence Layer for Room Data
|
||||
*
|
||||
* This service acts as a PERSISTENCE LAYER for room-related data and CRUD operations.
|
||||
*
|
||||
* Responsibilities:
|
||||
* - Persist room data (roomId, roomSecret) in SessionStorage for page refresh/reload
|
||||
* - Automatically sync persisted data to MeetingContextService (Single Source of Truth)
|
||||
* - Provide HTTP API methods for room CRUD operations
|
||||
* - Load and update room configuration
|
||||
*/
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class RoomService {
|
||||
protected readonly ROOMS_API = `${HttpService.API_PATH_PREFIX}/rooms`;
|
||||
protected readonly INTERNAL_ROOMS_API = `${HttpService.INTERNAL_API_PATH_PREFIX}/rooms`;
|
||||
|
||||
protected httpService: HttpService = inject(HttpService);
|
||||
protected loggerService: LoggerService = inject(LoggerService);
|
||||
protected featureConfService: FeatureConfigurationService = inject(FeatureConfigurationService);
|
||||
|
||||
protected log: ILogger = this.loggerService.get('OpenVidu Meet - RoomService');
|
||||
|
||||
constructor() {}
|
||||
|
||||
/**
|
||||
@ -48,9 +41,9 @@ export class RoomService {
|
||||
}
|
||||
|
||||
/**
|
||||
* Lists rooms with optional filters for pagination and fields.
|
||||
* Lists rooms with optional filters.
|
||||
*
|
||||
* @param filters - Optional filters for pagination and fields
|
||||
* @param filters - Optional filters
|
||||
* @return A promise that resolves to an object containing rooms and pagination info
|
||||
*/
|
||||
async listRooms(filters?: MeetRoomFilters): Promise<{
|
||||
@ -65,29 +58,17 @@ export class RoomService {
|
||||
|
||||
if (filters) {
|
||||
const queryParams = new URLSearchParams();
|
||||
if (filters.roomName) {
|
||||
queryParams.set('roomName', filters.roomName);
|
||||
}
|
||||
if (filters.status) {
|
||||
queryParams.set('status', filters.status);
|
||||
}
|
||||
if (filters.fields) {
|
||||
queryParams.set('fields', filters.fields);
|
||||
}
|
||||
if (filters.maxItems) {
|
||||
queryParams.set('maxItems', filters.maxItems.toString());
|
||||
}
|
||||
if (filters.nextPageToken) {
|
||||
queryParams.set('nextPageToken', filters.nextPageToken);
|
||||
}
|
||||
if (filters.sortField) {
|
||||
queryParams.set('sortField', filters.sortField);
|
||||
}
|
||||
if (filters.sortOrder) {
|
||||
queryParams.set('sortOrder', filters.sortOrder);
|
||||
}
|
||||
|
||||
path += `?${queryParams.toString()}`;
|
||||
Object.entries(filters).forEach(([key, value]) => {
|
||||
if (value) {
|
||||
queryParams.set(key, value.toString());
|
||||
}
|
||||
});
|
||||
|
||||
const queryString = queryParams.toString();
|
||||
if (queryString) {
|
||||
path += `?${queryString}`;
|
||||
}
|
||||
}
|
||||
|
||||
return this.httpService.getRequest(path);
|
||||
@ -104,6 +85,48 @@ export class RoomService {
|
||||
return this.httpService.getRequest(path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the config for a specific room.
|
||||
*
|
||||
* @param roomId - The unique identifier of the room
|
||||
* @return A promise that resolves to the MeetRoomConfig object
|
||||
*/
|
||||
async getRoomConfig(roomId: string): Promise<MeetRoomConfig> {
|
||||
const path = `${this.ROOMS_API}/${roomId}/config`;
|
||||
return this.httpService.getRequest<MeetRoomConfig>(path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the room config and updates the feature configuration service.
|
||||
*
|
||||
* @param roomId - The unique identifier of the room
|
||||
*/
|
||||
async loadRoomConfig(roomId: string): Promise<void> {
|
||||
this.log.d('Fetching room config for roomId:', roomId);
|
||||
|
||||
try {
|
||||
const config = await this.getRoomConfig(roomId);
|
||||
this.featureConfService.setRoomConfig(config);
|
||||
this.log.d('Room config loaded:', config);
|
||||
} catch (error) {
|
||||
this.log.e('Error loading room config', error);
|
||||
throw new Error('Failed to load room config');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves new room config.
|
||||
*
|
||||
* @param roomId - The unique identifier of the room
|
||||
* @param config - The room config to be saved.
|
||||
* @returns A promise that resolves when the config have been saved.
|
||||
*/
|
||||
async updateRoomConfig(roomId: string, config: Partial<MeetRoomConfig>): Promise<void> {
|
||||
this.log.d('Saving room config', config);
|
||||
const path = `${this.ROOMS_API}/${roomId}/config`;
|
||||
await this.httpService.putRequest(path, { config });
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the status of a room.
|
||||
*
|
||||
@ -116,6 +139,30 @@ export class RoomService {
|
||||
return this.httpService.putRequest(path, { status });
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the roles permissions of a room.
|
||||
*
|
||||
* @param roomId - The unique identifier of the room
|
||||
* @param rolesConfig - The new roles configuration to be set
|
||||
* @returns A promise that resolves when the roles configuration has been updated
|
||||
*/
|
||||
async updateRoomRoles(roomId: string, rolesConfig: MeetRoomRolesConfig): Promise<void> {
|
||||
const path = `${this.ROOMS_API}/${roomId}/roles`;
|
||||
return this.httpService.putRequest(path, { roles: rolesConfig });
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the anonymous access configuration of a room.
|
||||
*
|
||||
* @param roomId - The unique identifier of the room
|
||||
* @param anonymousConfig - The new anonymous access configuration to be set
|
||||
* @returns A promise that resolves when the anonymous access configuration has been updated
|
||||
*/
|
||||
async updateRoomAnonymous(roomId: string, anonymousConfig: MeetRoomAnonymousConfig): Promise<void> {
|
||||
const path = `${this.ROOMS_API}/${roomId}/anonymous`;
|
||||
return this.httpService.putRequest(path, { anonymous: anonymousConfig });
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a room by its ID.
|
||||
*
|
||||
@ -165,64 +212,4 @@ export class RoomService {
|
||||
const path = `${this.ROOMS_API}?${queryParams.toString()}`;
|
||||
return this.httpService.deleteRequest(path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the config for a specific room.
|
||||
*
|
||||
* @param roomId - The unique identifier of the room
|
||||
* @return A promise that resolves to the MeetRoomConfig object
|
||||
*/
|
||||
async getRoomConfig(roomId: string): Promise<MeetRoomConfig> {
|
||||
this.log.d('Fetching room config for roomId:', roomId);
|
||||
|
||||
try {
|
||||
const path = `${this.ROOMS_API}/${roomId}/config`;
|
||||
const config = await this.httpService.getRequest<MeetRoomConfig>(path);
|
||||
return config;
|
||||
} catch (error) {
|
||||
this.log.e('Error fetching room config', error);
|
||||
throw new Error(`Failed to fetch room config for roomId: ${roomId}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the room config and updates the feature configuration service.
|
||||
*
|
||||
* @param roomId - The unique identifier of the room
|
||||
*/
|
||||
async loadRoomConfig(roomId: string): Promise<void> {
|
||||
try {
|
||||
const config = await this.getRoomConfig(roomId);
|
||||
this.featureConfService.setRoomConfig(config);
|
||||
this.log.d('Room config loaded:', config);
|
||||
} catch (error) {
|
||||
this.log.e('Error loading room config', error);
|
||||
throw new Error('Failed to load room config');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves new room config.
|
||||
*
|
||||
* @param roomId - The unique identifier of the room
|
||||
* @param config - The room config to be saved.
|
||||
* @returns A promise that resolves when the config have been saved.
|
||||
*/
|
||||
async updateRoomConfig(roomId: string, config: Partial<MeetRoomConfig>): Promise<void> {
|
||||
this.log.d('Saving room config', config);
|
||||
const path = `${this.ROOMS_API}/${roomId}/config`;
|
||||
await this.httpService.putRequest(path, { config });
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the role and permissions for a specified room and secret.
|
||||
*
|
||||
* @param roomId - The unique identifier of the room
|
||||
* @param secret - The secret parameter for the room
|
||||
* @returns A promise that resolves to an object containing the role and permissions
|
||||
*/
|
||||
async getRoomMemberRoleAndPermissions(roomId: string, secret: string): Promise<MeetRoomMemberRoleAndPermissions> {
|
||||
const path = `${this.INTERNAL_ROOMS_API}/${roomId}/roles/${secret}`;
|
||||
return this.httpService.getRequest(path);
|
||||
}
|
||||
}
|
||||
|
||||
@ -181,10 +181,10 @@ export class FeatureConfigurationService {
|
||||
* DISABLED_WITH_WARNING: room config enabled BUT global config disabled
|
||||
*/
|
||||
protected computeCaptionsStatus(
|
||||
roomCaptionsConfig: MeetRoomCaptionsConfig | undefined,
|
||||
roomCaptionsConfig: MeetRoomCaptionsConfig,
|
||||
globalEnabled: boolean
|
||||
): CaptionsStatus {
|
||||
if (!roomCaptionsConfig?.enabled) {
|
||||
if (!roomCaptionsConfig.enabled) {
|
||||
return 'HIDDEN';
|
||||
}
|
||||
return globalEnabled ? 'ENABLED' : 'DISABLED_WITH_WARNING';
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { inject, Injectable } from '@angular/core';
|
||||
import { AuthMode, MeetAppearanceConfig, SecurityConfig, WebhookConfig } from '@openvidu-meet/typings';
|
||||
import { MeetAppearanceConfig, SecurityConfig, WebhookConfig } from '@openvidu-meet/typings';
|
||||
import { ILogger, LoggerService } from 'openvidu-components-angular';
|
||||
import { FeatureConfigurationService } from './feature-configuration.service';
|
||||
import { HttpService } from './http.service';
|
||||
@ -9,37 +9,23 @@ import { HttpService } from './http.service';
|
||||
})
|
||||
export class GlobalConfigService {
|
||||
protected readonly GLOBAL_CONFIG_API = `${HttpService.INTERNAL_API_PATH_PREFIX}/config`;
|
||||
protected securityConfig?: SecurityConfig;
|
||||
|
||||
protected loggerService: LoggerService = inject(LoggerService);
|
||||
protected httpService: HttpService = inject(HttpService);
|
||||
protected featureConfService: FeatureConfigurationService = inject(FeatureConfigurationService);
|
||||
|
||||
protected log: ILogger = this.loggerService.get('OpenVidu Meet - GlobalConfigService');
|
||||
|
||||
constructor() {}
|
||||
|
||||
async getSecurityConfig(forceRefresh = false): Promise<SecurityConfig> {
|
||||
if (this.securityConfig && !forceRefresh) {
|
||||
return this.securityConfig;
|
||||
}
|
||||
|
||||
try {
|
||||
const path = `${this.GLOBAL_CONFIG_API}/security`;
|
||||
this.securityConfig = await this.httpService.getRequest<SecurityConfig>(path);
|
||||
return this.securityConfig;
|
||||
} catch (error) {
|
||||
this.log.e('Error fetching security config:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
async getAuthModeToAccessRoom(): Promise<AuthMode> {
|
||||
await this.getSecurityConfig();
|
||||
return this.securityConfig!.authentication.authModeToAccessRoom;
|
||||
async getSecurityConfig(): Promise<SecurityConfig> {
|
||||
const path = `${this.GLOBAL_CONFIG_API}/security`;
|
||||
return await this.httpService.getRequest<SecurityConfig>(path);
|
||||
}
|
||||
|
||||
async saveSecurityConfig(config: SecurityConfig) {
|
||||
const path = `${this.GLOBAL_CONFIG_API}/security`;
|
||||
await this.httpService.putRequest(path, config);
|
||||
this.securityConfig = config;
|
||||
}
|
||||
|
||||
async getWebhookConfig(): Promise<WebhookConfig> {
|
||||
|
||||
@ -5,6 +5,7 @@ export const setsAreEqual = <T>(setA: Set<T>, setB: Set<T>): boolean => {
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
export const arraysAreEqual = <T>(arrayA: T[], arrayB: T[]): boolean => {
|
||||
if (arrayA.length !== arrayB.length) return false;
|
||||
for (let i = 0; i < arrayA.length; i++) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user