Add custom decorator

This commit is contained in:
rubikscraft
2022-02-21 23:19:10 +01:00
parent 34d805969f
commit eee3ce9e9f
8 changed files with 65 additions and 41 deletions

View File

@@ -2,11 +2,9 @@ import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { AuthModule } from './routes/auth/auth.module';
import { UserEntity } from './collections/userdb/user.entity';
import { UsersModule } from './collections/userdb/userdb.module';
import { ImageModule } from './routes/image/imageroute.module';
import Config from './env';
import { ImageEntity } from './collections/imagedb/image.entity';
import { SafeImagesModule } from './lib/safeimages/safeimages.module';
@Module({
imports: [
@@ -22,9 +20,7 @@ import { SafeImagesModule } from './lib/safeimages/safeimages.module';
entities: [UserEntity, ImageEntity],
}),
AuthModule,
UsersModule,
ImageModule,
SafeImagesModule,
],
})
export class AppModule {}

View File

@@ -0,0 +1,38 @@
import {
BadRequestException,
createParamDecorator,
ExecutionContext,
} from '@nestjs/common';
import { FastifyRequest } from 'fastify';
import { Multipart } from 'fastify-multipart';
import { request } from 'http';
import Config from 'src/env';
export interface MPFile {
fieldname: string;
}
export const PostFile = createParamDecorator(
async (data: unknown, ctx: ExecutionContext) => {
const req: FastifyRequest = ctx.switchToHttp().getRequest();
if (!req.isMultipart()) throw new BadRequestException('Invalid file');
const file = await req.file({
limits: { fileSize: Config.limits.maxFileSize, files: 1 },
});
if (file === undefined) throw new BadRequestException('Invalid file');
const allFields: Multipart[] = Object.values(file.fields).filter(
(entry) => entry,
) as any;
const files = allFields.filter((entry) => entry.file !== undefined);
if (files.length !== 1) throw new BadRequestException('Invalid file');
return await files[0].toBuffer();
},
);
// TODO: Make better multipart decoder

View File

@@ -1,7 +1,7 @@
const Config = {
database: {
host: process.env.DB_HOST ?? 'localhost',
port: parseInt(process.env.DB_PORT) ?? 5432,
port: process.env.DB_PORT ? parseInt(process.env.DB_PORT) : 5432,
username: process.env.DB_USERNAME ?? 'imagur',
password: process.env.DB_PASSWORD ?? 'imagur',
database: process.env.DB_DATABASE ?? 'imagur',
@@ -14,6 +14,11 @@ const Config = {
secret: process.env.JWT_SECRET ?? 'CHANGE_ME',
expiresIn: process.env.JWT_EXPIRES_IN ?? '1d',
},
limits: {
maxFileSize: process.env.MAX_FILE_SIZE
? parseInt(process.env.MAX_FILE_SIZE)
: 128000000,
},
};
export default Config;

View File

@@ -1,10 +0,0 @@
import { Module } from '@nestjs/common';
import { ImageDBModule } from 'src/collections/imagedb/imagedb.module';
import { SafeImagesService } from './safeimages.service';
@Module({
imports: [ImageDBModule],
providers: [SafeImagesService],
exports: [SafeImagesService],
})
export class SafeImagesModule {}

View File

@@ -0,0 +1,10 @@
import { Module } from '@nestjs/common';
import { ImageDBModule } from 'src/collections/imagedb/imagedb.module';
import { ImageManagerService } from './imagemanager.service';
@Module({
imports: [ImageDBModule],
providers: [ImageManagerService],
exports: [ImageManagerService],
})
export class ImageManagerModule {}

View File

@@ -6,7 +6,7 @@ import { FullMime, MimesService } from 'src/collections/imagedb/mimes.service';
import { AsyncFailable, Fail, HasFailed } from 'src/types/failable';
@Injectable()
export class SafeImagesService {
export class ImageManagerService {
constructor(
private readonly imagesService: ImageDBService,
private readonly mimesService: MimesService,

View File

@@ -10,13 +10,13 @@ import {
Res,
} from '@nestjs/common';
import { FastifyReply, FastifyRequest } from 'fastify';
import { Multipart } from 'fastify-multipart';
import { PostFile } from 'src/decorators/multipart.decorator';
import { ImageManagerService } from 'src/managers/imagemanager/imagemanager.service';
import { HasFailed } from 'src/types/failable';
import { SafeImagesService } from 'src/lib/safeimages/safeimages.service';
@Controller()
export class ImageController {
constructor(private readonly imagesService: SafeImagesService) {}
constructor(private readonly imagesService: ImageManagerService) {}
@Get('i/:hash')
async getImage(
@@ -35,27 +35,11 @@ export class ImageController {
}
@Post('i')
async uploadImage(@Req() req: FastifyRequest) {
if (!req.isMultipart())
throw new BadRequestException('Not a multipart request');
const file = await req.file({ limits: {} });
if (file === undefined) throw new BadRequestException('No file uploaded');
const allFields: Multipart[] = Object.values(file.fields).filter(
(entry) => entry,
) as any;
const options = allFields.filter((entry) => entry.file === undefined);
const files = allFields.filter((entry) => entry.file !== undefined);
if (files.length !== 1) throw new BadRequestException('Invalid file');
const image = await files[0].toBuffer();
const hash = await this.imagesService.uploadImage(image);
if (HasFailed(hash))
async uploadImage(@Req() req: FastifyRequest, @PostFile() file: Buffer) {
const hash = await this.imagesService.uploadImage(file);
if (HasFailed(hash)) {
throw new InternalServerErrorException('Failed to upload image');
}
return { hash };
}

View File

@@ -1,9 +1,10 @@
import { Module } from '@nestjs/common';
import { SafeImagesModule } from 'src/lib/safeimages/safeimages.module';
import { ImageManagerModule } from 'src/managers/imagemanager/imagemanager.module';
import { ImageController } from './imageroute.controller';
@Module({
imports: [SafeImagesModule],
imports: [ImageManagerModule],
controllers: [ImageController],
})
export class ImageModule {}