frontend: update users permissions component for improved admin credential handling and access settings

This commit is contained in:
juancarmore 2025-07-02 19:04:27 +02:00
parent 66140468be
commit 9dc2796d24
2 changed files with 90 additions and 105 deletions

View File

@ -15,7 +15,7 @@
<div class="loading-content">
<div class="loading-header">
<div class="loading-title">
<mat-icon class="ov-settings-icon loading-icon"> settings </mat-icon>
<mat-icon class="ov-settings-icon loading-icon">settings</mat-icon>
<h1>Loading Settings</h1>
</div>
<p class="loading-subtitle">Please wait while we fetch your settings...</p>
@ -61,7 +61,7 @@
<h3>User Authentication</h3>
<ov-pro-feature-badge class="users-pro-badge"></ov-pro-feature-badge>
</div>
<p class="field-description">Choose how users will authenticate to join rooms.</p>
<p class="field-description">Choose how users will authenticate to access OpenVidu Meet.</p>
<mat-form-field
subscriptSizing="dynamic"
appearance="outline"
@ -70,47 +70,53 @@
<mat-select [value]="'single'">
<mat-option value="single">Single user</mat-option>
<mat-option value="multiusers" [disabled]="true">
Multi-user authentication (OAuth & credentials)
Multi-user (credentials & optional OAuth)
</mat-option>
<mat-option value="oauth" [disabled]="true">Only OAuth </mat-option>
<mat-option value="oauth" [disabled]="true">Multi-user (only OAuth)</mat-option>
</mat-select>
</mat-form-field>
</div>
<!-- Change Admin Password -->
<div class="form-section">
<div class="form-field-header">
<h3>Admin Authentication</h3>
<p class="field-description">
Change the password for the admin user for OpenVidu Meet access.
</p>
</div>
<form [formGroup]="adminCredentialsForm" (ngSubmit)="onSaveAdminCredentials()">
<div class="form-section">
<div class="form-field-header">
<h3>Admin Credentials</h3>
<p class="field-description">Change the password for the admin user.</p>
</div>
<div class="admin-auth-form">
<mat-form-field subscriptSizing="dynamic" appearance="outline" class="username-field">
<mat-label>Username</mat-label>
<input matInput type="text" value="Admin (TODO)" disabled />
</mat-form-field>
<div class="admin-auth-form">
<mat-form-field subscriptSizing="dynamic" appearance="outline" class="username-field">
<mat-label>Username</mat-label>
<input matInput type="text" formControlName="adminUsername" placeholder="admin" />
</mat-form-field>
<mat-form-field subscriptSizing="dynamic" appearance="outline" class="password-field">
<mat-label>Password</mat-label>
<input
matInput
type="password"
[formControl]="adminPasswordControl"
placeholder="••••••••"
/>
<mat-hint>Minimum of 8 characters</mat-hint>
@if (getAdminPasswordError()) {
<mat-error>{{ getAdminPasswordError() }}</mat-error>
}
</mat-form-field>
<mat-form-field subscriptSizing="dynamic" appearance="outline" class="password-field">
<mat-label>Password</mat-label>
<input
matInput
type="password"
formControlName="adminPassword"
placeholder="••••••••"
/>
<mat-hint>Minimum of 4 characters</mat-hint>
@if (getAdminPasswordError()) {
<mat-error>{{ getAdminPasswordError() }}</mat-error>
}
</mat-form-field>
</div>
</div>
</div>
</form>
</mat-card-content>
<mat-card-actions>
<button mat-raised-button color="primary" type="submit" (click)="onSaveAccess()">
Save Admin password
<button
mat-raised-button
color="primary"
type="submit"
[disabled]="adminCredentialsForm.invalid"
(click)="onSaveAdminCredentials()"
>
Save admin password
</button>
</mat-card-actions>
</mat-card>
@ -127,7 +133,7 @@
<mat-divider class="section-divider"></mat-divider>
<mat-card-content>
<form [formGroup]="authForm" (ngSubmit)="onSaveAccess()">
<form [formGroup]="accessSettingsForm" (ngSubmit)="onSaveAccessSettings()">
<!-- Authentication for joining room -->
<div class="form-section">
<div class="form-field-header">
@ -142,16 +148,13 @@
<mat-option [value]="option.value">{{ option.label }}</mat-option>
}
</mat-select>
@if (getFieldError(authForm, 'authModeToAccessRoom')) {
<mat-error>{{ getFieldError(authForm, 'authModeToAccessRoom') }}</mat-error>
}
</mat-form-field>
</div>
</form>
</mat-card-content>
<mat-card-actions>
<button mat-raised-button color="primary" type="submit" (click)="onSaveAccess()">
Save Configuration
<button mat-raised-button color="primary" type="submit" (click)="onSaveAccessSettings()">
Save configuration
</button>
</mat-card-actions>
</mat-card>

View File

