mvoe syspref to backend

This commit is contained in:
rubikscraft 2022-03-27 22:33:13 +02:00
parent 2c150c3027
commit ac98db10df
No known key found for this signature in database
GPG key ID: 1463EBE9200A5CD4
17 changed files with 105 additions and 114 deletions

View file

@ -3,8 +3,7 @@ import { InjectRepository } from '@nestjs/typeorm';
import { plainToClass } from 'class-transformer';
import {
InternalSysprefRepresentation,
SysPreferences,
SysPreferenceValueTypes,
SysPreference,
SysPrefValueType
} from 'picsur-shared/dist/dto/syspreferences.dto';
import {
@ -15,6 +14,10 @@ import {
} from 'picsur-shared/dist/types';
import { strictValidate } from 'picsur-shared/dist/util/validate';
import { Repository } from 'typeorm';
import {
SysPreferenceList,
SysPreferenceValueTypes
} from '../../models/dto/syspreferences.dto';
import { ESysPreferenceBackend } from '../../models/entities/syspreference.entity';
import { SysPreferenceDefaultsService } from './syspreferencedefaults.service';
@ -29,7 +32,7 @@ export class SysPreferenceService {
) {}
public async setPreference(
key: SysPreferences,
key: string,
value: SysPrefValueType,
): AsyncFailable<InternalSysprefRepresentation> {
// Validate
@ -50,12 +53,13 @@ export class SysPreferenceService {
return {
key: sysPreference.key,
value,
type: SysPreferenceValueTypes[key],
// key has to be valid here, we validated it
type: SysPreferenceValueTypes[key as SysPreference],
};
}
public async getPreference(
key: SysPreferences,
key: string,
): AsyncFailable<InternalSysprefRepresentation> {
// Validate
let validatedKey = this.validatePrefKey(key);
@ -92,7 +96,7 @@ export class SysPreferenceService {
return this.retrieveConvertedValue(foundSysPreference);
}
public async getStringPreference(key: SysPreferences): AsyncFailable<string> {
public async getStringPreference(key: string): AsyncFailable<string> {
const pref = await this.getPreference(key);
if (HasFailed(pref)) return pref;
if (pref.type !== 'string') return Fail('Invalid preference type');
@ -100,7 +104,7 @@ export class SysPreferenceService {
return pref.value as string;
}
public async getNumberPreference(key: SysPreferences): AsyncFailable<number> {
public async getNumberPreference(key: string): AsyncFailable<number> {
const pref = await this.getPreference(key);
if (HasFailed(pref)) return pref;
if (pref.type !== 'number') return Fail('Invalid preference type');
@ -108,9 +112,7 @@ export class SysPreferenceService {
return pref.value as number;
}
public async getBooleanPreference(
key: SysPreferences,
): AsyncFailable<boolean> {
public async getBooleanPreference(key: string): AsyncFailable<boolean> {
const pref = await this.getPreference(key);
if (HasFailed(pref)) return pref;
if (pref.type !== 'boolean') return Fail('Invalid preference type');
@ -122,7 +124,7 @@ export class SysPreferenceService {
InternalSysprefRepresentation[]
> {
let internalSysPrefs = await Promise.all(
SysPreferences.map((key) => this.getPreference(key as SysPreferences)),
SysPreferenceList.map((key) => this.getPreference(key)),
);
if (internalSysPrefs.some((pref) => HasFailed(pref))) {
return Fail('Could not get all preferences');
@ -133,7 +135,7 @@ export class SysPreferenceService {
// Private
private async saveDefault(
key: SysPreferences,
key: SysPreference, // Force enum here because we dont validate
): AsyncFailable<InternalSysprefRepresentation> {
return this.setPreference(key, this.defaultsService.defaults[key]());
}
@ -141,7 +143,10 @@ export class SysPreferenceService {
private retrieveConvertedValue(
preference: ESysPreferenceBackend,
): Failable<InternalSysprefRepresentation> {
const type = SysPreferenceValueTypes[preference.key];
const key = this.validatePrefKey(preference.key);
if (HasFailed(key)) return key;
const type = SysPreferenceValueTypes[key];
switch (type) {
case 'string':
return {
@ -190,16 +195,16 @@ export class SysPreferenceService {
return verifySysPreference;
}
private validatePrefKey(key: string): Failable<SysPreferences> {
if (!SysPreferences.includes(key)) {
private validatePrefKey(key: string): Failable<SysPreference> {
if (!SysPreferenceList.includes(key)) {
return Fail('Invalid preference key');
}
return key as SysPreferences;
return key as SysPreference;
}
private validatePrefValue(
key: SysPreferences,
key: SysPreference,
value: SysPrefValueType,
): Failable<string> {
const expectedType = SysPreferenceValueTypes[key];

View file

@ -1,6 +1,6 @@
import { Injectable, Logger } from '@nestjs/common';
import {
SysPreferences,
SysPreference,
SysPrefValueType
} from 'picsur-shared/dist/dto/syspreferences.dto';
import { generateRandomString } from 'picsur-shared/dist/util/random';
@ -13,9 +13,9 @@ export class SysPreferenceDefaultsService {
constructor(private jwtConfigService: EnvJwtConfigService) {}
public readonly defaults: {
[key in SysPreferences]: () => SysPrefValueType;
[key in SysPreference]: () => SysPrefValueType;
} = {
jwt_secret: () => {
[SysPreference.JwtSecret]: () => {
const envSecret = this.jwtConfigService.getJwtSecret();
if (envSecret) {
return envSecret;
@ -26,10 +26,10 @@ export class SysPreferenceDefaultsService {
return generateRandomString(64);
}
},
jwt_expires_in: () => this.jwtConfigService.getJwtExpiresIn() ?? '7d',
[SysPreference.JwtExpiresIn]: () => this.jwtConfigService.getJwtExpiresIn() ?? '7d',
test_string: () => 'test_string',
test_number: () => 123,
test_boolean: () => true,
[SysPreference.TestString]: () => 'test_string',
[SysPreference.TestNumber]: () => 123,
[SysPreference.TestBoolean]: () => true,
};
}

View file

@ -6,5 +6,4 @@ export { Permission } from 'picsur-shared/dist/dto/permissions.dto';
// Derivatives
export const PermissionsList: Permission[] = Object.values(Permission);
export type Permissions = Permission[];

View file

@ -0,0 +1,19 @@
import {
SysPreference,
SysPrefValueTypeStrings
} from 'picsur-shared/dist/dto/syspreferences.dto';
export type SysPreferences = SysPreference[];
export const SysPreferenceList: string[] = Object.values(SysPreference);
// Syspref Values
export const SysPreferenceValueTypes: {
[key in SysPreference]: SysPrefValueTypeStrings;
} = {
[SysPreference.JwtSecret]: 'string',
[SysPreference.JwtExpiresIn]: 'string',
[SysPreference.TestString]: 'string',
[SysPreference.TestNumber]: 'number',
[SysPreference.TestBoolean]: 'boolean',
};

View file

@ -1,4 +1,3 @@
import { SysPreferences } from 'picsur-shared/dist/dto/syspreferences.dto';
import { ESysPreference } from 'picsur-shared/dist/entities/syspreference.entity';
import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';
@ -8,7 +7,7 @@ export class ESysPreferenceBackend extends ESysPreference {
override id?: number;
@Column({ nullable: false, unique: true })
override key: SysPreferences;
override key: string;
@Column({ nullable: false })
override value: string;

View file

@ -1,7 +1,6 @@
import { Controller, Get } from '@nestjs/common';
import { plainToClass } from 'class-transformer';
import { InfoResponse } from 'picsur-shared/dist/dto/api/info.dto';
import { AllPermissionsResponse } from 'picsur-shared/dist/dto/api/roles.dto';
import { AllPermissionsResponse, InfoResponse } from 'picsur-shared/dist/dto/api/info.dto';
import { HostConfigService } from '../../../config/host.config.service';
import { NoPermissions } from '../../../decorators/permissions.decorator';
import { PermissionsList } from '../../../models/dto/permissions.dto';

View file

@ -15,7 +15,6 @@ import {
UpdateSysPreferenceRequest,
UpdateSysPreferenceResponse
} from 'picsur-shared/dist/dto/api/pref.dto';
import { SysPreferences } from 'picsur-shared/dist/dto/syspreferences.dto';
import { HasFailed } from 'picsur-shared/dist/types';
import { SysPreferenceService } from '../../../collections/syspreferencesdb/syspreferencedb.service';
import { RequiredPermissions } from '../../../decorators/permissions.decorator';
@ -50,7 +49,7 @@ export class PrefController {
async getSysPref(
@Param('key') key: string,
): Promise<GetSyspreferenceResponse> {
const pref = await this.prefService.getPreference(key as SysPreferences);
const pref = await this.prefService.getPreference(key);
if (HasFailed(pref)) {
this.logger.warn(pref.getReason());
throw new InternalServerErrorException('Could not get preference');
@ -66,20 +65,18 @@ export class PrefController {
): Promise<UpdateSysPreferenceResponse> {
const value = body.value;
const pref = await this.prefService.setPreference(
key as SysPreferences,
value,
);
const pref = await this.prefService.setPreference(key, value);
if (HasFailed(pref)) {
this.logger.warn(pref.getReason());
throw new InternalServerErrorException('Could not set preference');
}
const returned = new UpdateSysPreferenceResponse();
returned.key = key as SysPreferences;
returned.value = pref.value;
returned.type = pref.type;
const returned = {
key,
value: pref.value,
type: pref.type,
};
return returned;
return plainToClass(UpdateSysPreferenceResponse, returned);
}
}

View file

@ -0,0 +1,11 @@
import { SysPreference } from 'picsur-shared/dist/dto/syspreferences.dto';
export const SysPreferenceFriendlyNames: {
[key in SysPreference]: string;
} = {
[SysPreference.JwtSecret]: 'JWT Secret',
[SysPreference.JwtExpiresIn]: 'JWT Expiry Time',
[SysPreference.TestString]: 'Test String',
[SysPreference.TestNumber]: 'Test Number',
[SysPreference.TestBoolean]: 'Test Boolean',
};

View file

@ -1,12 +1,10 @@
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 {
SysPreferenceFriendlyNames,
SysPrefValueType
} from 'picsur-shared/dist/dto/syspreferences.dto';
import { SysPreference, SysPrefValueType } 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';
import { SnackBarType } from 'src/app/models/snack-bar-type';
import { SysprefService } from 'src/app/services/api/syspref.service';
import { UtilService } from 'src/app/util/util.service';
@ -31,7 +29,7 @@ export class SettingsSysprefOptionComponent implements OnInit {
}
get name(): string {
return SysPreferenceFriendlyNames[this.pref.key];
return SysPreferenceFriendlyNames[this.pref.key as SysPreference] ?? this.pref.key;
}
get valString(): string {

View file

@ -1,6 +1,6 @@
import { Injectable } from '@angular/core';
import { AutoUnsubscribe } from 'ngx-auto-unsubscribe-decorator';
import { AllPermissionsResponse } from 'picsur-shared/dist/dto/api/roles.dto';
import { AllPermissionsResponse } from 'picsur-shared/dist/dto/api/info.dto';
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';

View file

@ -8,15 +8,13 @@ import {
UpdateSysPreferenceResponse
} from 'picsur-shared/dist/dto/api/pref.dto';
import { Permission } from 'picsur-shared/dist/dto/permissions.dto';
import {
SysPreferences,
SysPrefValueType
} from 'picsur-shared/dist/dto/syspreferences.dto';
import { SysPrefValueType } from 'picsur-shared/dist/dto/syspreferences.dto';
import { AsyncFailable, Fail, HasFailed } from 'picsur-shared/dist/types';
import { BehaviorSubject } from 'rxjs';
import { ApiService } from './api.service';
import { PermissionService } from './permission.service';
@Injectable({
providedIn: 'root',
})
@ -60,7 +58,7 @@ export class SysprefService {
}
public async getPreference(
key: SysPreferences
key: string,
): AsyncFailable<GetSyspreferenceResponse> {
if (!this.hasPermission)
return Fail('You do not have permission to edit system preferences');
@ -79,7 +77,7 @@ export class SysprefService {
}
public async setPreference(
key: SysPreferences,
key: string,
value: SysPrefValueType
): AsyncFailable<UpdateSysPreferenceResponse> {
if (!this.hasPermission)

View file

@ -1,4 +1,5 @@
import { IsBoolean, IsDefined, IsSemVer, IsString } from 'class-validator';
import { IsStringList } from '../../validators/string-list.validator';
export class InfoResponse {
@IsBoolean()
@ -14,3 +15,10 @@ export class InfoResponse {
@IsSemVer()
version: string;
}
// AllPermissions
export class AllPermissionsResponse {
@IsDefined()
@IsStringList()
Permissions: string[];
}

View file

@ -1,20 +1,15 @@
import { Type } from 'class-transformer';
import {
IsArray, IsEnum, IsNotEmpty, ValidateNested
IsArray, IsEnum, IsNotEmpty, IsString, ValidateNested
} from 'class-validator';
import { IsPosInt } from '../../validators/positive-int.validator';
import { IsSysPrefValue } from '../../validators/syspref.validator';
import {
SysPreferences,
SysPrefValueType,
SysPrefValueTypes,
SysPrefValueTypeStrings
} from '../syspreferences.dto';
import { SysPrefValueType, SysPrefValueTypes, SysPrefValueTypeStrings } from '../syspreferences.dto';
export class SysPreferenceBaseResponse {
@IsNotEmpty()
@IsEnum(SysPreferences)
key: SysPreferences;
@IsString()
key: string;
@IsNotEmpty()
@IsSysPrefValue()

View file

@ -54,10 +54,3 @@ export class SpecialRolesResponse {
@IsStringList()
DefaultRoles: string[];
}
// AllPermissions
export class AllPermissionsResponse {
@IsDefined()
@IsStringList()
Permissions: string[];
}

View file

@ -1,4 +1,7 @@
// Only add no rename
// This enum only makes permissions easier to program,
// This does not have to be a complete list of all permissions
// -> the frontend and backend can be somewhat out of sync
export enum Permission {
ImageView = 'image-view',
ImageUpload = 'image-upload',

View file

@ -1,51 +1,19 @@
import tuple from '../types/tuple';
// Syspref keys
const SysPreferencesTuple = tuple(
'jwt_secret',
'jwt_expires_in',
'test_string',
'test_number',
'test_boolean',
);
export const SysPreferences: string[] = SysPreferencesTuple;
export type SysPreferences = typeof SysPreferencesTuple[number];
export const SysPreferenceFriendlyNames: {
[key in SysPreferences]: string;
} = {
jwt_secret: 'JWT Secret',
jwt_expires_in: 'JWT Expiry Time',
test_string: 'Test String',
test_number: 'Test Number',
test_boolean: 'Test Boolean',
};
// Syspref Values
export enum SysPreference {
JwtSecret = 'jwt_secret',
JwtExpiresIn = 'jwt_expires_in',
TestString = 'test_string',
TestNumber = 'test_number',
TestBoolean = 'test_boolean',
}
// Variable value type
export type SysPrefValueType = string | number | boolean;
export type SysPrefValueTypeStrings = 'string' | 'number' | 'boolean';
export const SysPrefValueTypes = ['string', 'number', 'boolean'];
export const SysPreferenceValueTypes: {
[key in SysPreferences]: SysPrefValueTypeStrings;
} = {
jwt_secret: 'string',
jwt_expires_in: 'string',
test_string: 'string',
test_number: 'number',
test_boolean: 'boolean',
};
// Validators
// interfaces
// Interfaces
export interface InternalSysprefRepresentation {
key: SysPreferences;
key: string;
value: SysPrefValueType;
type: SysPrefValueTypeStrings;
}

View file

@ -1,5 +1,4 @@
import { IsEnum, IsNotEmpty, IsString } from 'class-validator';
import { SysPreferences } from '../dto/syspreferences.dto';
import { IsNotEmpty, IsString } from 'class-validator';
import { EntityID } from '../validators/entity-id.validator';
export class ESysPreference {
@ -7,8 +6,8 @@ export class ESysPreference {
id?: number;
@IsNotEmpty()
@IsEnum(SysPreferences)
key: SysPreferences;
@IsString()
key: string;
@IsNotEmpty()
@IsString()