frontend: enhance HTTP service methods to support custom headers for requests. Update meeting, recording and room services to utilize participant role header.

This commit is contained in:
juancarmore 2025-07-11 01:46:06 +02:00
parent 82592e1f6c
commit 6dd074df57
5 changed files with 49 additions and 21 deletions

View File

@ -1,4 +1,4 @@
import { HttpClient } from '@angular/common/http'; import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { lastValueFrom } from 'rxjs'; import { lastValueFrom } from 'rxjs';
@ -13,20 +13,27 @@ export class HttpService {
constructor(protected http: HttpClient) {} constructor(protected http: HttpClient) {}
async getRequest<T>(path: string): Promise<T> { async getRequest<T>(path: string, headers?: Record<string, string>): Promise<T> {
return lastValueFrom(this.http.get<T>(path)); const options = headers ? { headers: new HttpHeaders(headers) } : {};
return lastValueFrom(this.http.get<T>(path, options));
} }
async postRequest<T>(path: string, body: any = {}): Promise<T> { async postRequest<T>(path: string, body: any = {}, headers?: Record<string, string>): Promise<T> {
return lastValueFrom(this.http.post<T>(path, body)); const options = headers ? { headers: new HttpHeaders(headers) } : {};
return lastValueFrom(this.http.post<T>(path, body, options));
} }
async putRequest<T>(path: string, body: any = {}): Promise<T> { async putRequest<T>(path: string, body: any = {}, headers?: Record<string, string>): Promise<T> {
return lastValueFrom(this.http.put<T>(path, body)); const options = headers ? { headers: new HttpHeaders(headers) } : {};
return lastValueFrom(this.http.put<T>(path, body, options));
} }
async deleteRequest<T>(path: string): Promise<T> { async deleteRequest<T>(path: string, headers?: Record<string, string>): Promise<T> {
return lastValueFrom(this.http.delete<T>(path, { observe: 'response' })).then((response) => ({ const options = {
observe: 'response' as const,
...(headers ? { headers: new HttpHeaders(headers) } : {})
};
return lastValueFrom(this.http.delete<T>(path, options)).then((response) => ({
...(response.body as T), ...(response.body as T),
statusCode: response.status statusCode: response.status
})); }));

View File

@ -1,5 +1,5 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { HttpService } from '@lib/services'; import { HttpService, ParticipantTokenService } from '@lib/services';
import { LoggerService } from 'openvidu-components-angular'; import { LoggerService } from 'openvidu-components-angular';
@Injectable({ @Injectable({
@ -12,7 +12,8 @@ export class MeetingService {
constructor( constructor(
protected loggerService: LoggerService, protected loggerService: LoggerService,
protected httpService: HttpService protected httpService: HttpService,
protected participantService: ParticipantTokenService
) { ) {
this.log = this.loggerService.get('OpenVidu Meet - MeetingService'); this.log = this.loggerService.get('OpenVidu Meet - MeetingService');
} }
@ -25,7 +26,8 @@ export class MeetingService {
*/ */
async endMeeting(roomId: string): Promise<any> { async endMeeting(roomId: string): Promise<any> {
const path = `${this.MEETINGS_API}/${roomId}`; const path = `${this.MEETINGS_API}/${roomId}`;
return this.httpService.deleteRequest(path); const headers = this.participantService.getParticipantRoleHeader();
return this.httpService.deleteRequest(path, headers);
} }
/** /**
@ -37,7 +39,8 @@ export class MeetingService {
*/ */
async kickParticipant(roomId: string, participantId: string): Promise<void> { async kickParticipant(roomId: string, participantId: string): Promise<void> {
const path = `${this.MEETINGS_API}/${roomId}/participants/${participantId}`; const path = `${this.MEETINGS_API}/${roomId}/participants/${participantId}`;
await this.httpService.deleteRequest(path); const headers = this.participantService.getParticipantRoleHeader();
await this.httpService.deleteRequest(path, headers);
this.log.d(`Participant '${participantId}' kicked from room ${roomId}`); this.log.d(`Participant '${participantId}' kicked from room ${roomId}`);
} }
} }

View File

@ -70,12 +70,15 @@ export class ParticipantTokenService {
protected updateParticipantTokenInfo(token: string): void { protected updateParticipantTokenInfo(token: string): void {
try { try {
const decodedToken = getValidDecodedToken(token); const decodedToken = getValidDecodedToken(token);
const roleAndPermissions = decodedToken.metadata.roles?.find(
(r: { role: ParticipantRole; permissions: ParticipantPermissions }) => r.role === this.participantRole
);
this.currentTokenInfo = { this.currentTokenInfo = {
token: token, token: token,
role: decodedToken.metadata.role, role: roleAndPermissions.role,
permissions: { permissions: {
livekit: decodedToken.video, livekit: decodedToken.video,
openvidu: decodedToken.metadata.permissions openvidu: roleAndPermissions.permissions
} }
}; };
this.participantRole = this.currentTokenInfo.role; this.participantRole = this.currentTokenInfo.role;
@ -108,4 +111,8 @@ export class ParticipantTokenService {
getParticipantPermissions(): ParticipantPermissions | undefined { getParticipantPermissions(): ParticipantPermissions | undefined {
return this.currentTokenInfo?.permissions; return this.currentTokenInfo?.permissions;
} }
getParticipantRoleHeader(): Record<string, string> {
return { 'x-participant-role': this.getParticipantRole() };
}
} }

View File

@ -1,7 +1,7 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { MatDialog } from '@angular/material/dialog'; import { MatDialog } from '@angular/material/dialog';
import { ShareRecordingDialogComponent } from '@lib/components'; import { ShareRecordingDialogComponent } from '@lib/components';
import { HttpService } from '@lib/services'; import { HttpService, ParticipantTokenService } from '@lib/services';
import { MeetRecordingFilters, MeetRecordingInfo, RecordingPermissions } from '@lib/typings/ce'; import { MeetRecordingFilters, MeetRecordingInfo, RecordingPermissions } from '@lib/typings/ce';
import { getValidDecodedToken } from '@lib/utils'; import { getValidDecodedToken } from '@lib/utils';
import { ActionService, LoggerService } from 'openvidu-components-angular'; import { ActionService, LoggerService } from 'openvidu-components-angular';
@ -23,6 +23,7 @@ export class RecordingManagerService {
constructor( constructor(
protected loggerService: LoggerService, protected loggerService: LoggerService,
private httpService: HttpService, private httpService: HttpService,
protected participantService: ParticipantTokenService,
private actionService: ActionService, private actionService: ActionService,
protected dialog: MatDialog protected dialog: MatDialog
) { ) {
@ -37,7 +38,8 @@ export class RecordingManagerService {
*/ */
async startRecording(roomId: string): Promise<MeetRecordingInfo> { async startRecording(roomId: string): Promise<MeetRecordingInfo> {
try { try {
return this.httpService.postRequest(this.INTERNAL_RECORDINGS_API, { roomId }); const headers = this.participantService.getParticipantRoleHeader();
return this.httpService.postRequest(this.INTERNAL_RECORDINGS_API, { roomId }, headers);
} catch (error) { } catch (error) {
console.error('Error starting recording:', error); console.error('Error starting recording:', error);
throw error; throw error;
@ -57,7 +59,8 @@ export class RecordingManagerService {
try { try {
const path = `${this.INTERNAL_RECORDINGS_API}/${recordingId}/stop`; const path = `${this.INTERNAL_RECORDINGS_API}/${recordingId}/stop`;
return this.httpService.postRequest(path); const headers = this.participantService.getParticipantRoleHeader();
return this.httpService.postRequest(path, {}, headers);
} catch (error) { } catch (error) {
console.error('Error stopping recording:', error); console.error('Error stopping recording:', error);
throw error; throw error;

View File

@ -1,5 +1,10 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { FeatureConfigurationService, HttpService, SessionStorageService } from '@lib/services'; import {
FeatureConfigurationService,
HttpService,
ParticipantTokenService,
SessionStorageService
} from '@lib/services';
import { import {
MeetRoom, MeetRoom,
MeetRoomFilters, MeetRoomFilters,
@ -26,6 +31,7 @@ export class RoomService {
constructor( constructor(
protected loggerService: LoggerService, protected loggerService: LoggerService,
protected httpService: HttpService, protected httpService: HttpService,
protected participantService: ParticipantTokenService,
protected featureConfService: FeatureConfigurationService, protected featureConfService: FeatureConfigurationService,
protected sessionStorageService: SessionStorageService protected sessionStorageService: SessionStorageService
) { ) {
@ -102,7 +108,8 @@ export class RoomService {
*/ */
async getRoom(roomId: string): Promise<MeetRoom> { async getRoom(roomId: string): Promise<MeetRoom> {
let path = `${this.ROOMS_API}/${roomId}`; let path = `${this.ROOMS_API}/${roomId}`;
return this.httpService.getRequest(path); const headers = this.participantService.getParticipantRoleHeader();
return this.httpService.getRequest(path, headers);
} }
/** /**
@ -148,7 +155,8 @@ export class RoomService {
try { try {
const path = `${this.INTERNAL_ROOMS_API}/${roomId}/preferences`; const path = `${this.INTERNAL_ROOMS_API}/${roomId}/preferences`;
const preferences = await this.httpService.getRequest<MeetRoomPreferences>(path); const headers = this.participantService.getParticipantRoleHeader();
const preferences = await this.httpService.getRequest<MeetRoomPreferences>(path, headers);
if (!preferences) { if (!preferences) {
this.log.w('Room preferences not found for roomId:', roomId); this.log.w('Room preferences not found for roomId:', roomId);