@ -1,4 +1,3 @@
import { CommonModule } from '@angular/common';
import { Component, OnInit, signal } from '@angular/core';
import { FormControl, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms';
import { MatButtonModule } from '@angular/material/button';
@ -9,9 +8,7 @@ import { MatIconModule } from '@angular/material/icon';
import { MatInputModule } from '@angular/material/input';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
import { MatSelectModule } from '@angular/material/select';
import { MatSnackBarModule } from '@angular/material/snack-bar';
import { MatTooltipModule } from '@angular/material/tooltip';
import { LogoSelectorComponent, ProFeatureBadgeComponent } from '@lib/components';
import { ProFeatureBadgeComponent } from '@lib/components';
import { AuthService, GlobalPreferencesService, NotificationService } from '@lib/services';
import { AuthMode } from '@lib/typings/ce';
@ -19,41 +16,36 @@ import { AuthMode } from '@lib/typings/ce';
selector: 'ov-preferences',
standalone: true,
imports: [
CommonModule,
MatCardModule,
MatButtonModule,
MatIconModule,
MatInputModule,
MatFormFieldModule,
MatSelectModule,
MatSnackBarModule,
MatTooltipModule,
MatProgressSpinnerModule,
MatDividerModule,
ReactiveFormsModule,
LogoSelectorComponent,
ProFeatureBadgeComponent,
MatSelectModule
ProFeatureBadgeComponent
],
templateUrl: './users-permissions.component.html',
styleUrl: './users-permissions.component.scss'
})
export class UsersPermissionsComponent implements OnInit {
isLoading = signal(false);
isSavingBranding = signal(false);
isSavingAccess = signal(false);
authForm = new FormGroup({
adminCredentialsForm = new FormGroup({
adminUsername: new FormControl({ value: '', disabled: true }, [Validators.required]),
adminPassword: new FormControl('', [Validators.required, Validators.minLength(4)])
});
accessSettingsForm = new FormGroup({
authModeToAccessRoom: new FormControl(AuthMode.NONE, [Validators.required])
});
adminPasswordControl = new FormControl('', [Validators.required, Validators.minLength(8)]);
// Auth mode options for the select dropdown
authModeOptions = [
{ value: AuthMode.ALL_USERS, label: 'Everyone' },
{ value: AuthMode.MODERATORS_ONLY, label: 'Only Moderators' },
{ value: AuthMode.NONE, label: 'Nobody' }
{ value: AuthMode.NONE, label: 'Nobody' },
{ value: AuthMode.MODERATORS_ONLY, label: 'Only moderators' },
{ value: AuthMode.ALL_USERS, label: 'Everyone' }
];
constructor(
@ -63,52 +55,72 @@ export class UsersPermissionsComponent implements OnInit {
) {}
async ngOnInit() {
await this.loadSettings();
this.isLoading.set(true);
await this.loadAdminUsername();
await this.loadAccessSettings();
this.isLoading.set(false);
}
private async loadSettings() {
this.isLoading.set(true);
private async loadAdminUsername() {
const username = await this.authService.getUsername();
if (!username) {
console.error('Admin username not found');
this.notificationService.showSnackbar('Failed to load admin username');
return;
}
this.adminCredentialsForm.get('adminUsername')?.setValue(username);
}
private async loadAccessSettings() {
try {
const authMode = await this.preferencesService.getAuthModeToAccessRoom();
this.authForm.get('authModeToAccessRoom')?.setValue(authMode);
this.accessSettingsForm.get('authModeToAccessRoom')?.setValue(authMode);
} catch (error) {
console.error('Error loading security preferences:', error);
this.notificationService.showSnackbar('Failed to load security preferences');
}
this.isLoading.set(false);
}
async onSaveAccess() {
if (this.authForm.invalid || this.adminPasswordControl.invalid) {
async onSaveAdminCredentials() {
if (this.adminCredentialsForm.invalid) {
return;
}
this.isSavingAccess.set(true);
const formData = this.authForm.value;
const adminPassword = this.adminPasswordControl.value;
const formData = this.adminCredentialsForm.value;
const adminPassword = formData.adminPassword!;
try {
await this.authService.changePassword(adminPassword);
this.notificationService.showSnackbar('Admin credentials updated successfully');
} catch (error) {
console.error('Error saving admin credentials:', error);
this.notificationService.showSnackbar('Failed to save admin credentials');
}
}
async onSaveAccessSettings() {
if (this.accessSettingsForm.invalid) {
return;
}
const formData = this.accessSettingsForm.value;
try {
const securityPrefs = await this.preferencesService.getSecurityPreferences();
securityPrefs.authentication.authModeToAccessRoom = formData.authModeToAccessRoom!;
await this.preferencesService.saveSecurityPreferences(securityPrefs);
if (adminPassword) {
await this.authService.changePassword(adminPassword);
}
this.notificationService.showSnackbar('Access & Permissions settings saved successfully');
} catch (error) {
console.error('Error saving access permissions:', error);
this.notificationService.showSnackbar('Failed to save Access & Permissions settings');
} finally {
this.isSavingAccess.set(false);
}
}
// Utility methods for form validation
getAdminPasswordError(): string {
const control = this.adminPasswordControl;
const control = this.adminCredentialsForm.get('adminPassword')!;
if (!control.touched || !control.errors) {
return '';
}
@ -123,34 +135,4 @@ export class UsersPermissionsComponent implements OnInit {
return '';
}
// Utility methods for form validation
getFieldError(formGroup: FormGroup, fieldName: string): string {
const field = formGroup.get(fieldName);
if (!field || !field.touched || !field.errors) {
return '';
}
const errors = field.errors;
if (errors['required']) {
return `${this.getFieldLabel(fieldName)} is required`;
}
if (errors['minlength']) {
return `${this.getFieldLabel(fieldName)} must be at least ${errors['minlength'].requiredLength} characters`;
}
if (errors['invalidUrl']) {
return `${this.getFieldLabel(fieldName)} must be a valid URL`;
}
return '';
}
private getFieldLabel(fieldName: string): string {
const labels: Record<string, string> = {
logoUrl: 'Logo URL',
authModeToAccessRoom: 'Authentication mode to access room',
adminPassword: 'Admin password'
};
return labels[fieldName] || fieldName;
}
}