add user status

This commit is contained in:
_Bastler 2021-03-27 13:30:23 +01:00
parent b3f77eb721
commit 2cbfd628a2
5 changed files with 133 additions and 24 deletions

View File

@ -2,15 +2,15 @@
<mat-card> <mat-card>
<mat-card-content> <mat-card-content>
<h2>{{'password.change' | i18n}}</h2> <h2>{{'password.change' | i18n}}</h2>
<mat-hint *ngIf="success">
{{'password.changed' | i18n}}
</mat-hint>
<mat-form-field> <mat-form-field>
<input matInput type="password" placeholder="{{'password.current' | i18n}}" <input matInput type="password" placeholder="{{'password.current' | i18n}}"
formControlName="oldPassword" [(ngModel)]="model.old"> formControlName="oldPassword" [(ngModel)]="model.old">
<mat-error *ngFor="let error of passwordForm.get('oldPassword').errors | keyvalue"> <mat-error *ngFor="let error of passwordForm.get('oldPassword').errors | keyvalue">
{{error.key}} {{error.key}}
</mat-error> </mat-error>
<mat-hint *ngIf="success">
{{'password.changed' | i18n}}
</mat-hint>
</mat-form-field> </mat-form-field>
<mat-form-field> <mat-form-field>
<input matInput type="password" placeholder="{{'password' | i18n}}" formControlName="password" <input matInput type="password" placeholder="{{'password' | i18n}}" formControlName="password"
@ -36,13 +36,41 @@
</mat-card> </mat-card>
</form> </form>
<form [formGroup]="statusForm" (ngSubmit)="changeStatus()" #statusFormDirective="ngForm">
<mat-card>
<mat-card-content>
<h2>{{'security.status' | i18n}}</h2>
<p> {{'security.status.hint' | i18n}}</p>
<mat-form-field>
<mat-select [(ngModel)]="model.status" formControlName="status" placeholder="{{'security.status' | i18n}}">
<mat-option *ngFor="let status of statuses" [value]="status">
{{'security.status.' + status | i18n}}
</mat-option>
</mat-select>
<mat-hint *ngIf="successStatus">
{{'security.status.success' | i18n}}
</mat-hint>
</mat-form-field>
<mat-label>{{'security.status.' + model.status + '.hint' | i18n}}</mat-label>
</mat-card-content>
<mat-card-actions>
<mat-progress-bar *ngIf="working" mode="indeterminate"></mat-progress-bar>
<button *ngIf="!working" mat-raised-button color="primary" [disabled]="statusForm.invalid">
{{'security.status.change' | i18n}}
</button>
</mat-card-actions>
</mat-card>
</form>
<mat-card> <mat-card>
<mat-card-content> <mat-card-content>
<h2>{{'security.2fa' | i18n}}</h2> <h2>{{'security.2fa' | i18n}}</h2>
<p>{{'security.2fa.info' | i18n}}</p> <p>{{'security.2fa.info' | i18n}}</p>
</mat-card-content> </mat-card-content>
<mat-card-actions> <mat-card-actions>
<button *ngIf="!totp" (click)="createTotp()" mat-raised-button color="accent">{{'security.2fa.totp.create' | i18n}}</button> <button *ngIf="!totp" (click)="createTotp()" mat-raised-button color="accent">{{'security.2fa.totp.create' |
<button *ngIf="totp" (click)="removeTotp()" mat-raised-button color="warn">{{'security.2fa.totp.remove' | i18n}}</button> i18n}}</button>
<button *ngIf="totp" (click)="removeTotp()" mat-raised-button color="warn">{{'security.2fa.totp.remove' |
i18n}}</button>
</mat-card-actions> </mat-card-actions>
</mat-card> </mat-card>

View File

