refactor api dto's

This commit is contained in:
rubikscraft
2022-03-24 16:14:14 +01:00
parent 6417651419
commit 25b85c00e0
13 changed files with 90 additions and 86 deletions

View File

@@ -9,9 +9,11 @@ import {
} from '@nestjs/common'; } from '@nestjs/common';
import { plainToClass } from 'class-transformer'; import { plainToClass } from 'class-transformer';
import { import {
GetSyspreferenceResponse,
MultipleSysPreferencesResponse, MultipleSysPreferencesResponse,
SysPreferenceResponse, SysPreferenceBaseResponse,
UpdateSysPreferenceRequest UpdateSysPreferenceRequest,
UpdateSysPreferenceResponse
} from 'picsur-shared/dist/dto/api/pref.dto'; } from 'picsur-shared/dist/dto/api/pref.dto';
import { Permission } from 'picsur-shared/dist/dto/permissions'; import { Permission } from 'picsur-shared/dist/dto/permissions';
import { SysPreferences } from 'picsur-shared/dist/dto/syspreferences.dto'; import { SysPreferences } from 'picsur-shared/dist/dto/syspreferences.dto';
@@ -36,28 +38,30 @@ export class PrefController {
const returned = new MultipleSysPreferencesResponse(); const returned = new MultipleSysPreferencesResponse();
returned.preferences = prefs.map((pref) => returned.preferences = prefs.map((pref) =>
plainToClass(SysPreferenceResponse, pref), plainToClass(SysPreferenceBaseResponse, pref),
); );
return returned; return returned;
} }
@Get('sys/:key') @Get('sys/:key')
async getSysPref(@Param('key') key: string): Promise<SysPreferenceResponse> { async getSysPref(
@Param('key') key: string,
): Promise<GetSyspreferenceResponse> {
const pref = await this.prefService.getPreference(key as SysPreferences); const pref = await this.prefService.getPreference(key as SysPreferences);
if (HasFailed(pref)) { if (HasFailed(pref)) {
this.logger.warn(pref.getReason()); this.logger.warn(pref.getReason());
throw new InternalServerErrorException('Could not get preference'); throw new InternalServerErrorException('Could not get preference');
} }
return plainToClass(SysPreferenceResponse, pref); return plainToClass(GetSyspreferenceResponse, pref);
} }
@Post('sys/:key') @Post('sys/:key')
async setSysPref( async setSysPref(
@Param('key') key: string, @Param('key') key: string,
@Body() body: UpdateSysPreferenceRequest, @Body() body: UpdateSysPreferenceRequest,
): Promise<SysPreferenceResponse> { ): Promise<UpdateSysPreferenceResponse> {
const value = body.value; const value = body.value;
const pref = await this.prefService.setPreference( const pref = await this.prefService.setPreference(
@@ -69,7 +73,7 @@ export class PrefController {
throw new InternalServerErrorException('Could not set preference'); throw new InternalServerErrorException('Could not set preference');
} }
const returned = new SysPreferenceResponse(); const returned = new UpdateSysPreferenceResponse();
returned.key = key as SysPreferences; returned.key = key as SysPreferences;
returned.value = pref.value; returned.value = pref.value;
returned.type = pref.type; returned.type = pref.type;

View File

@@ -1,6 +1,6 @@
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { AutoUnsubscribe } from 'ngx-auto-unsubscribe-decorator'; import { AutoUnsubscribe } from 'ngx-auto-unsubscribe-decorator';
import { SysPreferenceResponse } from 'picsur-shared/dist/dto/api/pref.dto'; import { SysPreferenceBaseResponse } from 'picsur-shared/dist/dto/api/pref.dto';
import { HasFailed } from 'picsur-shared/dist/types'; import { HasFailed } from 'picsur-shared/dist/types';
import { SnackBarType } from 'src/app/models/snack-bar-type'; import { SnackBarType } from 'src/app/models/snack-bar-type';
import { SysprefService as SysPrefService } from 'src/app/services/api/syspref.service'; import { SysprefService as SysPrefService } from 'src/app/services/api/syspref.service';
@@ -11,7 +11,7 @@ import { UtilService } from 'src/app/util/util.service';
}) })
export class SettingsSysprefComponent implements OnInit { export class SettingsSysprefComponent implements OnInit {
render = true; render = true;
preferences: SysPreferenceResponse[] = []; preferences: SysPreferenceBaseResponse[] = [];
constructor( constructor(
private sysprefService: SysPrefService, private sysprefService: SysPrefService,

View File

@@ -1,6 +1,6 @@
import { Component, Input, OnInit } from '@angular/core'; import { Component, Input, OnInit } from '@angular/core';
import { AutoUnsubscribe } from 'ngx-auto-unsubscribe-decorator'; import { AutoUnsubscribe } from 'ngx-auto-unsubscribe-decorator';
import { SysPreferenceResponse } from 'picsur-shared/dist/dto/api/pref.dto'; import { SysPreferenceBaseResponse } from 'picsur-shared/dist/dto/api/pref.dto';
import { import {
SysPreferenceFriendlyNames, SysPreferenceFriendlyNames,
SysPrefValueType SysPrefValueType
@@ -17,7 +17,7 @@ import { UtilService } from 'src/app/util/util.service';
styleUrls: ['./settings-syspref-option.component.scss'], styleUrls: ['./settings-syspref-option.component.scss'],
}) })
export class SettingsSysprefOptionComponent implements OnInit { export class SettingsSysprefOptionComponent implements OnInit {
@Input() pref: SysPreferenceResponse; @Input() pref: SysPreferenceBaseResponse;
private updateSubject = new Subject<SysPrefValueType>(); private updateSubject = new Subject<SysPrefValueType>();

View File

@@ -1,9 +1,11 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { AutoUnsubscribe } from 'ngx-auto-unsubscribe-decorator'; import { AutoUnsubscribe } from 'ngx-auto-unsubscribe-decorator';
import { import {
GetSyspreferenceResponse,
MultipleSysPreferencesResponse, MultipleSysPreferencesResponse,
SysPreferenceResponse, SysPreferenceBaseResponse,
UpdateSysPreferenceRequest UpdateSysPreferenceRequest,
UpdateSysPreferenceResponse
} from 'picsur-shared/dist/dto/api/pref.dto'; } from 'picsur-shared/dist/dto/api/pref.dto';
import { Permission } from 'picsur-shared/dist/dto/permissions'; import { Permission } from 'picsur-shared/dist/dto/permissions';
import { import {
@@ -29,7 +31,7 @@ export class SysprefService {
return this.sysprefObservable; return this.sysprefObservable;
} }
private sysprefObservable = new BehaviorSubject<SysPreferenceResponse[]>([]); private sysprefObservable = new BehaviorSubject<SysPreferenceBaseResponse[]>([]);
constructor( constructor(
private api: ApiService, private api: ApiService,
@@ -38,7 +40,7 @@ export class SysprefService {
this.onPermissions(); this.onPermissions();
} }
public async getPreferences(): AsyncFailable<SysPreferenceResponse[]> { public async getPreferences(): AsyncFailable<SysPreferenceBaseResponse[]> {
if (!this.hasPermission) if (!this.hasPermission)
return Fail('You do not have permission to edit system preferences'); return Fail('You do not have permission to edit system preferences');
@@ -57,12 +59,12 @@ export class SysprefService {
public async getPreference( public async getPreference(
key: SysPreferences key: SysPreferences
): AsyncFailable<SysPreferenceResponse> { ): AsyncFailable<GetSyspreferenceResponse> {
if (!this.hasPermission) if (!this.hasPermission)
return Fail('You do not have permission to edit system preferences'); return Fail('You do not have permission to edit system preferences');
const response = await this.api.get( const response = await this.api.get(
SysPreferenceResponse, GetSyspreferenceResponse,
`/api/pref/sys/${key}` `/api/pref/sys/${key}`
); );
if (HasFailed(response)) { if (HasFailed(response)) {
@@ -77,13 +79,13 @@ export class SysprefService {
public async setPreference( public async setPreference(
key: SysPreferences, key: SysPreferences,
value: SysPrefValueType value: SysPrefValueType
): AsyncFailable<SysPreferenceResponse> { ): AsyncFailable<UpdateSysPreferenceResponse> {
if (!this.hasPermission) if (!this.hasPermission)
return Fail('You do not have permission to edit system preferences'); return Fail('You do not have permission to edit system preferences');
const response = await this.api.post( const response = await this.api.post(
UpdateSysPreferenceRequest, UpdateSysPreferenceRequest,
SysPreferenceResponse, UpdateSysPreferenceResponse,
`/api/pref/sys/${key}`, `/api/pref/sys/${key}`,
{ value } { value }
); );
@@ -96,7 +98,7 @@ export class SysprefService {
return response; return response;
} }
private updatePrefArray(pref: SysPreferenceResponse) { private updatePrefArray(pref: SysPreferenceBaseResponse) {
const prefArray = this.snapshot; const prefArray = this.snapshot;
// Replace the old pref with the new one // Replace the old pref with the new one
const index = prefArray.findIndex((i) => pref.key === i.key); const index = prefArray.findIndex((i) => pref.key === i.key);
@@ -112,7 +114,7 @@ export class SysprefService {
private sync() { private sync() {
this.sysprefObservable.next( this.sysprefObservable.next(
([] as SysPreferenceResponse[]).concat(this.snapshot) ([] as SysPreferenceBaseResponse[]).concat(this.snapshot)
); );
} }

View File

@@ -1 +0,0 @@
export * from './api.dto';

View File

@@ -1,24 +1,17 @@
import { Type } from 'class-transformer'; import { Type } from 'class-transformer';
import { import {
IsArray, IsArray, IsEnum, IsNotEmpty, ValidateNested
IsEnum,
IsNotEmpty, ValidateNested
} from 'class-validator'; } from 'class-validator';
import { IsPosInt } from '../../validators/positive-int.validator';
import { IsSysPrefValue } from '../../validators/syspref.validator';
import { import {
IsSysPrefValue,
SysPreferences, SysPreferences,
SysPrefValueType, SysPrefValueType,
SysPrefValueTypes, SysPrefValueTypes,
SysPrefValueTypeStrings SysPrefValueTypeStrings
} from '../syspreferences.dto'; } from '../syspreferences.dto';
export class UpdateSysPreferenceRequest { export class SysPreferenceBaseResponse {
@IsNotEmpty()
@IsSysPrefValue()
value: SysPrefValueType;
}
export class SysPreferenceResponse {
@IsNotEmpty() @IsNotEmpty()
@IsEnum(SysPreferences) @IsEnum(SysPreferences)
key: SysPreferences; key: SysPreferences;
@@ -32,10 +25,28 @@ export class SysPreferenceResponse {
type: SysPrefValueTypeStrings; type: SysPrefValueTypeStrings;
} }
// Get Syspreference
// Request is done via url parameters
export class GetSyspreferenceResponse extends SysPreferenceBaseResponse {}
// Get syspreferences
export class MultipleSysPreferencesResponse { export class MultipleSysPreferencesResponse {
@IsArray() @IsArray()
@IsNotEmpty() @IsNotEmpty()
@ValidateNested({ each: true }) @ValidateNested({ each: true })
@Type(() => SysPreferenceResponse) @Type(() => SysPreferenceBaseResponse)
preferences: SysPreferenceResponse[]; preferences: SysPreferenceBaseResponse[];
@IsPosInt()
total: number;
} }
// Update Syspreference
export class UpdateSysPreferenceRequest {
@IsNotEmpty()
@IsSysPrefValue()
value: SysPrefValueType;
}
export class UpdateSysPreferenceResponse extends SysPreferenceBaseResponse {}

View File

@@ -1,15 +1,14 @@
import { Type } from 'class-transformer'; import { Type } from 'class-transformer';
import { import {
IsArray, IsArray,
IsDefined, IsDefined, ValidateNested
IsInt, IsPositive,
ValidateNested
} from 'class-validator'; } from 'class-validator';
import { import {
ERole, ERole,
RoleNameObject, RoleNameObject,
RoleNamePermsObject RoleNamePermsObject
} from '../../entities/role.entity'; } from '../../entities/role.entity';
import { IsPosInt } from '../../validators/positive-int.validator';
// RoleInfo // RoleInfo
export class RoleInfoRequest extends RoleNameObject {} export class RoleInfoRequest extends RoleNameObject {}
@@ -23,9 +22,7 @@ export class RoleListResponse {
@Type(() => ERole) @Type(() => ERole)
roles: ERole[]; roles: ERole[];
@IsInt() @IsPosInt()
@IsPositive()
@IsDefined()
total: number; total: number;
} }

View File

@@ -1,7 +1,7 @@
import { Type } from 'class-transformer'; import { Type } from 'class-transformer';
import { import {
IsArray, IsDefined, IsArray, IsDefined,
IsEnum, IsString, IsEnum, IsJWT, IsString,
ValidateNested ValidateNested
} from 'class-validator'; } from 'class-validator';
import { EUser, NamePassUser } from '../../entities/user.entity'; import { EUser, NamePassUser } from '../../entities/user.entity';
@@ -15,6 +15,7 @@ export class UserLoginRequest extends NamePassUser {}
export class UserLoginResponse { export class UserLoginResponse {
@IsString() @IsString()
@IsDefined() @IsDefined()
@IsJWT()
jwt_token: string; jwt_token: string;
} }
@@ -32,6 +33,7 @@ export class UserMeResponse {
@IsString() @IsString()
@IsDefined() @IsDefined()
@IsJWT()
token: string; token: string;
} }

View File

@@ -1,27 +1,20 @@
import { Type } from 'class-transformer'; import { Type } from 'class-transformer';
import { import {
IsArray, IsArray,
IsDefined, IsDefined, IsOptional,
IsInt, IsString, ValidateNested
IsOptional,
IsString,
Min,
ValidateNested
} from 'class-validator'; } from 'class-validator';
import { EUser, NamePassUser, UsernameUser } from '../../entities/user.entity'; import { EUser, NamePassUser, UsernameUser } from '../../entities/user.entity';
import { IsPosInt } from '../../validators/positive-int.validator';
import { IsPlainTextPwd } from '../../validators/user.validators'; import { IsPlainTextPwd } from '../../validators/user.validators';
import { Roles } from '../roles.dto'; import { Roles } from '../roles.dto';
// UserList // UserList
export class UserListRequest { export class UserListRequest {
@IsDefined() @IsPosInt()
@IsInt()
@Min(0)
count: number; count: number;
@IsDefined() @IsPosInt()
@IsInt()
@Min(0)
page: number; page: number;
} }
@@ -32,14 +25,10 @@ export class UserListResponse {
@Type(() => EUser) @Type(() => EUser)
users: EUser[]; users: EUser[];
@IsDefined() @IsPosInt()
@IsInt()
@Min(0)
count: number; count: number;
@IsDefined() @IsPosInt()
@IsInt()
@Min(0)
page: number; page: number;
} }

View File

@@ -1,8 +1,3 @@
import {
registerDecorator,
ValidationArguments,
ValidationOptions
} from 'class-validator';
import tuple from '../types/tuple'; import tuple from '../types/tuple';
// Syspref keys // Syspref keys
@@ -46,24 +41,6 @@ export const SysPreferenceValueTypes: {
// Validators // Validators
export function isSysPrefValue(value: any, args: ValidationArguments) {
const type = typeof value;
return SysPrefValueTypes.includes(type);
}
export function IsSysPrefValue(validationOptions?: ValidationOptions) {
return function (object: Object, propertyName: string) {
registerDecorator({
name: 'isSysPrefValue',
target: object.constructor,
propertyName: propertyName,
options: validationOptions,
validator: {
validate: isSysPrefValue,
},
});
};
}
// interfaces // interfaces

View File

@@ -1,4 +1,2 @@
// Nothing export { };
const a = 'hello';
export default a;

View File

@@ -0,0 +1,4 @@
import { IsDefined, IsInt, Min } from 'class-validator';
import { ComposeValidators } from './compose.validator';
export const IsPosInt = ComposeValidators(IsInt(), Min(0), IsDefined());

View File

@@ -0,0 +1,21 @@
import { registerDecorator, ValidationArguments, ValidationOptions } from 'class-validator';
import { SysPrefValueTypes } from '../dto/syspreferences.dto';
export function isSysPrefValue(value: any, args: ValidationArguments) {
const type = typeof value;
return SysPrefValueTypes.includes(type);
}
export function IsSysPrefValue(validationOptions?: ValidationOptions) {
return function (object: Object, propertyName: string) {
registerDecorator({
name: 'isSysPrefValue',
target: object.constructor,
propertyName: propertyName,
options: validationOptions,
validator: {
validate: isSysPrefValue,
},
});
};
}