mirror of
https://github.com/CaramelFur/Picsur.git
synced 2025-11-13 23:35:39 +01:00
systempreference api done
This commit is contained in:
@@ -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 {}
|
||||||
}
|
|
||||||
|
|||||||
@@ -8,4 +8,4 @@ import { SysPreferenceService } from './syspreferencedb.service';
|
|||||||
providers: [SysPreferenceService],
|
providers: [SysPreferenceService],
|
||||||
exports: [SysPreferenceService],
|
exports: [SysPreferenceService],
|
||||||
})
|
})
|
||||||
export class UsersModule {}
|
export class SysPreferenceModule {}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 {}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user