cleanup decorators
This commit is contained in:
parent
d7d44b0147
commit
a30cd8249a
|
@ -6,7 +6,14 @@ import { PostFilePipe } from './postfile.pipe';
|
|||
@Module({
|
||||
imports: [EarlyConfigModule],
|
||||
providers: [MultiPartPipe, PostFilePipe],
|
||||
exports: [MultiPartPipe, PostFilePipe, EarlyConfigModule],
|
||||
|
||||
exports: [
|
||||
MultiPartPipe,
|
||||
PostFilePipe,
|
||||
// EarlyConfigModule is exported here because the pipes are dependedant on the config
|
||||
// But these pipes dont resolve their dependencies via this module
|
||||
// So this way we force it to be "global"
|
||||
EarlyConfigModule,
|
||||
],
|
||||
})
|
||||
export class DecoratorsModule {
|
||||
}
|
||||
export class DecoratorsModule {}
|
||||
|
|
12
backend/src/decorators/injectrequest.decorator.ts
Normal file
12
backend/src/decorators/injectrequest.decorator.ts
Normal file
|
@ -0,0 +1,12 @@
|
|||
import { createParamDecorator, ExecutionContext } from '@nestjs/common';
|
||||
import { Newable } from 'picsur-shared/dist/types';
|
||||
|
||||
// Since pipes dont have direct access to the request object, we need this decorator to inject it
|
||||
export const InjectRequest = createParamDecorator(
|
||||
async <T extends Object>(data: Newable<T>, ctx: ExecutionContext) => {
|
||||
return {
|
||||
req: ctx.switchToHttp().getRequest(),
|
||||
data,
|
||||
};
|
||||
},
|
||||
);
|
|
@ -1,22 +1,9 @@
|
|||
import {
|
||||
createParamDecorator,
|
||||
ExecutionContext
|
||||
} from '@nestjs/common';
|
||||
import { Newable } from 'picsur-shared/dist/types';
|
||||
import { InjectRequest } from './injectrequest.decorator';
|
||||
import { MultiPartPipe } from './multipart.pipe';
|
||||
import { PostFilePipe } from './postfile.pipe';
|
||||
|
||||
const InjectRequest = createParamDecorator(
|
||||
async <T extends Object>(data: Newable<T>, ctx: ExecutionContext) => {
|
||||
return {
|
||||
req: ctx.switchToHttp().getRequest(),
|
||||
data,
|
||||
};
|
||||
},
|
||||
);
|
||||
|
||||
export const PostFile = () =>
|
||||
InjectRequest(PostFilePipe);
|
||||
export const PostFile = () => InjectRequest(PostFilePipe);
|
||||
|
||||
export const MultiPart = <T extends Object>(data: Newable<T>) =>
|
||||
InjectRequest(data, MultiPartPipe);
|
||||
|
|
|
@ -28,10 +28,12 @@ export class MultiPartPipe implements PipeTransform {
|
|||
req: FastifyRequest;
|
||||
data: Newable<T>;
|
||||
}) {
|
||||
// Data should be a validatable class constructor
|
||||
const dtoClass = new data();
|
||||
|
||||
if (!req.isMultipart()) throw new BadRequestException('Invalid file');
|
||||
|
||||
// Fetch all fields from the request
|
||||
let fields: MultipartFields | null = null;
|
||||
try {
|
||||
fields = (
|
||||
|
@ -44,11 +46,15 @@ export class MultiPartPipe implements PipeTransform {
|
|||
}
|
||||
if (!fields) throw new BadRequestException('Invalid file');
|
||||
|
||||
// Loop over every formfield that was sent
|
||||
for (const key of Object.keys(fields)) {
|
||||
// Ignore duplicate fields
|
||||
if (Array.isArray(fields[key])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Use the value property to differentiate between a field and a file
|
||||
// And then put the value into the correct property on the validatable class
|
||||
if ((fields[key] as any).value) {
|
||||
(dtoClass as any)[key] = new MultiPartFieldDto(
|
||||
fields[key] as MultipartFile,
|
||||
|
@ -61,6 +67,7 @@ export class MultiPartPipe implements PipeTransform {
|
|||
}
|
||||
}
|
||||
|
||||
// Now validate the class we made, if any properties were invalid, it will error here
|
||||
const errors = await strictValidate(dtoClass);
|
||||
if (errors.length > 0) {
|
||||
this.logger.warn(errors);
|
||||
|
|
|
@ -7,9 +7,10 @@ export const RequiredPermissions = (...permissions: Permissions) => {
|
|||
return SetMetadata('permissions', permissions);
|
||||
};
|
||||
|
||||
// Easy to read roles
|
||||
// Just a verbose wrapper
|
||||
export const NoPermissions = () => RequiredPermissions();
|
||||
|
||||
// This still requires permissions, but also allows the client to use user/pass authentication instead of JWT
|
||||
export const UseLocalAuth = (...permissions: Permissions) =>
|
||||
CombineFCDecorators(
|
||||
RequiredPermissions(...permissions),
|
||||
|
|
|
@ -18,6 +18,7 @@ export class PostFilePipe implements PipeTransform {
|
|||
async transform({ req }: { req: FastifyRequest }) {
|
||||
if (!req.isMultipart()) throw new BadRequestException('Invalid file');
|
||||
|
||||
// Only one file is allowed
|
||||
const file = await req.file({
|
||||
limits: {
|
||||
...this.multipartConfigService.getLimits(),
|
||||
|
@ -26,14 +27,17 @@ export class PostFilePipe implements PipeTransform {
|
|||
});
|
||||
if (file === undefined) throw new BadRequestException('Invalid file');
|
||||
|
||||
// Remove empty fields
|
||||
const allFields: Multipart[] = Object.values(file.fields).filter(
|
||||
(entry) => entry,
|
||||
) as any;
|
||||
|
||||
// Remove non-file fields
|
||||
const files = allFields.filter((entry) => entry.file !== undefined);
|
||||
|
||||
if (files.length !== 1) throw new BadRequestException('Invalid file');
|
||||
|
||||
// Return a buffer of the file
|
||||
try {
|
||||
return await files[0].toBuffer();
|
||||
} catch (e) {
|
||||
|
|
Loading…
Reference in a new issue