diff --git a/frontend/projects/shared-meet-components/src/lib/guards/auth.guard.ts b/frontend/projects/shared-meet-components/src/lib/guards/auth.guard.ts
index 38571b4..b111022 100644
--- a/frontend/projects/shared-meet-components/src/lib/guards/auth.guard.ts
+++ b/frontend/projects/shared-meet-components/src/lib/guards/auth.guard.ts
@@ -1,12 +1,5 @@
import { inject } from '@angular/core';
-import {
- ActivatedRouteSnapshot,
- CanActivateFn,
- RedirectCommand,
- Router,
- RouterStateSnapshot,
- UrlTree
-} from '@angular/router';
+import { ActivatedRouteSnapshot, CanActivateFn, Router, RouterStateSnapshot, UrlTree } from '@angular/router';
import { AuthMode, ParticipantRole } from '@lib/typings/ce';
import { AuthService, ContextService, HttpService, SessionStorageService } from '../services';
@@ -79,12 +72,9 @@ export const checkParticipantRoleAndAuthGuard: CanActivateFn = async (
const isAuthenticated = await authService.isUserAuthenticated();
if (!isAuthenticated) {
// Redirect to the login page with query param to redirect back to the room
- const loginRoute = router.createUrlTree(['login'], {
+ return router.createUrlTree(['login'], {
queryParams: { redirectTo: state.url }
});
- return new RedirectCommand(loginRoute, {
- skipLocationChange: true
- });
}
}
diff --git a/frontend/projects/shared-meet-components/src/lib/guards/index.ts b/frontend/projects/shared-meet-components/src/lib/guards/index.ts
index c495167..7e93399 100644
--- a/frontend/projects/shared-meet-components/src/lib/guards/index.ts
+++ b/frontend/projects/shared-meet-components/src/lib/guards/index.ts
@@ -2,7 +2,5 @@ export * from './application-mode.guard';
export * from './auth.guard';
export * from './extract-query-params.guard';
export * from './moderator-secret.guard';
-export * from './participant-name.guard';
export * from './run-serially.guard';
-export * from './validate-room-access.guard';
export * from './validate-recording-access.guard';
diff --git a/frontend/projects/shared-meet-components/src/lib/guards/moderator-secret.guard.ts b/frontend/projects/shared-meet-components/src/lib/guards/moderator-secret.guard.ts
index 0301f51..67c3092 100644
--- a/frontend/projects/shared-meet-components/src/lib/guards/moderator-secret.guard.ts
+++ b/frontend/projects/shared-meet-components/src/lib/guards/moderator-secret.guard.ts
@@ -5,54 +5,6 @@ import { Router } from '@angular/router';
import { ContextService, HttpService, SessionStorageService } from '../services';
import { filter, take } from 'rxjs';
-/**
- * Guard that replaces the moderator secret in the URL with the publisher secret.
- *
- * This guard checks if the current participant is a moderator. If so, it retrieves the moderator and publisher secrets
- * for the current room and updates the session storage with the moderator secret. It then replaces the secret in the URL
- * with the publisher secret.
- *
- * @param route - The activated route snapshot.
- * @param state - The router state snapshot.
- * @returns A promise that resolves to `true` if the operation is successful, otherwise `false`.
- *
- * @throws Will log an error and return `false` if an error occurs during the process.
- */
-export const replaceModeratorSecretGuard: CanActivateFn = (route, _state) => {
- const httpService = inject(HttpService);
- const contextService = inject(ContextService);
- const router = inject(Router);
- const location: Location = inject(Location);
- const sessionStorageService = inject(SessionStorageService);
-
- try {
- router.events
- .pipe(
- filter((event) => event instanceof NavigationEnd),
- take(1)
- )
- .subscribe(async () => {
- if (contextService.isModeratorParticipant()) {
- const roomId = contextService.getRoomId();
- const { moderatorSecret, publisherSecret } = await getUrlSecret(httpService, roomId);
-
- sessionStorageService.setModeratorSecret(roomId, moderatorSecret);
- // Replace secret in URL by the publisher secret
- const queryParams = { ...route.queryParams, secret: publisherSecret };
- const urlTree = router.createUrlTree([], { queryParams, queryParamsHandling: 'merge' });
- const newUrl = router.serializeUrl(urlTree);
-
- location.replaceState(newUrl);
- }
- });
-
- return true;
- } catch (error) {
- console.error('error', error);
- return false;
- }
-};
-
/**
* Guard that intercepts navigation to remove the 'secret' query parameter from the URL
* when a moderator participant is detected. The secret is stored in session storage
diff --git a/frontend/projects/shared-meet-components/src/lib/guards/participant-name.guard.ts b/frontend/projects/shared-meet-components/src/lib/guards/participant-name.guard.ts
deleted file mode 100644
index 1ece264..0000000
--- a/frontend/projects/shared-meet-components/src/lib/guards/participant-name.guard.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-import { inject } from '@angular/core';
-import { CanActivateFn, RedirectCommand } from '@angular/router';
-import { Router } from '@angular/router';
-import { ContextService } from '../services';
-
-export const checkParticipantNameGuard: CanActivateFn = (_route, state) => {
- const router = inject(Router);
- const contextService = inject(ContextService);
- const roomId = contextService.getRoomId();
- const hasParticipantName = !!contextService.getParticipantName();
-
- // Check if participant name exists in the service
- if (!hasParticipantName) {
- // Redirect to a page where the participant can input their participant name
- const participantNameRoute = router.createUrlTree([`room/${roomId}/participant-name`], {
- queryParams: { originUrl: state.url, t: Date.now() }
- });
- return new RedirectCommand(participantNameRoute, {
- skipLocationChange: true
- });
- }
-
- // Proceed if the name exists
- return true;
-};
diff --git a/frontend/projects/shared-meet-components/src/lib/guards/validate-room-access.guard.ts b/frontend/projects/shared-meet-components/src/lib/guards/validate-room-access.guard.ts
deleted file mode 100644
index 7a62eaf..0000000
--- a/frontend/projects/shared-meet-components/src/lib/guards/validate-room-access.guard.ts
+++ /dev/null
@@ -1,64 +0,0 @@
-import { inject } from '@angular/core';
-import {
- ActivatedRouteSnapshot,
- Router,
- RouterStateSnapshot,
- CanActivateFn,
- UrlTree,
- RedirectCommand
-} from '@angular/router';
-import { ContextService, HttpService, SessionStorageService } from '../services';
-
-/**
- * Guard to validate the access to a room.
- */
-export const validateRoomAccessGuard: CanActivateFn = async (
- _route: ActivatedRouteSnapshot,
- state: RouterStateSnapshot
-) => {
- const httpService = inject(HttpService);
- const contextService = inject(ContextService);
- const router = inject(Router);
- const sessionStorageService = inject(SessionStorageService);
-
- const roomId = contextService.getRoomId();
- const participantName = contextService.getParticipantName();
- const secret = contextService.getSecret();
- const storageSecret = sessionStorageService.getModeratorSecret(roomId);
-
- try {
- // Generate a participant token
- const response = await httpService.generateParticipantToken({
- roomId,
- participantName,
- secret: storageSecret || secret
- });
- contextService.setParticipantToken(response.token);
- return true;
- } catch (error: any) {
- console.error('Error generating participant token:', error);
- switch (error.status) {
- case 400:
- // Invalid secret
- return redirectToErrorPage(router, 'invalid-secret');
- case 404:
- // Room not found
- return redirectToErrorPage(router, 'invalid-room');
- case 409:
- // Participant already exists.
- // Send a timestamp to force update the query params and show the error message in participant name input form
- const participantNameRoute = router.createUrlTree([`room/${roomId}/participant-name`], {
- queryParams: { originUrl: state.url, accessError: 'participant-exists', t: Date.now() }
- });
- return new RedirectCommand(participantNameRoute, {
- skipLocationChange: true
- });
- default:
- return redirectToErrorPage(router, 'internal-error');
- }
- }
-};
-
-const redirectToErrorPage = (router: Router, reason: string): UrlTree => {
- return router.createUrlTree(['error'], { queryParams: { reason } });
-};
diff --git a/frontend/projects/shared-meet-components/src/lib/pages/index.ts b/frontend/projects/shared-meet-components/src/lib/pages/index.ts
index c88b758..9d311c0 100644
--- a/frontend/projects/shared-meet-components/src/lib/pages/index.ts
+++ b/frontend/projects/shared-meet-components/src/lib/pages/index.ts
@@ -10,6 +10,5 @@ export * from './console/security-preferences/security-preferences.component';
export * from './disconnected/disconnected.component';
export * from './error/error.component';
export * from './login/login.component';
-export * from './participant-name-form/participant-name-form.component';
export * from './room-recordings/room-recordings.component';
export * from './video-room/video-room.component';
diff --git a/frontend/projects/shared-meet-components/src/lib/pages/participant-name-form/participant-name-form.component.html b/frontend/projects/shared-meet-components/src/lib/pages/participant-name-form/participant-name-form.component.html
deleted file mode 100644
index cf977f0..0000000
--- a/frontend/projects/shared-meet-components/src/lib/pages/participant-name-form/participant-name-form.component.html
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
-
-
diff --git a/frontend/projects/shared-meet-components/src/lib/pages/participant-name-form/participant-name-form.component.scss b/frontend/projects/shared-meet-components/src/lib/pages/participant-name-form/participant-name-form.component.scss
deleted file mode 100644
index 5ce78a8..0000000
--- a/frontend/projects/shared-meet-components/src/lib/pages/participant-name-form/participant-name-form.component.scss
+++ /dev/null
@@ -1,36 +0,0 @@
-.form-container {
- display: flex;
- justify-content: center;
- align-items: center;
- height: 100vh;
- background-color: var(--ov-background-color);
-}
-
-.form-card {
- width: 400px;
- padding: 20px;
- box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
- border-radius: var(--ov-surface-radius);
- background-color: var(--ov-surface-color);
-}
-
-.form-title {
- text-align: center;
- margin-bottom: 20px;
- color: var(--ov-text-surface-color);
-}
-
-.full-width {
- width: 100%;
- margin-bottom: 20px;
-}
-
-button {
- height: 56px;
- border-radius: var(--ov-surface-radius);
-}
-
-button:not([disabled]) {
- background-color: var(--ov-accent-action-color);
- color: var(--ov-text-primary-color);
-}
diff --git a/frontend/projects/shared-meet-components/src/lib/pages/participant-name-form/participant-name-form.component.spec.ts b/frontend/projects/shared-meet-components/src/lib/pages/participant-name-form/participant-name-form.component.spec.ts
deleted file mode 100644
index 74c69a5..0000000
--- a/frontend/projects/shared-meet-components/src/lib/pages/participant-name-form/participant-name-form.component.spec.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-import { ComponentFixture, TestBed } from '@angular/core/testing';
-
-import { ParticipantNameFormComponent } from './participant-name-form.component';
-
-describe('ParticipantNameFormComponent', () => {
- let component: ParticipantNameFormComponent;
- let fixture: ComponentFixture;
-
- beforeEach(async () => {
- await TestBed.configureTestingModule({
- imports: [ParticipantNameFormComponent]
- })
- .compileComponents();
-
- fixture = TestBed.createComponent(ParticipantNameFormComponent);
- component = fixture.componentInstance;
- fixture.detectChanges();
- });
-
- it('should create', () => {
- expect(component).toBeTruthy();
- });
-});
diff --git a/frontend/projects/shared-meet-components/src/lib/pages/participant-name-form/participant-name-form.component.ts b/frontend/projects/shared-meet-components/src/lib/pages/participant-name-form/participant-name-form.component.ts
deleted file mode 100644
index a7f94f4..0000000
--- a/frontend/projects/shared-meet-components/src/lib/pages/participant-name-form/participant-name-form.component.ts
+++ /dev/null
@@ -1,74 +0,0 @@
-import { Component, OnInit } from '@angular/core';
-import { FormGroup, Validators, FormsModule, ReactiveFormsModule, FormControl } from '@angular/forms';
-import { MatButtonModule } from '@angular/material/button';
-import { MatCardModule } from '@angular/material/card';
-import { MatFormFieldModule } from '@angular/material/form-field';
-import { MatInputModule } from '@angular/material/input';
-import { ActivatedRoute, Router } from '@angular/router';
-import { AuthService } from 'shared-meet-components';
-
-@Component({
- selector: 'ov-participant-name-form',
- standalone: true,
- imports: [
- MatFormFieldModule,
- MatInputModule,
- FormsModule,
- ReactiveFormsModule,
- MatCardModule,
- MatButtonModule
- // MatIconModule
- ],
- templateUrl: './participant-name-form.component.html',
- styleUrl: './participant-name-form.component.scss'
-})
-export class ParticipantNameFormComponent implements OnInit {
- participantForm = new FormGroup({
- name: new FormControl('', [Validators.required, Validators.minLength(4)])
- });
- protected originUrl: string = '';
- protected error = '';
-
- constructor(
- protected router: Router,
- protected route: ActivatedRoute,
- protected authService: AuthService
- ) {}
-
- async ngOnInit() {
- this.route.queryParams.subscribe((params) => {
- if (params['originUrl']) {
- this.originUrl = params['originUrl'];
- this.error = params['accessError'];
- this.applyErrorToForm();
- }
- });
-
- // Set the username if authenticated as default value
- const username = await this.authService.getUsername();
- if (username) {
- this.participantForm.get('name')?.setValue(username);
- }
- }
-
- get name() {
- return this.participantForm.get('name');
- }
-
- async onSubmit() {
- if (this.participantForm.valid) {
- const participantName = this.participantForm.value.name;
-
- let urlTree = this.router.parseUrl(this.originUrl);
- urlTree.queryParams = { ...urlTree.queryParams, 'participant-name': participantName };
-
- await this.router.navigateByUrl(urlTree);
- }
- }
-
- private applyErrorToForm() {
- if (this.error === 'participant-exists') {
- this.participantForm.get('name')?.setErrors({ participantExists: true });
- }
- }
-}
diff --git a/frontend/projects/shared-meet-components/src/lib/pages/video-room/video-room.component.html b/frontend/projects/shared-meet-components/src/lib/pages/video-room/video-room.component.html
index 714c97d..46510ed 100644
--- a/frontend/projects/shared-meet-components/src/lib/pages/video-room/video-room.component.html
+++ b/frontend/projects/shared-meet-components/src/lib/pages/video-room/video-room.component.html
@@ -1,7 +1,45 @@
-@if (!serverError && !loading) {
+@if (!showRoom) {
+
+
+
+
+
+
+} @else {
}
-
-@if (!loading && serverError) {
-
- error
-
- {{ serverError }}
-
-
-}
diff --git a/frontend/projects/shared-meet-components/src/lib/pages/video-room/video-room.component.scss b/frontend/projects/shared-meet-components/src/lib/pages/video-room/video-room.component.scss
index e94ef4a..5ce78a8 100644
--- a/frontend/projects/shared-meet-components/src/lib/pages/video-room/video-room.component.scss
+++ b/frontend/projects/shared-meet-components/src/lib/pages/video-room/video-room.component.scss
@@ -1,9 +1,36 @@
-.error {
- height: 100%;
- width: 100%;
- text-align: center;
- margin-top: 20px;
- mat-icon {
- vertical-align: bottom;
- }
+.form-container {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ height: 100vh;
+ background-color: var(--ov-background-color);
+}
+
+.form-card {
+ width: 400px;
+ padding: 20px;
+ box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
+ border-radius: var(--ov-surface-radius);
+ background-color: var(--ov-surface-color);
+}
+
+.form-title {
+ text-align: center;
+ margin-bottom: 20px;
+ color: var(--ov-text-surface-color);
+}
+
+.full-width {
+ width: 100%;
+ margin-bottom: 20px;
+}
+
+button {
+ height: 56px;
+ border-radius: var(--ov-surface-radius);
+}
+
+button:not([disabled]) {
+ background-color: var(--ov-accent-action-color);
+ color: var(--ov-text-primary-color);
}
diff --git a/frontend/projects/shared-meet-components/src/lib/pages/video-room/video-room.component.ts b/frontend/projects/shared-meet-components/src/lib/pages/video-room/video-room.component.ts
index 916ab63..2f24f26 100644
--- a/frontend/projects/shared-meet-components/src/lib/pages/video-room/video-room.component.ts
+++ b/frontend/projects/shared-meet-components/src/lib/pages/video-room/video-room.component.ts
@@ -1,53 +1,74 @@
-import { ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core';
-import { Router } from '@angular/router';
-import { MatIcon } from '@angular/material/icon';
+import { Location } from '@angular/common';
+import { Component, OnDestroy, OnInit } from '@angular/core';
+import { FormControl, FormGroup, FormsModule, ReactiveFormsModule, Validators } from '@angular/forms';
+import { MatButtonModule } from '@angular/material/button';
+import { MatCardModule } from '@angular/material/card';
+import { MatFormFieldModule } from '@angular/material/form-field';
+import { MatInputModule } from '@angular/material/input';
+import { ActivatedRoute, Router } from '@angular/router';
+import { MeetRecordingAccess, MeetRoomPreferences, OpenViduMeetPermissions, ParticipantRole } from '@lib/typings/ce';
import {
- RecordingDeleteRequestedEvent,
- RecordingStartRequestedEvent,
- RecordingStopRequestedEvent,
ApiDirectiveModule,
- ParticipantLeftEvent,
- ParticipantModel,
OpenViduComponentsUiModule,
- ParticipantLeftReason
+ ParticipantLeftEvent,
+ ParticipantLeftReason,
+ ParticipantModel,
+ RecordingStartRequestedEvent,
+ RecordingStopRequestedEvent
} from 'openvidu-components-angular';
-
-import {
- MeetChatPreferences,
- MeetRecordingAccess,
- MeetRecordingPreferences,
- MeetVirtualBackgroundPreferences
-} from '@lib/typings/ce';
-
-import {
- HttpService,
- WebComponentManagerService,
- ContextService,
- RoomService,
- SessionStorageService
-} from '../../services';
-import { OutboundEventMessage } from 'webcomponent/src/models/message.type';
import { WebComponentEvent } from 'webcomponent/src/models/event.model';
+import { OutboundEventMessage } from 'webcomponent/src/models/message.type';
+import {
+ AuthService,
+ ContextService,
+ HttpService,
+ RoomService,
+ SessionStorageService,
+ WebComponentManagerService
+} from '../../services';
@Component({
selector: 'app-video-room',
templateUrl: './video-room.component.html',
styleUrls: ['./video-room.component.scss'],
standalone: true,
- imports: [OpenViduComponentsUiModule, ApiDirectiveModule, MatIcon]
+ imports: [
+ OpenViduComponentsUiModule,
+ ApiDirectiveModule,
+ MatFormFieldModule,
+ MatInputModule,
+ FormsModule,
+ ReactiveFormsModule,
+ MatCardModule,
+ MatButtonModule
+ ]
})
export class VideoRoomComponent implements OnInit, OnDestroy {
+ participantForm = new FormGroup({
+ name: new FormControl('', [Validators.required, Validators.minLength(4)])
+ });
+ showRoom = false;
+
roomId = '';
+ roomSecret = '';
participantName = '';
- token = '';
- serverError = '';
- loading = true;
- chatPreferences: MeetChatPreferences = { enabled: true };
- recordingPreferences: MeetRecordingPreferences = {
- enabled: true,
- allowAccessTo: MeetRecordingAccess.ADMIN_MODERATOR_PUBLISHER
+ participantToken = '';
+ participantRole: ParticipantRole = ParticipantRole.PUBLISHER;
+ participantPermissions: OpenViduMeetPermissions = {
+ canRecord: false,
+ canChat: false,
+ canChangeVirtualBackground: false,
+ canPublishScreen: false
+ };
+
+ roomPreferences: MeetRoomPreferences = {
+ recordingPreferences: {
+ enabled: true,
+ allowAccessTo: MeetRecordingAccess.ADMIN_MODERATOR_PUBLISHER
+ },
+ chatPreferences: { enabled: true },
+ virtualBackgroundPreferences: { enabled: true }
};
- virtualBackgroundPreferences: MeetVirtualBackgroundPreferences = { enabled: true };
featureFlags = {
videoEnabled: true,
audioEnabled: true,
@@ -63,56 +84,132 @@ export class VideoRoomComponent implements OnInit, OnDestroy {
constructor(
protected httpService: HttpService,
protected router: Router,
+ protected route: ActivatedRoute,
+ protected location: Location,
+ protected authService: AuthService,
protected ctxService: ContextService,
protected roomService: RoomService,
protected wcManagerService: WebComponentManagerService,
- protected sessionStorageService: SessionStorageService,
- protected cdr: ChangeDetectorRef
+ protected sessionStorageService: SessionStorageService
) {}
async ngOnInit() {
- try {
- this.roomId = this.ctxService.getRoomId();
- this.participantName = this.ctxService.getParticipantName();
+ this.roomId = this.ctxService.getRoomId();
+ const secret = this.ctxService.getSecret();
+ const storageSecret = this.sessionStorageService.getModeratorSecret(this.roomId);
+ this.roomSecret = storageSecret || secret;
- if (this.ctxService.isEmbeddedMode()) {
- this.featureFlags.showPrejoin = false;
- }
+ // Apply participant name from context if set, otherwise use authenticated username
+ const contextParticipantName = this.ctxService.getParticipantName();
+ const username = await this.authService.getUsername();
+ const participantName = contextParticipantName || username;
- // TODO: Apply room preferences from saved room using context service
- // await this.loadRoomPreferences();
-
- // TODO: Extract permissions from token and apply them to the component
- this.applyParticipantPermissions();
- } catch (error: any) {
- console.error('Error fetching room preferences', error);
- this.serverError = error.error.message || error.message || error.error;
+ if (participantName) {
+ this.participantForm.get('name')?.setValue(participantName);
}
- this.loading = false;
}
ngOnDestroy(): void {
- // Clean up the context service
- // this.contextService.clearContext();
this.wcManagerService.stopCommandsListener();
}
- async onTokenRequested(participantName: string) {
- try {
- if (this.ctxService.isStandaloneMode()) {
- // As token is not provided, we need to set the participant name from
- // ov-videoconference event
- this.ctxService.setParticipantName(participantName);
- }
-
- this.token = this.ctxService.getParticipantToken();
- } catch (error: any) {
- console.error(error);
- this.serverError = error.error;
+ async accessRoom() {
+ if (!this.participantForm.valid) {
+ return;
}
- this.loading = false;
- this.cdr.detectChanges();
+ this.participantName = this.participantForm.value.name!;
+
+ try {
+ await this.generateParticipantToken();
+ await this.replaceUrlQueryParams();
+ // await this.loadRoomPreferences();
+ this.applyParticipantPermissions();
+ this.showRoom = true;
+ } catch (error) {
+ console.error('Error accessing room:', error);
+ }
+ }
+
+ async onTokenRequested() {
+ // Participant token must be set only when requested
+ this.participantToken = this.ctxService.getParticipantToken();
+ }
+
+ private async generateParticipantToken() {
+ try {
+ const response = await this.httpService.generateParticipantToken({
+ roomId: this.roomId,
+ participantName: this.participantName,
+ secret: this.roomSecret
+ });
+ this.setParticipantToken(response.token);
+ } catch (error: any) {
+ console.error('Error generating participant token:', error);
+ switch (error.status) {
+ case 400:
+ // Invalid secret
+ this.redirectToErrorPage('invalid-secret');
+ break;
+ case 404:
+ // Room not found
+ this.redirectToErrorPage('invalid-room');
+ break;
+ case 409:
+ // Participant already exists.
+ // Show the error message in participant name input form
+ this.participantForm.get('name')?.setErrors({ participantExists: true });
+ throw new Error('Participant already exists in the room');
+ default:
+ this.redirectToErrorPage('internal-error');
+ }
+ }
+ }
+
+ private setParticipantToken(token: string): void {
+ try {
+ this.ctxService.setParticipantToken(token);
+ this.participantRole = this.ctxService.getParticipantRole();
+ this.participantPermissions = this.ctxService.getParticipantPermissions();
+ } catch (error: any) {
+ console.error('Error setting token in context', error);
+ }
+ }
+
+ private async replaceUrlQueryParams() {
+ let secretQueryParam = this.roomSecret;
+
+ // If participant is moderator, store the moderator secret in session storage
+ // and replace the secret in the URL with the publisher secret
+ if (this.participantRole === ParticipantRole.MODERATOR) {
+ try {
+ const { moderatorSecret, publisherSecret } = await this.getRoomSecrets();
+ this.sessionStorageService.setModeratorSecret(this.roomId, moderatorSecret);
+ secretQueryParam = publisherSecret;
+ } catch (error) {
+ console.error('error', error);
+ }
+ }
+
+ // Replace secret and participant name in the URL query parameters
+ const queryParams = {
+ ...this.route.snapshot.queryParams,
+ secret: secretQueryParam,
+ 'participant-name': this.participantName
+ };
+ const urlTree = this.router.createUrlTree([], { queryParams, queryParamsHandling: 'merge' });
+ const newUrl = this.router.serializeUrl(urlTree);
+ this.location.replaceState(newUrl);
+ }
+
+ private async getRoomSecrets(): Promise<{ moderatorSecret: string; publisherSecret: string }> {
+ const { moderatorRoomUrl, publisherRoomUrl } = await this.httpService.getRoom(this.roomId);
+
+ const publisherUrl = new URL(publisherRoomUrl);
+ const publisherSecret = publisherUrl.searchParams.get('secret') || '';
+ const moderatorUrl = new URL(moderatorRoomUrl);
+ const moderatorSecret = moderatorUrl.searchParams.get('secret') || '';
+ return { publisherSecret, moderatorSecret };
}
onParticipantConnected(event: ParticipantModel) {
@@ -158,11 +255,7 @@ export class VideoRoomComponent implements OnInit, OnDestroy {
this.sessionStorageService.removeModeratorSecret(event.roomName);
}
- //if (this.contextService.isEmbeddedMode()) this.sendMessageToParent(event);
this.redirectTo(redirectURL, isExternalURL);
-
- // Stop listening to commands from the parent
- this.wcManagerService.stopCommandsListener();
}
async onRecordingStartRequested(event: RecordingStartRequestedEvent) {
@@ -186,18 +279,6 @@ export class VideoRoomComponent implements OnInit, OnDestroy {
}
}
- async onRecordingDeleteRequested(event: RecordingDeleteRequestedEvent) {
- try {
- const { recordingId } = event;
-
- if (!recordingId) throw new Error('Recording ID not found when deleting recording');
-
- await this.httpService.deleteRecording(recordingId);
- } catch (error) {
- console.error(error);
- }
- }
-
/**
* Loads the room preferences from the global preferences service and assigns them to the component.
*
@@ -208,26 +289,26 @@ export class VideoRoomComponent implements OnInit, OnDestroy {
* @returns {Promise} A promise that resolves when the room preferences have been loaded and applied.
*/
private async loadRoomPreferences() {
- const preferences = await this.roomService.getRoomPreferences();
- // Assign the preferences to the component
- Object.assign(this, preferences);
+ try {
+ this.roomPreferences = await this.roomService.getRoomPreferences();
+ } catch (error) {
+ console.error('Error loading room preferences:', error);
+ }
- this.featureFlags.showChat = this.chatPreferences.enabled;
- this.featureFlags.showRecording = this.recordingPreferences.enabled;
- this.featureFlags.showBackgrounds = this.virtualBackgroundPreferences.enabled;
+ this.featureFlags.showChat = this.roomPreferences.chatPreferences.enabled;
+ this.featureFlags.showRecording = this.roomPreferences.recordingPreferences.enabled;
+ this.featureFlags.showBackgrounds = this.roomPreferences.virtualBackgroundPreferences.enabled;
}
/**
- * Configures the feature flags based on the token permissions.
- *
- * This method checks the token permissions and sets the feature flags accordingly.
+ * Configures the feature flags based on participant permissions.
*/
private applyParticipantPermissions() {
if (this.featureFlags.showChat) {
- this.featureFlags.showChat = this.ctxService.canChat();
+ this.featureFlags.showChat = this.participantPermissions.canChat;
}
if (this.featureFlags.showRecording) {
- this.featureFlags.showRecording = this.ctxService.canRecord();
+ this.featureFlags.showRecording = this.participantPermissions.canRecord;
}
}
@@ -240,4 +321,8 @@ export class VideoRoomComponent implements OnInit, OnDestroy {
this.router.navigate([url], { replaceUrl: true });
}
}
+
+ private redirectToErrorPage(reason: string) {
+ this.router.navigate(['error'], { queryParams: { reason } });
+ }
}
diff --git a/frontend/projects/shared-meet-components/src/lib/routes/base-routes.ts b/frontend/projects/shared-meet-components/src/lib/routes/base-routes.ts
index 6bd937c..c18e9b5 100644
--- a/frontend/projects/shared-meet-components/src/lib/routes/base-routes.ts
+++ b/frontend/projects/shared-meet-components/src/lib/routes/base-routes.ts
@@ -1,17 +1,14 @@
import { Routes } from '@angular/router';
import {
applicationModeGuard,
- checkParticipantNameGuard,
checkParticipantRoleAndAuthGuard,
checkUserAuthenticatedGuard,
checkUserNotAuthenticatedGuard,
extractRecordingQueryParamsGuard,
extractRoomQueryParamsGuard,
removeModeratorSecretGuard,
- replaceModeratorSecretGuard,
runGuardsSerially,
- validateRecordingAccessGuard,
- validateRoomAccessGuard
+ validateRecordingAccessGuard
} from '../guards';
import {
ConsoleComponent,
@@ -19,7 +16,6 @@ import {
ErrorComponent,
LoginComponent,
OverviewComponent,
- ParticipantNameFormComponent,
RecordingsComponent,
RoomFormComponent,
RoomRecordingsComponent,
@@ -83,20 +79,9 @@ export const baseRoutes: Routes = [
path: 'room/:room-id',
component: VideoRoomComponent,
canActivate: [
- runGuardsSerially(
- applicationModeGuard,
- extractRoomQueryParamsGuard,
- checkParticipantRoleAndAuthGuard,
- checkParticipantNameGuard,
- validateRoomAccessGuard,
- replaceModeratorSecretGuard
- )
+ runGuardsSerially(applicationModeGuard, extractRoomQueryParamsGuard, checkParticipantRoleAndAuthGuard)
]
},
- {
- path: 'room/:room-id/participant-name',
- component: ParticipantNameFormComponent
- },
{
path: 'room/:room-id/recordings',
component: RoomRecordingsComponent,
diff --git a/frontend/projects/shared-meet-components/src/lib/services/context/context.service.ts b/frontend/projects/shared-meet-components/src/lib/services/context/context.service.ts
index 0d2b081..0ebeff4 100644
--- a/frontend/projects/shared-meet-components/src/lib/services/context/context.service.ts
+++ b/frontend/projects/shared-meet-components/src/lib/services/context/context.service.ts
@@ -150,12 +150,8 @@ export class ContextService {
return this.context.participantRole === ParticipantRole.MODERATOR;
}
- canRecord(): boolean {
- return this.context.participantPermissions.canRecord;
- }
-
- canChat(): boolean {
- return this.context.participantPermissions.canChat;
+ getParticipantPermissions() {
+ return this.context.participantPermissions;
}
setRecordingPermissionsFromToken(token: string): void {