add userprefs to frontend

This commit is contained in:
rubikscraft
2022-04-13 21:14:24 +02:00
parent 478e6cc52e
commit 6a9443b247
18 changed files with 98 additions and 52 deletions

View File

@@ -30,6 +30,7 @@ export class PreferenceDefaultsService {
if (envSecret) {
return envSecret;
} else {
console.trace(`what`);
this.logger.warn(
'Since no JWT secret was provided, a random one will be generated and saved',
);

View File

@@ -57,7 +57,7 @@ export class UsersModule implements OnModuleInit {
username,
password,
roles,
false,
true,
);
if (HasFailed(newUser)) {
this.logger.error(

View File

@@ -1,21 +1,30 @@
import { Component, Input, OnInit } from '@angular/core';
import { AutoUnsubscribe } from 'ngx-auto-unsubscribe-decorator';
import { DecodedSysPref, PrefValueType } from 'picsur-shared/dist/dto/preferences.dto';
import {
DecodedSysPref,
PrefValueType
} from 'picsur-shared/dist/dto/preferences.dto';
import { SysPreference } from 'picsur-shared/dist/dto/syspreferences.dto';
import { HasFailed } from 'picsur-shared/dist/types';
import { Subject, throttleTime } from 'rxjs';
import { AsyncFailable, HasFailed } from 'picsur-shared/dist/types';
import { Subject } from 'rxjs';
import { SysPreferenceFriendlyNames } from 'src/app/i18n/syspref.i18n';
import { Required } from 'src/app/models/decorators/required.decorator';
import { SnackBarType } from 'src/app/models/dto/snack-bar-type.dto';
import { SysPrefService } from 'src/app/services/api/syspref.service';
import { Throttle } from 'src/app/util/throttle';
import { UtilService } from 'src/app/util/util.service';
@Component({
selector: 'syspref-option',
templateUrl: './settings-syspref-option.component.html',
styleUrls: ['./settings-syspref-option.component.scss'],
selector: 'pref-option',
templateUrl: './pref-option.component.html',
styleUrls: ['./pref-option.component.scss'],
})
export class SettingsSysprefOptionComponent implements OnInit {
@Input() pref: DecodedSysPref;
export class PrefOptionComponent implements OnInit {
@Input() @Required pref: DecodedSysPref;
@Input('update') @Required updateFunction: (
key: string,
pref: PrefValueType
) => AsyncFailable<any>;
private updateSubject = new Subject<PrefValueType>();
@@ -72,10 +81,7 @@ export class SettingsSysprefOptionComponent implements OnInit {
}
private async updatePreference(value: PrefValueType) {
const result = await this.sysprefService.setPreference(
this.pref.key,
value
);
const result = await this.updateFunction(this.pref.key, value);
if (!HasFailed(result)) {
this.utilService.showSnackBar(
`Updated ${this.name}`,
@@ -92,7 +98,7 @@ export class SettingsSysprefOptionComponent implements OnInit {
@AutoUnsubscribe()
subscribeUpdate() {
return this.updateSubject
.pipe(throttleTime(300, undefined, { leading: true, trailing: true }))
.pipe(Throttle(300))
.subscribe(this.updatePreference.bind(this));
}
}

View File

@@ -0,0 +1,18 @@
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatInputModule } from '@angular/material/input';
import { MatSlideToggleModule } from '@angular/material/slide-toggle';
import { PrefOptionComponent } from './pref-option.component';
@NgModule({
imports: [
CommonModule,
MatFormFieldModule,
MatInputModule,
MatSlideToggleModule,
],
declarations: [PrefOptionComponent],
exports: [PrefOptionComponent],
})
export class PrefOptionModule {}

View File

@@ -1,6 +1,8 @@
<h1>Settings</h1>
<p *ngFor="let setting of userPref.live | async">
<span>{{setting.key}}</span>
<span>{{setting.value}}</span>
</p>
<ng-container *ngFor="let pref of preferences | async">
<pref-option
[pref]="pref"
[update]="usrPrefService.setPreference.bind(usrPrefService)"
></pref-option>
</ng-container>

View File

@@ -1,11 +1,15 @@
import { Component, OnInit } from '@angular/core';
import { Component } from '@angular/core';
import { DecodedPref } from 'picsur-shared/dist/dto/preferences.dto';
import { Observable } from 'rxjs';
import { UsrPrefService } from 'src/app/services/api/usrpref.service';
@Component({
templateUrl: './settings-general.component.html',
})
export class SettingsGeneralComponent implements OnInit {
constructor(public userPref: UsrPrefService) {}
export class SettingsGeneralComponent {
preferences: Observable<DecodedPref[]>;
ngOnInit(): void {}
constructor(public usrPrefService: UsrPrefService) {
this.preferences = usrPrefService.live;
}
}

View File

@@ -1,5 +1,6 @@
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { PrefOptionModule } from 'src/app/components/pref-option/pref-option.module';
import { SettingsGeneralComponent } from './settings-general.component';
import { SettingsGeneralRoutingModule } from './settings-general.routing.module';
@@ -8,6 +9,7 @@ import { SettingsGeneralRoutingModule } from './settings-general.routing.module'
imports: [
CommonModule,
SettingsGeneralRoutingModule,
PrefOptionModule
],
})
export class SettingsGeneralRouteModule {}

View File

@@ -1,5 +1,8 @@
<h1>System Settings</h1>
<ng-container *ngFor="let pref of preferences | async">
<syspref-option [pref]="pref"></syspref-option>
<pref-option
[pref]="pref"
[update]="sysPrefService.setPreference.bind(sysPrefService)"
></pref-option>
</ng-container>

View File

@@ -1,5 +1,5 @@
import { Component } from '@angular/core';
import { DecodedSysPref } from 'picsur-shared/dist/dto/preferences.dto';
import { DecodedPref } from 'picsur-shared/dist/dto/preferences.dto';
import { Observable } from 'rxjs';
import { SysPrefService } from 'src/app/services/api/syspref.service';
@@ -7,9 +7,9 @@ import { SysPrefService } from 'src/app/services/api/syspref.service';
templateUrl: './settings-syspref.component.html',
})
export class SettingsSysprefComponent {
preferences: Observable<DecodedSysPref[]>;
preferences: Observable<DecodedPref[]>;
constructor(sysprefService: SysPrefService) {
this.preferences = sysprefService.live;
constructor(public sysPrefService: SysPrefService) {
this.preferences = sysPrefService.live;
}
}

View File

@@ -1,18 +1,15 @@
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { MatInputModule } from '@angular/material/input';
import { MatSlideToggleModule } from '@angular/material/slide-toggle';
import { PrefOptionModule } from 'src/app/components/pref-option/pref-option.module';
import { SettingsSysprefComponent } from './settings-syspref.component';
import { SettingsSysprefRoutingModule } from './settings-syspref.routing.module';
import { SettingsSysprefOptionComponent } from './syspref-option/settings-syspref-option.component';
@NgModule({
declarations: [SettingsSysprefComponent, SettingsSysprefOptionComponent],
declarations: [SettingsSysprefComponent],
imports: [
CommonModule,
SettingsSysprefRoutingModule,
MatSlideToggleModule,
MatInputModule,
PrefOptionModule,
],
})
export class SettingsSysprefRouteModule {}

View File

@@ -4,11 +4,12 @@ import { Router } from '@angular/router';
import { AutoUnsubscribe } from 'ngx-auto-unsubscribe-decorator';
import { EUser } from 'picsur-shared/dist/entities/user.entity';
import { HasFailed } from 'picsur-shared/dist/types';
import { BehaviorSubject, Subject, throttleTime } from 'rxjs';
import { BehaviorSubject, Subject } from 'rxjs';
import { SnackBarType } from 'src/app/models/dto/snack-bar-type.dto';
import { StaticInfoService } from 'src/app/services/api/static-info.service';
import { UserManageService } from 'src/app/services/api/usermanage.service';
import { Logger } from 'src/app/services/logger/logger.service';
import { Throttle } from 'src/app/util/throttle';
import { UtilService } from 'src/app/util/util.service';
@Component({
@@ -96,7 +97,7 @@ export class SettingsUsersComponent implements OnInit {
@AutoUnsubscribe()
private subscribeToUpdate() {
return this.updateSubject
.pipe(throttleTime(500, undefined, { leading: true, trailing: true }))
.pipe(Throttle(500))
.subscribe(async (pageEvent: PageEvent) => {
let success = await this.fetchUsers(
pageEvent.pageSize,

View File

@@ -59,13 +59,11 @@ export class InfoService {
if (serverDecoded[0] === '0' || clientDecoded[0] === '0') {
if (serverVersion !== clientVersion) {
console.log('a');
return false;
} else {
return true;
}
} else {
console.log('b');
return serverDecoded[0] === clientDecoded[0];
}
}

View File

@@ -3,6 +3,7 @@ import { AutoUnsubscribe } from 'ngx-auto-unsubscribe-decorator';
import { UserMePermissionsResponse } from 'picsur-shared/dist/dto/api/user.dto';
import { AsyncFailable, HasFailed } from 'picsur-shared/dist/types';
import { BehaviorSubject, filter, map, Observable, take } from 'rxjs';
import { Throttle } from 'src/app/util/throttle';
import { Logger } from '../logger/logger.service';
import { ApiService } from './api.service';
import { StaticInfoService } from './static-info.service';
@@ -55,7 +56,7 @@ export class PermissionService {
@AutoUnsubscribe()
private subscribeUser() {
return this.userService.live.subscribe(async (user) => {
return this.userService.live.pipe(Throttle(300)).subscribe(async (user) => {
const permissions = await this.updatePermissions();
if (HasFailed(permissions)) {
this.logger.warn(permissions.getReason());

View File

@@ -14,6 +14,7 @@ import {
import { AsyncFailable, Fail, HasFailed, Map } from 'picsur-shared/dist/types';
import { BehaviorSubject } from 'rxjs';
import { SnackBarType } from 'src/app/models/dto/snack-bar-type.dto';
import { Throttle } from 'src/app/util/throttle';
import { UtilService } from 'src/app/util/util.service';
import { Logger } from '../logger/logger.service';
import { ApiService } from './api.service';
@@ -43,10 +44,9 @@ export class SysPrefService {
private utilService: UtilService
) {
this.subscribePermissions();
this.init().catch(this.logger.error);
}
private async init() {
private async refresh() {
const result = await this.getPreferences();
if (HasFailed(result)) {
this.utilService.showSnackBar(
@@ -126,11 +126,18 @@ export class SysPrefService {
// We want to flush on logout, because the syspreferences can contain sensitive information
@AutoUnsubscribe()
private subscribePermissions() {
return this.permissionsService.live.subscribe((permissions) => {
this.hasPermission = permissions.includes(Permission.SysPrefManage);
if (!this.hasPermission) {
this.flush();
}
});
return this.permissionsService.live
.pipe(Throttle(300))
.subscribe((permissions) => {
const oldHasPermission = this.hasPermission;
this.hasPermission = permissions.includes(Permission.SysPrefManage);
if (!this.hasPermission) {
this.flush();
}
if (!oldHasPermission && this.hasPermission) {
this.refresh().catch(this.logger.error);
}
});
}
}

View File

@@ -14,6 +14,7 @@ import {
import { AsyncFailable, Fail, HasFailed, Map } from 'picsur-shared/dist/types';
import { BehaviorSubject } from 'rxjs';
import { SnackBarType } from 'src/app/models/dto/snack-bar-type.dto';
import { Throttle } from 'src/app/util/throttle';
import { UtilService } from 'src/app/util/util.service';
import { Logger } from '../logger/logger.service';
import { ApiService } from './api.service';
@@ -43,10 +44,9 @@ export class UsrPrefService {
private utilService: UtilService
) {
this.subscribePermissions();
this.init().catch(this.logger.error);
}
private async init() {
private async refresh() {
const result = await this.getPreferences();
if (HasFailed(result)) {
this.utilService.showSnackBar(
@@ -126,9 +126,12 @@ export class UsrPrefService {
// We want to flush on logout, because the syspreferences can contain sensitive information
@AutoUnsubscribe()
private subscribePermissions() {
return this.permissionsService.live.subscribe((permissions) => {
this.hasPermission = permissions.includes(Permission.Settings);
if (!this.hasPermission) this.flush();
});
return this.permissionsService.live
.pipe(Throttle(300))
.subscribe((permissions) => {
this.hasPermission = permissions.includes(Permission.Settings);
if (!this.hasPermission) this.flush();
else this.refresh().catch(this.logger.error);
});
}
}

View File

@@ -0,0 +1,3 @@
import { throttleTime } from 'rxjs';
export const Throttle = <T>(time: number) => throttleTime<T>(time, undefined, { leading: true, trailing: true });