mirror of
https://github.com/CaramelFur/Picsur.git
synced 2025-10-26 06:56:06 +01:00
add userprefs to frontend
This commit is contained in:
@@ -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',
|
||||
);
|
||||
|
||||
@@ -57,7 +57,7 @@ export class UsersModule implements OnModuleInit {
|
||||
username,
|
||||
password,
|
||||
roles,
|
||||
false,
|
||||
true,
|
||||
);
|
||||
if (HasFailed(newUser)) {
|
||||
this.logger.error(
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -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 {}
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
3
frontend/src/app/util/throttle.ts
Normal file
3
frontend/src/app/util/throttle.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
import { throttleTime } from 'rxjs';
|
||||
|
||||
export const Throttle = <T>(time: number) => throttleTime<T>(time, undefined, { leading: true, trailing: true });
|
||||
Reference in New Issue
Block a user