systempreference api done

This commit is contained in:
rubikscraft
2022-03-04 15:28:56 +01:00
parent 9db7ad51eb
commit be38075169
9 changed files with 113 additions and 52 deletions

View File

@@ -8,6 +8,7 @@ import { DemoManagerModule } from './managers/demo/demomanager.module';
import { EImageBackend } from './models/entities/image.entity'; import { EImageBackend } from './models/entities/image.entity';
import { EUserBackend } from './models/entities/user.entity'; import { EUserBackend } from './models/entities/user.entity';
import { PrefModule } from './routes/api/pref/pref.module'; import { PrefModule } from './routes/api/pref/pref.module';
import { ESysPreferenceBackend } from './models/entities/syspreference.entity';
@Module({ @Module({
imports: [ imports: [
@@ -20,7 +21,7 @@ import { PrefModule } from './routes/api/pref/pref.module';
database: Config.database.database, database: Config.database.database,
synchronize: true, synchronize: true,
entities: [EUserBackend, EImageBackend], entities: [EUserBackend, EImageBackend, ESysPreferenceBackend],
}), }),
ServeStaticModule.forRoot({ ServeStaticModule.forRoot({
rootPath: Config.static.frontendRoot, rootPath: Config.static.frontendRoot,
@@ -31,5 +32,4 @@ import { PrefModule } from './routes/api/pref/pref.module';
PrefModule, PrefModule,
], ],
}) })
export class AppModule { export class AppModule {}
}

View File

@@ -8,4 +8,4 @@ import { SysPreferenceService } from './syspreferencedb.service';
providers: [SysPreferenceService], providers: [SysPreferenceService],
exports: [SysPreferenceService], exports: [SysPreferenceService],
}) })
export class UsersModule {} export class SysPreferenceModule {}

View File

