fix: disable user action if viewer (#2737)

This commit is contained in:
Max Peintner 2021-11-25 11:27:20 +01:00 committed by GitHub
parent f7743834b0
commit a9035def0f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 92 additions and 90 deletions

View File

@ -1,7 +1,8 @@
<form [formGroup]="profileForm" *ngIf="profileForm" (ngSubmit)="submitForm()">
<div class="user-form-content">
<div class="user-form-content inner">
<button class="camera-wrapper" type="button" (click)="showEditImage ? openUploadDialog() : null">
<button [disabled]="user && disabled" class="camera-wrapper" type="button"
(click)="showEditImage ? openUploadDialog() : null">
<div class="i-wrapper" *ngIf="showEditImage">
<i class="las la-camera"></i>
</div>
@ -16,7 +17,7 @@
<cnsl-label>{{ 'USER.PROFILE.USERNAME' | translate }}</cnsl-label>
<input cnslInput formControlName="userName" />
</cnsl-form-field>
<button type="button" color="primary" mat-stroked-button class="edit"
<button [disabled]="user && disabled" type="button" color="primary" mat-stroked-button class="edit"
(click)="changeUsername()">{{'USER.PROFILE.CHANGEUSERNAME' |
translate}}</button>
</div>

View File

@ -16,25 +16,20 @@ export class DetailFormComponent implements OnDestroy, OnChanges {
@Input() public preferredLoginName: string = '';
@Input() public username!: string;
@Input() public user!: Human.AsObject;
@Input() public disabled: boolean = false;
@Input() public disabled: boolean = true;
@Input() public genders: Gender[] = [];
@Input() public languages: string[] = ['de', 'en'];
@Output() public submitData: EventEmitter<Profile.AsObject> = new EventEmitter<Profile.AsObject>();
@Output() public changedLanguage: EventEmitter<string> = new EventEmitter<string>();
@Output() public changeUsernameClicked: EventEmitter<void> = new EventEmitter();
public profileForm!: FormGroup;
private sub: Subscription = new Subscription();
constructor(
private fb: FormBuilder,
private dialog: MatDialog,
) {
constructor(private fb: FormBuilder, private dialog: MatDialog) {
this.profileForm = this.fb.group({
userName: [{ value: '', disabled: true }, [
Validators.required,
]],
userName: [{ value: '', disabled: true }, [Validators.required]],
firstName: [{ value: '', disabled: this.disabled }, Validators.required],
lastName: [{ value: '', disabled: this.disabled }, Validators.required],
nickName: [{ value: '', disabled: this.disabled }],
@ -46,9 +41,7 @@ export class DetailFormComponent implements OnDestroy, OnChanges {
public ngOnChanges(): void {
this.profileForm = this.fb.group({
userName: [{ value: '', disabled: true }, [
Validators.required,
]],
userName: [{ value: '', disabled: true }, [Validators.required]],
firstName: [{ value: '', disabled: this.disabled }, Validators.required],
lastName: [{ value: '', disabled: this.disabled }, Validators.required],
nickName: [{ value: '', disabled: this.disabled }],
@ -60,7 +53,7 @@ export class DetailFormComponent implements OnDestroy, OnChanges {
this.profileForm.patchValue({ userName: this.username, ...this.user.profile });
if (this.preferredLanguage) {
this.sub = this.preferredLanguage.valueChanges.subscribe(value => {
this.sub = this.preferredLanguage.valueChanges.subscribe((value) => {
this.changedLanguage.emit(value);
});
}
@ -86,7 +79,7 @@ export class DetailFormComponent implements OnDestroy, OnChanges {
width: '400px',
});
dialogRef.afterClosed().subscribe(resp => {
dialogRef.afterClosed().subscribe((resp) => {
if (resp) {
}
});
@ -114,5 +107,4 @@ export class DetailFormComponent implements OnDestroy, OnChanges {
public get preferredLanguage(): AbstractControl | null {
return this.profileForm.get('preferredLanguage');
}
}

View File

@ -1,53 +1,53 @@
<cnsl-card title="{{'USER.PASSWORDLESS.TITLE' | translate}}"
description="{{'USER.PASSWORDLESS.DESCRIPTION' | translate}}">
<button card-actions mat-icon-button (click)="getPasswordless()" class="icon-button" matTooltip="{{'ACTIONS.REFRESH' | translate}}">
<mat-icon class="icon">refresh</mat-icon>
description="{{'USER.PASSWORDLESS.DESCRIPTION' | translate}}">
<button card-actions mat-icon-button (click)="getPasswordless()" class="icon-button"
matTooltip="{{'ACTIONS.REFRESH' | translate}}">
<mat-icon class="icon">refresh</mat-icon>
</button>
<cnsl-refresh-table [hideRefresh]="true" [loading]="loading$ | async" [dataSize]="dataSource?.data?.length ?? 0">
<table class="table" mat-table [dataSource]="dataSource">
<ng-container matColumnDef="name">
<th mat-header-cell *matHeaderCellDef> {{ 'USER.PASSWORDLESS.NAME' | translate }} </th>
<td mat-cell *matCellDef="let mfa"><span *ngIf="mfa?.name" class="centered">
{{ mfa?.name }}
</span>
</td>
</ng-container>
<ng-container matColumnDef="state">
<th mat-header-cell *matHeaderCellDef> {{ 'USER.PASSWORDLESS.TABLESTATE' | translate }} </th>
<td mat-cell *matCellDef="let mfa"><span class="centered">
{{'USER.PASSWORDLESS.STATE.'+ mfa.state | translate}}
<i matTooltip="verified" *ngIf="mfa.state === AuthFactorState.AUTH_FACTOR_STATE_READY"
class="verified las la-check-circle"></i>
</span>
</td>
</ng-container>
<ng-container matColumnDef="actions">
<th mat-header-cell *matHeaderCellDef> {{ 'USER.PASSWORDLESS.TABLEACTIONS' | translate }} </th>
<td mat-cell *matCellDef="let mfa">
<button matTooltip="{{'ACTIONS.REMOVE' | translate}}" color="warn" mat-icon-button
(click)="deletePasswordless(mfa.id)">
<i class="las la-trash"></i>
</button>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr class="highlight" mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
</cnsl-refresh-table>
<div class="add-row">
<button [disabled]="user && disabled" class="button" (click)="sendPasswordlessRegistration()" mat-raised-button
color="primary" matTooltip="{{'ACTIONS.NEW' | translate}}">
{{'USER.PASSWORDLESS.SEND' | translate}}
<i class="icon las la-paper-plane"></i>
</button>
<cnsl-refresh-table [hideRefresh]="true" [loading]="loading$ | async"
[dataSize]="dataSource?.data?.length ?? 0">
<table class="table" mat-table [dataSource]="dataSource">
<ng-container matColumnDef="name">
<th mat-header-cell *matHeaderCellDef> {{ 'USER.PASSWORDLESS.NAME' | translate }} </th>
<td mat-cell *matCellDef="let mfa"><span *ngIf="mfa?.name" class="centered">
{{ mfa?.name }}
</span>
</td>
</ng-container>
<ng-container matColumnDef="state">
<th mat-header-cell *matHeaderCellDef> {{ 'USER.PASSWORDLESS.TABLESTATE' | translate }} </th>
<td mat-cell *matCellDef="let mfa"><span class="centered">
{{'USER.PASSWORDLESS.STATE.'+ mfa.state | translate}}
<i matTooltip="verified" *ngIf="mfa.state === AuthFactorState.AUTH_FACTOR_STATE_READY"
class="verified las la-check-circle"></i>
</span>
</td>
</ng-container>
<ng-container matColumnDef="actions">
<th mat-header-cell *matHeaderCellDef> {{ 'USER.PASSWORDLESS.TABLEACTIONS' | translate }} </th>
<td mat-cell *matCellDef="let mfa">
<button matTooltip="{{'ACTIONS.REMOVE' | translate}}" color="warn" mat-icon-button
(click)="deletePasswordless(mfa.id)">
<i class="las la-trash"></i>
</button>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr class="highlight" mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
</cnsl-refresh-table>
<div class="add-row">
<button class="button" (click)="sendPasswordlessRegistration()" mat-raised-button color="primary"
matTooltip="{{'ACTIONS.NEW' | translate}}">
{{'USER.PASSWORDLESS.SEND' | translate}}
<i class="icon las la-paper-plane"></i>
</button>
</div>
<div class="table-wrapper">
<div class="spinner-container" *ngIf="loading$ | async">
<mat-spinner diameter="50"></mat-spinner>
</div>
<div class="table-wrapper">
<div class="spinner-container" *ngIf="loading$ | async">
<mat-spinner diameter="50"></mat-spinner>
</div>
</div>
</cnsl-card>

View File

@ -10,10 +10,10 @@ import { ToastService } from 'src/app/services/toast.service';
export interface WebAuthNOptions {
challenge: string;
rp: { name: string, id: string; };
user: { name: string, id: string, displayName: string; };
rp: { name: string; id: string };
user: { name: string; id: string; displayName: string };
pubKeyCredParams: any;
authenticatorSelection: { userVerification: string; };
authenticatorSelection: { userVerification: string };
timeout: number;
attestation: string;
}
@ -25,6 +25,7 @@ export interface WebAuthNOptions {
})
export class PasswordlessComponent implements OnInit, OnDestroy {
@Input() public user!: User.AsObject;
@Input() public disabled: boolean = true;
public displayedColumns: string[] = ['name', 'state', 'actions'];
private loadingSubject: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
public loading$: Observable<boolean> = this.loadingSubject.asObservable();
@ -36,9 +37,7 @@ export class PasswordlessComponent implements OnInit, OnDestroy {
public AuthFactorState: any = AuthFactorState;
public error: string = '';
constructor(private service: ManagementService,
private toast: ToastService,
private dialog: MatDialog) { }
constructor(private service: ManagementService, private toast: ToastService, private dialog: MatDialog) {}
public ngOnInit(): void {
this.getPasswordless();
@ -49,12 +48,15 @@ export class PasswordlessComponent implements OnInit, OnDestroy {
}
public getPasswordless(): void {
this.service.listHumanPasswordless(this.user.id).then(passwordless => {
this.dataSource = new MatTableDataSource(passwordless.resultList);
this.dataSource.sort = this.sort;
}).catch(error => {
this.error = error.message;
});
this.service
.listHumanPasswordless(this.user.id)
.then((passwordless) => {
this.dataSource = new MatTableDataSource(passwordless.resultList);
this.dataSource.sort = this.sort;
})
.catch((error) => {
this.error = error.message;
});
}
public deletePasswordless(id?: string): void {
@ -68,23 +70,29 @@ export class PasswordlessComponent implements OnInit, OnDestroy {
width: '400px',
});
dialogRef.afterClosed().subscribe(resp => {
dialogRef.afterClosed().subscribe((resp) => {
if (resp && id) {
this.service.removeHumanPasswordless(id, this.user.id).then(() => {
this.toast.showInfo('USER.TOAST.PASSWORDLESSREMOVED', true);
this.getPasswordless();
}).catch(error => {
this.toast.showError(error);
});
this.service
.removeHumanPasswordless(id, this.user.id)
.then(() => {
this.toast.showInfo('USER.TOAST.PASSWORDLESSREMOVED', true);
this.getPasswordless();
})
.catch((error) => {
this.toast.showError(error);
});
}
});
}
public sendPasswordlessRegistration(): void {
this.service.sendPasswordlessRegistration(this.user.id).then(() => {
this.toast.showInfo('USER.TOAST.PASSWORDLESSREGISTRATIONSENT');
}).catch(error => {
this.toast.showError(error);
});
this.service
.sendPasswordlessRegistration(this.user.id)
.then(() => {
this.toast.showInfo('USER.TOAST.PASSWORDLESSREGISTRATIONSENT');
})
.catch((error) => {
this.toast.showError(error);
});
}
}

View File

@ -87,7 +87,8 @@
</cnsl-card>
</ng-template>
<cnsl-passwordless *ngIf="user && user.human" [user]="user"></cnsl-passwordless>
<cnsl-passwordless *ngIf="user && user.human" [user]="user" [disabled]="(canWrite$ | async) === false">
</cnsl-passwordless>
<cnsl-user-mfa *ngIf="user && user.human" [user]="user"></cnsl-user-mfa>