diff --git a/packages/common/src/pipe/slash-command/slash-command.pipe.ts b/packages/common/src/pipe/slash-command/slash-command.pipe.ts index f905bea7..afa0f0b4 100644 --- a/packages/common/src/pipe/slash-command/slash-command.pipe.ts +++ b/packages/common/src/pipe/slash-command/slash-command.pipe.ts @@ -1,4 +1,4 @@ -import { ReflectMetadataProvider } from '@discord-nestjs/core'; +import { ParamType, ReflectMetadataProvider } from '@discord-nestjs/core'; import { ArgumentMetadata, Inject, @@ -8,7 +8,7 @@ import { Type, } from '@nestjs/common'; import { ClassTransformOptions, plainToInstance } from 'class-transformer'; -import { Interaction } from 'discord.js'; +import { Attachment, Interaction } from 'discord.js'; import { TRANSFORMER_OPTION } from '../../contants/transformer-options.constant'; @@ -40,6 +40,7 @@ export class SlashCommandPipe implements PipeTransform { const plainObject = {}; const dtoInstance = new metadata.metatype(); const allKeys = Object.keys(dtoInstance); + const assignWithoutTransform: Record = {}; allKeys.forEach((property: string) => { const paramDecoratorMetadata = @@ -50,17 +51,34 @@ export class SlashCommandPipe implements PipeTransform { if (!paramDecoratorMetadata) return; - const { name, required } = paramDecoratorMetadata; - plainObject[property] = - interaction.options.get(name ?? property, required)?.value ?? - dtoInstance[property]; + const { required, type } = paramDecoratorMetadata; + const name = paramDecoratorMetadata.name ?? property; + const interactionOption = interaction.options.get(name, required); + + plainObject[property] = interactionOption?.value ?? dtoInstance[property]; + + if (type === ParamType.ATTACHMENT) { + const propertyType = Reflect.getMetadata( + 'design:type', + dtoInstance, + property, + ); + + if (Object.is(propertyType, Attachment)) { + assignWithoutTransform[property] = + interactionOption?.attachment ?? dtoInstance[property]; + } + } }); - return plainToInstance( + // class-validator breaks classes trying to recreate an instance from a property type + const resultDto = plainToInstance( metadata.metatype, plainObject, this.classTransformerOptions, ); + + return Object.assign(resultDto, assignWithoutTransform); } private isDto(type: Type): boolean { diff --git a/packages/sample/sub-command/src/bot/dto/email.dto.ts b/packages/sample/sub-command/src/bot/dto/email.dto.ts index 5d32b0d1..44ca5fd8 100644 --- a/packages/sample/sub-command/src/bot/dto/email.dto.ts +++ b/packages/sample/sub-command/src/bot/dto/email.dto.ts @@ -1,4 +1,5 @@ import { Choice, Param, ParamType } from '@discord-nestjs/core'; +import { Attachment } from 'discord.js'; import { City } from '../definitions/city'; @@ -15,6 +16,13 @@ export class EmailDto { @Param({ description: 'User age', required: true, type: ParamType.INTEGER }) age: number; + @Param({ + description: 'Attachment', + type: ParamType.ATTACHMENT, + required: true, + }) + screenshot: Attachment; + @Choice(City) @Param({ description: 'City of residence', type: ParamType.INTEGER }) city: City;