@ -1,10 +1,10 @@
import { Component, OnInit, ViewChild, Inject } from '@angular/core'; import {Component, OnInit, ViewChild, Inject} from '@angular/core';
import { FormBuilder, FormGroup, FormControl, Validators, NgForm } from '@angular/forms'; import {FormBuilder, FormGroup, FormControl, Validators, NgForm} from '@angular/forms';
import { MatDialog, MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; import {MatDialog, MatDialogRef, MAT_DIALOG_DATA} from '@angular/material/dialog';
import { AuthService } from './../../../services/auth.service'; import {AuthService} from './../../../services/auth.service';
import { UserService } from './../../../services/user.service'; import {UserService} from './../../../services/user.service';
import { MatchingValidator } from './../../../utils/matching.validator'; import {MatchingValidator} from './../../../utils/matching.validator';
@Component({ @Component({
selector: 'app-account-security', selector: 'app-account-security',
@ -17,16 +17,21 @@ export class SecurityComponent implements OnInit {
model: any = {}; model: any = {};
public working: boolean; public working: boolean;
public success: boolean; public success: boolean;
public successStatus: boolean;
public totp: boolean = false; public totp: boolean = false;
statuses = ["NORMAL", "SLEEP", "PURGE"];
passwordForm: FormGroup; passwordForm: FormGroup;
statusForm: FormGroup;
@ViewChild('passwordFormDirective') private passwordFormDirective: NgForm; @ViewChild('passwordFormDirective') private passwordFormDirective: NgForm;
@ViewChild('statusFormDirective') private statusFormDirective: NgForm;
constructor( constructor(
private formBuilder: FormBuilder, private formBuilder: FormBuilder,
private userService: UserService, private userService: UserService,
private authService: AuthService, private authService: AuthService,
public dialog: MatDialog) { } public dialog: MatDialog) {}
ngOnInit(): void { ngOnInit(): void {
this.passwordForm = this.formBuilder.group({ this.passwordForm = this.formBuilder.group({
@ -37,6 +42,17 @@ export class SecurityComponent implements OnInit {
validator: MatchingValidator('password', 'password2') validator: MatchingValidator('password', 'password2')
}); });
this.statusForm = this.formBuilder.group({
status: ['', Validators.required]
});
this.userService.get().subscribe((response: any) => {
this.model.status = response.status;
}, error => {
})
this.authService.isTotpEnabled().subscribe(response => { this.authService.isTotpEnabled().subscribe(response => {
this.totp = true; this.totp = true;
}, error => { }, error => {
@ -45,7 +61,7 @@ export class SecurityComponent implements OnInit {
} }
changePassword() { changePassword() {
if (this.passwordForm.valid && !this.working) { if(this.passwordForm.valid && !this.working) {
this.working = true; this.working = true;
this.userService.password(this.model).subscribe((result: any) => { this.userService.password(this.model).subscribe((result: any) => {
@ -54,14 +70,14 @@ export class SecurityComponent implements OnInit {
this.working = false; this.working = false;
}, (error) => { }, (error) => {
this.working = false; this.working = false;
if (error.status == 409) { if(error.status == 409) {
let errors = {}; let errors = {};
for (let code of error.error) { for(let code of error.error) {
errors[code.field] = errors[code.field] || {}; errors[code.field] = errors[code.field] || {};
errors[code.field][code.code] = true; errors[code.field][code.code] = true;
} }
for (let code in errors) { for(let code in errors) {
this.passwordForm.get(code).setErrors(errors[code]); this.passwordForm.get(code).setErrors(errors[code]);
} }
} }
@ -69,6 +85,20 @@ export class SecurityComponent implements OnInit {
} }
} }
changeStatus() {
if(this.statusForm.valid && !this.working) {
this.working = true;
this.userService.update({status : this.model.status}).subscribe((result: any) => {
this.successStatus = true;
this.working = false;
}, (error) => {
this.working = false;
})
}
}
createTotp() { createTotp() {
this.authService.createTotp().subscribe((result: any) => { this.authService.createTotp().subscribe((result: any) => {
const dialogRef = this.dialog.open(SecurityTotpDialog, { const dialogRef = this.dialog.open(SecurityTotpDialog, {
@ -78,7 +108,7 @@ export class SecurityComponent implements OnInit {
}); });
dialogRef.afterClosed().subscribe(result => { dialogRef.afterClosed().subscribe(result => {
if (result) { if(result) {
this.authService.enableTotp(result).subscribe((result: any) => { this.authService.enableTotp(result).subscribe((result: any) => {
this.totp = true; this.totp = true;
}) })
@ -121,7 +151,7 @@ export class SecurityTotpDialog {
constructor( constructor(
public dialogRef: MatDialogRef<SecurityTotpDialog>, public dialogRef: MatDialogRef<SecurityTotpDialog>,
@Inject(MAT_DIALOG_DATA) public data: any @Inject(MAT_DIALOG_DATA) public data: any
) { } ) {}
ngOnInit(): void { ngOnInit(): void {
this.code = new FormControl('', [Validators.required, Validators.pattern("[0-9]{6}")]); this.code = new FormControl('', [Validators.required, Validators.pattern("[0-9]{6}")]);

View File

@ -11,6 +11,10 @@ export class UserService {
constructor(private http: HttpClient) { constructor(private http: HttpClient) {
} }
get() {
return this.http.get(environment.apiUrl + "/users");
}
register(userModel) { register(userModel) {
return this.http.post(environment.apiUrl + "/users", userModel); return this.http.post(environment.apiUrl + "/users", userModel);
} }

View File

@ -174,12 +174,30 @@
"missing": "Bitte TOTP Code eingeben", "missing": "Bitte TOTP Code eingeben",
"remove": "2FA (TOTP) deaktivieren" "remove": "2FA (TOTP) deaktivieren"
} }
},
"status": {
".": "Status",
"change" : "Status ändern",
"hint": "Dein User Status gibt an, wie mit deinen Account Daten umgegangen wird wenn deine Berechtigungen ausgelaufen sind.",
"NORMAL": {
".": "Normal",
"hint": "Dein Account sowie alle gespeicherten Daten werden vier (4) Wochen nach Ablauf gelöscht. Du hast also vier Wochen Zeit deinen Account wieder zu reaktivieren."
},
"PURGE": {
".": "Löschen",
"hint": "Dein Account sowie alle gespeicherten Daten werden umgehend(!) nach Ablauf gelöscht. Du kannst deinen Account nicht(!) mehr reaktivieren."
},
"SLEEP": {
".": "Schlafen",
"hint": "Dein Account sowie alle gespeicherten Daten werden nicht(!) gelöscht. Du kannst deinen Account also jederzeit wieder reaktivieren."
},
"success" : "Status erfolgreich geändert"
} }
}, },
"service-unavailable": { "service-unavailable": {
".": "Dienst nicht erreichbar", ".": "Dienst nicht erreichbar",
"retry" : "Seite neu laden", "retry": "Seite neu laden",
"support" : "Support", "support": "Support",
"text": "Zurzeit scheint der Dienst nicht erreichbar zu sein. Wenn diese Meldung länger besteht, melde dich beim Support!" "text": "Zurzeit scheint der Dienst nicht erreichbar zu sein. Wenn diese Meldung länger besteht, melde dich beim Support!"
}, },
"services": { "services": {
@ -227,6 +245,12 @@
"text": "Administrator Rechte für die API von we.bstly", "text": "Administrator Rechte für die API von we.bstly",
"title": "Administrator" "title": "Administrator"
}, },
"ROLE_GUEST": {
"icon": "schedule_send",
"subtitle": "Gast Account von we.bstly",
"text": "Gast Account Einladung",
"title": "Gast Account"
},
"ROLE_MEMBER": { "ROLE_MEMBER": {
"icon": "loyalty", "icon": "loyalty",
"subtitle": "Mitgliedschaft im Bastelei e. V.", "subtitle": "Mitgliedschaft im Bastelei e. V.",

View File

@ -174,12 +174,30 @@
"missing": "Please enter TOTP code", "missing": "Please enter TOTP code",
"remove": "Disable 2FA (TOTP)" "remove": "Disable 2FA (TOTP)"
} }
},
"status": {
".": "Status",
"change" : "Change status",
"hint": "You Account Status controls the handling of your account data after all permissions expired.",
"NORMAL": {
".": "Normal",
"hint": "Your account and all your data will be deleted after four (4) weeks. So you have 4 weeks left to reactivate your account."
},
"PURGE": {
".": "Purge",
"hint": "Your account and all your data will be deleted immediately after expiry. So you can not(!) reactivate your account."
},
"SLEEP": {
".": "Sleep",
"hint": "Your account and all your data will not(!) be deleted. So you have reactivate your account anytime."
},
"success" : "Status successfully changed"
} }
}, },
"service-unavailable": { "service-unavailable": {
".": "Service unavailable", ".": "Service unavailable",
"retry" : "Reload page", "retry": "Reload page",
"support" : "Support", "support": "Support",
"text": "The service seems currently unavailable. If this message appears over a longer period, please contact our support!" "text": "The service seems currently unavailable. If this message appears over a longer period, please contact our support!"
}, },
"services": { "services": {
@ -227,6 +245,12 @@
"text": "Administrator privileges for we.bstly API", "text": "Administrator privileges for we.bstly API",
"title": "Administrator" "title": "Administrator"
}, },
"ROLE_GUEST": {
"icon": "schedule_send",
"subtitle": "Guest Account of we.bstly",
"text": "Guest Account Invite",
"title": "Guest Account"
},
"ROLE_MEMBER": { "ROLE_MEMBER": {
"icon": "loyalty", "icon": "loyalty",
"subtitle": "Membership of Bastelei e. V.", "subtitle": "Membership of Bastelei e. V.",
@ -276,8 +300,7 @@
"info": "Generate vouchers for Add-Ons and registration.", "info": "Generate vouchers for Add-Ons and registration.",
"registration": "Registration", "registration": "Registration",
"stored-safely": { "stored-safely": {
".": ".": "Please store the provided voucher code securely, since we do not store any relation of vouchers to your account. If you leave page or reload the code won't be shown up again!",
"Please store the provided voucher code securely, since we do not store any relation of vouchers to your account. If you leave page or reload the code won't be shown up again!",
"confirm": "I securely stored the given voucher!" "confirm": "I securely stored the given voucher!"
}, },
"temp": { "temp": {