@@ -1,8 +1,9 @@
import { Injectable, Logger } from '@nestjs/common'; import { Injectable, Logger } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm'; import { InjectRepository } from '@nestjs/typeorm';
import { plainToClass } from 'class-transformer';
import { validate } from 'class-validator'; import { validate } from 'class-validator';
import { SysPreferences } from 'picsur-shared/dist/dto/syspreferences.dto'; import { SysPreferences } from 'picsur-shared/dist/dto/syspreferences.dto';
import { AsyncFailable, Fail } from 'picsur-shared/dist/types'; import { AsyncFailable, Fail, HasFailed } from 'picsur-shared/dist/types';
import { Repository } from 'typeorm'; import { Repository } from 'typeorm';
import { SysPreferenceDefaults } from '../../models/dto/syspreference.dto'; import { SysPreferenceDefaults } from '../../models/dto/syspreference.dto';
import { ESysPreferenceBackend } from '../../models/entities/syspreference.entity'; import { ESysPreferenceBackend } from '../../models/entities/syspreference.entity';
@@ -17,22 +18,15 @@ export class SysPreferenceService {
) {} ) {}
public async setPreference( public async setPreference(
key: SysPreferences, key: string,
value: string, value: string,
): AsyncFailable<ESysPreferenceBackend> { ): AsyncFailable<ESysPreferenceBackend> {
let sysPreference = new ESysPreferenceBackend(); let sysPreference = await this.validatePref(key, value);
sysPreference.key = key; if (HasFailed(sysPreference)) return sysPreference;
sysPreference.value = value;
const errors = await validate(sysPreference);
if (errors.length > 0) {
this.logger.warn(errors);
return Fail('Invalid preference');
}
try { try {
sysPreference = await this.sysPreferenceRepository.save(sysPreference, { await this.sysPreferenceRepository.upsert(sysPreference, {
reload: true, conflictPaths: ['key'],
}); });
} catch (e: any) { } catch (e: any) {
this.logger.warn(e); this.logger.warn(e);
@@ -43,23 +37,33 @@ export class SysPreferenceService {
} }
public async getPreference( public async getPreference(
key: SysPreferences, key: string,
): AsyncFailable<ESysPreferenceBackend> { ): AsyncFailable<ESysPreferenceBackend> {
let sysPreference: ESysPreferenceBackend | undefined; let sysPreference = await this.validatePref(key);
if (HasFailed(sysPreference)) return sysPreference;
let foundSysPreference: ESysPreferenceBackend | undefined;
try { try {
sysPreference = await this.sysPreferenceRepository.findOne({ foundSysPreference = await this.sysPreferenceRepository.findOne({
key, key: sysPreference.key,
}); });
} catch (e: any) { } catch (e: any) {
this.logger.warn(e); this.logger.warn(e);
return Fail('Could not get preference'); return Fail('Could not get preference');
} }
if (!sysPreference) { if (!foundSysPreference) {
return this.saveDefault(key); return this.saveDefault(sysPreference.key);
} else {
foundSysPreference = plainToClass(ESysPreferenceBackend, foundSysPreference);
const errors = await validate(foundSysPreference);
if (errors.length > 0) {
this.logger.warn(errors);
return Fail('Invalid preference');
}
} }
return sysPreference; return foundSysPreference;
} }
private async saveDefault( private async saveDefault(
@@ -67,4 +71,21 @@ export class SysPreferenceService {
): AsyncFailable<ESysPreferenceBackend> { ): AsyncFailable<ESysPreferenceBackend> {
return this.setPreference(key, SysPreferenceDefaults[key]()); return this.setPreference(key, SysPreferenceDefaults[key]());
} }
private async validatePref(
key: string,
value: string = 'validate',
): AsyncFailable<ESysPreferenceBackend> {
let verifySysPreference = new ESysPreferenceBackend();
verifySysPreference.key = key as SysPreferences;
verifySysPreference.value = value;
const errors = await validate(verifySysPreference);
if (errors.length > 0) {
this.logger.warn(errors);
return Fail('Invalid preference');
}
return verifySysPreference;
}
} }

View File

@@ -7,7 +7,7 @@ export class ESysPreferenceBackend extends ESysPreference {
@PrimaryGeneratedColumn() @PrimaryGeneratedColumn()
override id?: number; override id?: number;
@Column() @Column({ unique: true })
override key: SysPreferences; override key: SysPreferences;
@Column() @Column()

View File

@@ -46,8 +46,10 @@ export class AuthController {
register.username, register.username,
register.password, register.password,
); );
if (HasFailed(user)) {
if (HasFailed(user)) throw new ConflictException('User already exists'); console.warn(user.getReason());
throw new InternalServerErrorException('Could not create user');
}
if (register.isAdmin) { if (register.isAdmin) {
await this.authService.makeAdmin(user); await this.authService.makeAdmin(user);
@@ -63,7 +65,10 @@ export class AuthController {
@Body() deleteData: AuthDeleteRequest, @Body() deleteData: AuthDeleteRequest,
) { ) {
const user = await this.authService.deleteUser(deleteData.username); const user = await this.authService.deleteUser(deleteData.username);
if (HasFailed(user)) throw new NotFoundException('User does not exist'); if (HasFailed(user)) {
console.warn(user.getReason());
throw new InternalServerErrorException('Could not delete user');
}
return user; return user;
} }
@@ -72,9 +77,10 @@ export class AuthController {
@Get('list') @Get('list')
async listUsers(@Request() req: AuthFasityRequest) { async listUsers(@Request() req: AuthFasityRequest) {
const users = this.authService.listUsers(); const users = this.authService.listUsers();
if (HasFailed(users)) {
if (HasFailed(users)) console.warn(users.getReason());
throw new InternalServerErrorException('Could not list users'); throw new InternalServerErrorException('Could not list users');
}
return users; return users;
} }

View File

@@ -1,26 +1,47 @@
import { Controller, Post, UseGuards } from '@nestjs/common'; import {
Body,
Controller,
Get,
InternalServerErrorException,
NotFoundException,
Param,
Post,
UseGuards,
} from '@nestjs/common';
import { UpdateSysPreferenceRequest } from 'picsur-shared/dist/dto/syspreferences.dto';
import { HasFailed } from 'picsur-shared/dist/types';
import { SysPreferenceService } from '../../../collections/syspreferencesdb/syspreferencedb.service';
import { AdminGuard } from '../auth/admin.guard'; import { AdminGuard } from '../auth/admin.guard';
import { JwtAuthGuard } from '../auth/jwt.guard'; import { JwtAuthGuard } from '../auth/jwt.guard';
@Controller('pref') @UseGuards(JwtAuthGuard, AdminGuard)
@Controller('api/pref')
export class PrefController { export class PrefController {
@UseGuards(JwtAuthGuard, AdminGuard) constructor(private prefService: SysPreferenceService) {}
@Post('set/:key')
async register(
@Request() req: AuthFasityRequest,
@Body() register: AuthRegisterRequest,
) {
const user = await this.authService.createUser(
register.username,
register.password,
);
if (HasFailed(user)) throw new ConflictException('User already exists'); @Get('sys/:key')
async getSysPref(@Param('key') key: string) {
if (register.isAdmin) { const returned = await this.prefService.getPreference(key);
await this.authService.makeAdmin(user); if (HasFailed(returned)) {
console.warn(returned.getReason());
throw new InternalServerErrorException('Could not get preference');
} }
return user; return returned;
}
@Post('sys/:key')
async setSysPref(
@Param('key') key: string,
@Body() body: UpdateSysPreferenceRequest,
) {
const value = body.value;
const returned = await this.prefService.setPreference(key, value);
if (HasFailed(returned)) {
console.warn(returned.getReason());
throw new InternalServerErrorException('Could not set preference');
}
return returned;
} }
} }

View File

@@ -1,7 +1,9 @@
import { Module } from '@nestjs/common'; import { Module } from '@nestjs/common';
import { SysPreferenceModule } from '../../../collections/syspreferencesdb/syspreferencedb.module';
import { PrefController } from './pref.controller'; import { PrefController } from './pref.controller';
@Module({ @Module({
imports: [SysPreferenceModule],
controllers: [PrefController] controllers: [PrefController]
}) })
export class PrefModule {} export class PrefModule {}

View File

@@ -27,8 +27,10 @@ export class ImageController {
if (!isHash(hash, 'sha256')) throw new BadRequestException('Invalid hash'); if (!isHash(hash, 'sha256')) throw new BadRequestException('Invalid hash');
const image = await this.imagesService.retrieveComplete(hash); const image = await this.imagesService.retrieveComplete(hash);
if (HasFailed(image)) if (HasFailed(image)) {
throw new NotFoundException('Image not found'); console.warn(image.getReason());
throw new NotFoundException('Could not find image');
}
res.type(image.mime); res.type(image.mime);
return image.data; return image.data;
@@ -39,8 +41,10 @@ export class ImageController {
if (!isHash(hash, 'sha256')) throw new BadRequestException('Invalid hash'); if (!isHash(hash, 'sha256')) throw new BadRequestException('Invalid hash');
const image = await this.imagesService.retrieveInfo(hash); const image = await this.imagesService.retrieveInfo(hash);
if (HasFailed(image)) if (HasFailed(image)) {
throw new NotFoundException('Image not found'); console.warn(image.getReason());
throw new NotFoundException('Could not find image');
}
return image; return image;
} }
@@ -53,7 +57,8 @@ export class ImageController {
const fileBuffer = await multipart.image.toBuffer(); const fileBuffer = await multipart.image.toBuffer();
const image = await this.imagesService.upload(fileBuffer); const image = await this.imagesService.upload(fileBuffer);
if (HasFailed(image)) { if (HasFailed(image)) {
throw new InternalServerErrorException('Failed to upload image'); console.warn(image.getReason());
throw new InternalServerErrorException('Could not upload image');
} }
return image; return image;

View File

@@ -1,8 +1,14 @@
import { generateRandomString } from '../util/random'; import { generateRandomString } from '../util/random';
import tuple from '../types/tuple'; import tuple from '../types/tuple';
import { randomBytes } from 'crypto'; import { randomBytes } from 'crypto';
import { IsNotEmpty } from 'class-validator';
const SysPreferencesTuple = tuple('jwt_secret'); const SysPreferencesTuple = tuple('jwt_secret');
export const SysPreferences: string[] = SysPreferencesTuple; export const SysPreferences: string[] = SysPreferencesTuple;
export type SysPreferences = typeof SysPreferencesTuple[number]; export type SysPreferences = typeof SysPreferencesTuple[number];
export class UpdateSysPreferenceRequest {
@IsNotEmpty()
value: string;
}