add usrpreference entity, and refactor syspref

This commit is contained in:
rubikscraft
2022-04-01 10:31:00 +02:00
parent 7ddbc38ed1
commit ba2f361da3
15 changed files with 110 additions and 56 deletions

View File

@@ -1,10 +1,9 @@
import { Injectable, Logger } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { PrefValueType, PrefValueTypeStrings } from 'picsur-shared/dist/dto/preferences.dto';
import {
InternalSysprefRepresentation,
SysPreference,
SysPrefValueType,
SysPrefValueTypeStrings
InternalSysPrefRepresentation,
SysPreference
} from 'picsur-shared/dist/dto/syspreferences.dto';
import {
AsyncFailable,
@@ -33,8 +32,8 @@ export class SysPreferenceService {
public async setPreference(
key: string,
value: SysPrefValueType,
): AsyncFailable<InternalSysprefRepresentation> {
value: PrefValueType,
): AsyncFailable<InternalSysPrefRepresentation> {
// Validate
let sysPreference = await this.validatePref(key, value);
if (HasFailed(sysPreference)) return sysPreference;
@@ -61,7 +60,7 @@ export class SysPreferenceService {
public async getPreference(
key: string,
): AsyncFailable<InternalSysprefRepresentation> {
): AsyncFailable<InternalSysPrefRepresentation> {
// Validate
let validatedKey = this.validatePrefKey(key);
if (HasFailed(validatedKey)) return validatedKey;
@@ -108,8 +107,8 @@ export class SysPreferenceService {
private async getPreferencePinned(
key: string,
type: SysPrefValueTypeStrings,
): AsyncFailable<SysPrefValueType> {
type: PrefValueTypeStrings,
): AsyncFailable<PrefValueType> {
let pref = await this.getPreference(key);
if (HasFailed(pref)) return pref;
if (pref.type !== type) return Fail('Invalid preference type');
@@ -118,7 +117,7 @@ export class SysPreferenceService {
}
public async getAllPreferences(): AsyncFailable<
InternalSysprefRepresentation[]
InternalSysPrefRepresentation[]
> {
// TODO: We are fetching each value invidually, we should fetch all at once
let internalSysPrefs = await Promise.all(
@@ -128,21 +127,21 @@ export class SysPreferenceService {
return Fail('Could not get all preferences');
}
return internalSysPrefs as InternalSysprefRepresentation[];
return internalSysPrefs as InternalSysPrefRepresentation[];
}
// Private
private async saveDefault(
key: SysPreference, // Force enum here because we dont validate
): AsyncFailable<InternalSysprefRepresentation> {
): AsyncFailable<InternalSysPrefRepresentation> {
return this.setPreference(key, this.defaultsService.defaults[key]());
}
// This converts the raw string representation of the value to the correct type
private retrieveConvertedValue(
preference: ESysPreferenceBackend,
): Failable<InternalSysprefRepresentation> {
): Failable<InternalSysPrefRepresentation> {
const key = this.validatePrefKey(preference.key);
if (HasFailed(key)) return key;
@@ -173,7 +172,7 @@ export class SysPreferenceService {
private async validatePref(
key: string,
value: SysPrefValueType,
value: PrefValueType,
): AsyncFailable<ESysPreferenceBackend> {
const validatedKey = this.validatePrefKey(key);
if (HasFailed(validatedKey)) return validatedKey;
@@ -204,7 +203,7 @@ export class SysPreferenceService {
private validatePrefValue(
// Key is required, because the type of the value depends on the key
key: SysPreference,
value: SysPrefValueType,
value: PrefValueType,
): Failable<string> {
const expectedType = SysPreferenceValueTypes[key];

View File

@@ -1,7 +1,7 @@
import { Injectable, Logger } from '@nestjs/common';
import { PrefValueType } from 'picsur-shared/dist/dto/preferences.dto';
import {
SysPreference,
SysPrefValueType
SysPreference
} from 'picsur-shared/dist/dto/syspreferences.dto';
import { generateRandomString } from 'picsur-shared/dist/util/random';
import { EarlyJwtConfigService } from '../../config/early/earlyjwt.config.service';
@@ -16,7 +16,7 @@ export class SysPreferenceDefaultsService {
constructor(private jwtConfigService: EarlyJwtConfigService) {}
public readonly defaults: {
[key in SysPreference]: () => SysPrefValueType;
[key in SysPreference]: () => PrefValueType;
} = {
[SysPreference.JwtSecret]: () => {
const envSecret = this.jwtConfigService.getJwtSecret();

View File

@@ -1,14 +1,12 @@
import {
SysPreference,
SysPrefValueTypeStrings
} from 'picsur-shared/dist/dto/syspreferences.dto';
import { PrefValueTypeStrings } from 'picsur-shared/dist/dto/preferences.dto';
import { SysPreference } from 'picsur-shared/dist/dto/syspreferences.dto';
export type SysPreferences = SysPreference[];
export const SysPreferenceList: string[] = Object.values(SysPreference);
// Syspref Value types
export const SysPreferenceValueTypes: {
[key in SysPreference]: SysPrefValueTypeStrings;
[key in SysPreference]: PrefValueTypeStrings;
} = {
[SysPreference.JwtSecret]: 'string',
[SysPreference.JwtExpiresIn]: 'string',

View File

@@ -0,0 +1,18 @@
import { EUsrPreference } from 'picsur-shared/dist/entities/usrpreference';
import { Column, Index, PrimaryGeneratedColumn } from 'typeorm';
export class EUsrPreferenceBackend extends EUsrPreference {
@PrimaryGeneratedColumn()
override id?: number;
@Index()
@Column({ nullable: false, unique: true })
override key: string;
@Column({ nullable: false })
override value: string;
@Index()
@Column({ nullable: false })
override userId: number;
}

View File

@@ -11,7 +11,7 @@ import {
GetSyspreferenceResponse,
MultipleSysPreferencesResponse, UpdateSysPreferenceRequest,
UpdateSysPreferenceResponse
} from 'picsur-shared/dist/dto/api/pref.dto';
} from 'picsur-shared/dist/dto/api/syspref.dto';
import { HasFailed } from 'picsur-shared/dist/types';
import { SysPreferenceService } from '../../../collections/syspreferencesdb/syspreferencedb.service';
import { RequiredPermissions } from '../../../decorators/permissions.decorator';

View File

@@ -1,5 +1,5 @@
import { Component } from '@angular/core';
import { SysPreferenceBaseResponse } from 'picsur-shared/dist/dto/api/pref.dto';
import { SysPreferenceBaseResponse } from 'picsur-shared/dist/dto/api/syspref.dto';
import { Observable } from 'rxjs';
import { SysprefService as SysPrefService } from 'src/app/services/api/syspref.service';

View File

@@ -1,10 +1,8 @@
import { Component, Input, OnInit } from '@angular/core';
import { AutoUnsubscribe } from 'ngx-auto-unsubscribe-decorator';
import { SysPreferenceBaseResponse } from 'picsur-shared/dist/dto/api/pref.dto';
import {
SysPreference,
SysPrefValueType
} from 'picsur-shared/dist/dto/syspreferences.dto';
import { SysPreferenceBaseResponse } from 'picsur-shared/dist/dto/api/syspref.dto';
import { 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 { SysPreferenceFriendlyNames } from 'src/app/i18n/syspref.i18n';
@@ -20,7 +18,7 @@ import { UtilService } from 'src/app/util/util.service';
export class SettingsSysprefOptionComponent implements OnInit {
@Input() pref: SysPreferenceBaseResponse;
private updateSubject = new Subject<SysPrefValueType>();
private updateSubject = new Subject<PrefValueType>();
constructor(
private sysprefService: SysprefService,
@@ -71,7 +69,7 @@ export class SettingsSysprefOptionComponent implements OnInit {
this.update((e.target as HTMLInputElement).valueAsNumber);
}
private async updatePreference(value: SysPrefValueType) {
private async updatePreference(value: PrefValueType) {
const result = await this.sysprefService.setPreference(
this.pref.key,
value

View File

@@ -28,11 +28,12 @@ export class InfoService {
private infoSubject = new BehaviorSubject<ServerInfo>(new ServerInfo());
constructor(private api: ApiService, private utilService: UtilService) {
this.pollInfo()
.then(() => {
this.checkCompatibility();
})
.catch(this.logger.error);
this.init().catch(this.logger.error);
}
private async init() {
await this.pollInfo();
this.checkCompatibility();
}
public async pollInfo(): AsyncFailable<ServerInfo> {

View File

@@ -6,9 +6,9 @@ import {
SysPreferenceBaseResponse,
UpdateSysPreferenceRequest,
UpdateSysPreferenceResponse
} from 'picsur-shared/dist/dto/api/pref.dto';
} from 'picsur-shared/dist/dto/api/syspref.dto';
import { Permission } from 'picsur-shared/dist/dto/permissions.dto';
import { SysPrefValueType } from 'picsur-shared/dist/dto/syspreferences.dto';
import { PrefValueType } from 'picsur-shared/dist/dto/preferences.dto';
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';
@@ -67,7 +67,7 @@ export class SysprefService {
);
return Map(response, (pref) => {
this.sysprefObservable.next(pref.preferences)
this.sysprefObservable.next(pref.preferences);
return pref.preferences;
});
}
@@ -89,7 +89,7 @@ export class SysprefService {
public async setPreference(
key: string,
value: SysPrefValueType
value: PrefValueType
): AsyncFailable<UpdateSysPreferenceResponse> {
if (!this.hasPermission)
return Fail('You do not have permission to edit system preferences');

View File

@@ -4,7 +4,7 @@ import {
} from 'class-validator';
import { IsPosInt } from '../../validators/positive-int.validator';
import { IsSysPrefValue } from '../../validators/syspref.validator';
import { SysPrefValueType, SysPrefValueTypes, SysPrefValueTypeStrings } from '../syspreferences.dto';
import { PrefValueType, PrefValueTypes, PrefValueTypeStrings } from '../preferences.dto';
export class SysPreferenceBaseResponse {
@IsNotEmpty()
@@ -13,11 +13,11 @@ export class SysPreferenceBaseResponse {
@IsNotEmpty()
@IsSysPrefValue()
value: SysPrefValueType;
value: PrefValueType;
@IsNotEmpty()
@IsEnum(SysPrefValueTypes)
type: SysPrefValueTypeStrings;
@IsEnum(PrefValueTypes)
type: PrefValueTypeStrings;
}
// Get Syspreference
@@ -40,7 +40,7 @@ export class MultipleSysPreferencesResponse {
export class UpdateSysPreferenceRequest {
@IsNotEmpty()
@IsSysPrefValue()
value: SysPrefValueType;
value: PrefValueType;
}
export class UpdateSysPreferenceResponse extends SysPreferenceBaseResponse {}

View File

@@ -0,0 +1,4 @@
// Variable value type
export type PrefValueType = string | number | boolean;
export type PrefValueTypeStrings = 'string' | 'number' | 'boolean';
export const PrefValueTypes = ['string', 'number', 'boolean'];

View File

@@ -1,3 +1,5 @@
import { PrefValueType, PrefValueTypeStrings } from './preferences.dto';
// This enum is only here to make accessing the values easier, and type checking in the backend
export enum SysPreference {
JwtSecret = 'jwt_secret',
@@ -8,14 +10,9 @@ export enum SysPreference {
TestBoolean = 'test_boolean',
}
// Variable value type
export type SysPrefValueType = string | number | boolean;
export type SysPrefValueTypeStrings = 'string' | 'number' | 'boolean';
export const SysPrefValueTypes = ['string', 'number', 'boolean'];
// Interfaces
export interface InternalSysprefRepresentation {
export interface InternalSysPrefRepresentation {
key: string;
value: SysPrefValueType;
type: SysPrefValueTypeStrings;
value: PrefValueType;
type: PrefValueTypeStrings;
}

View File

@@ -0,0 +1,19 @@
import { PrefValueType, PrefValueTypeStrings } from './preferences.dto';
// This enum is only here to make accessing the values easier, and type checking in the backend
export enum UsrPreference {
JwtSecret = 'jwt_secret',
JwtExpiresIn = 'jwt_expires_in',
BCryptStrength = 'bcrypt_strength',
TestString = 'test_string',
TestNumber = 'test_number',
TestBoolean = 'test_boolean',
}
// Interfaces
export interface InternalUsrPrefRepresentation {
key: string;
value: PrefValueType;
type: PrefValueTypeStrings;
user: number;
}

View File

@@ -0,0 +1,20 @@
import { IsDefined, IsNotEmpty, IsString } from 'class-validator';
import { EntityID } from '../validators/entity-id.validator';
import { IsPosInt } from '../validators/positive-int.validator';
export class EUsrPreference {
@EntityID()
id?: number;
@IsNotEmpty()
@IsString()
key: string;
@IsNotEmpty()
@IsString()
value: string;
@IsDefined()
@IsPosInt()
userId: number;
}

View File

@@ -1,9 +1,9 @@
import { registerDecorator, ValidationArguments, ValidationOptions } from 'class-validator';
import { SysPrefValueTypes } from '../dto/syspreferences.dto';
import { PrefValueTypes } from '../dto/preferences.dto';
export function isSysPrefValue(value: any, args: ValidationArguments) {
const type = typeof value;
return SysPrefValueTypes.includes(type);
return PrefValueTypes.includes(type);
}
export function IsSysPrefValue(validationOptions?: ValidationOptions) {