diff --git a/packages/discord.js/src/structures/CommandInteraction.js b/packages/discord.js/src/structures/CommandInteraction.js index 5d61e8317..b0770813d 100644 --- a/packages/discord.js/src/structures/CommandInteraction.js +++ b/packages/discord.js/src/structures/CommandInteraction.js @@ -85,6 +85,7 @@ class CommandInteraction extends BaseInteraction { * @property {Collection} [members] The resolved guild members * @property {Collection} [roles] The resolved roles * @property {Collection} [channels] The resolved channels + * @property {Collection} [attachments] The resolved attachments */ /** @@ -92,7 +93,6 @@ class CommandInteraction extends BaseInteraction { * * @typedef {BaseInteractionResolvedData} CommandInteractionResolvedData * @property {Collection} [messages] The resolved messages - * @property {Collection} [attachments] The resolved attachments */ /** diff --git a/packages/discord.js/src/structures/ModalSubmitFields.js b/packages/discord.js/src/structures/ModalSubmitFields.js index 419265853..ba7bc0f46 100644 --- a/packages/discord.js/src/structures/ModalSubmitFields.js +++ b/packages/discord.js/src/structures/ModalSubmitFields.js @@ -216,6 +216,17 @@ class ModalSubmitFields { return null; } + + /** + * Gets file upload component + * + * @param {string} customId The custom id of the component + * @param {boolean} [required=false] Whether to throw an error if the component value is not found or empty + * @returns {?Collection} The uploaded files, or null if none were uploaded and not required + */ + getUploadedFiles(customId, required = false) { + return this._getTypedComponent(customId, [ComponentType.FileUpload], ['attachments'], required).attachments ?? null; + } } module.exports = ModalSubmitFields; diff --git a/packages/discord.js/src/structures/ModalSubmitInteraction.js b/packages/discord.js/src/structures/ModalSubmitInteraction.js index f7eeb0ecd..0c7d5ac7a 100644 --- a/packages/discord.js/src/structures/ModalSubmitInteraction.js +++ b/packages/discord.js/src/structures/ModalSubmitInteraction.js @@ -9,6 +9,7 @@ const InteractionResponses = require('./interfaces/InteractionResponses'); const { transformResolved } = require('../util/Util'); const getMessage = lazy(() => require('./Message').Message); +const getAttachment = lazy(() => require('./Attachment')); /** * @typedef {Object} BaseModalData @@ -16,6 +17,13 @@ const getMessage = lazy(() => require('./Message').Message); * @property {number} id The id of the field */ +/** + * @typedef {BaseModalData} FileUploadModalData + * @property {string} customId The custom id of the file upload + * @property {string[]} values The values of the file upload + * @property {Collection} [attachments] The resolved attachments + */ + /** * @typedef {BaseModalData} TextInputModalData * @property {string} customId The custom id of the field @@ -37,7 +45,7 @@ const getMessage = lazy(() => require('./Message').Message); */ /** - * @typedef {SelectMenuModalData|TextInputModalData} ModalData + * @typedef {SelectMenuModalData|TextInputModalData|FileUploadModalData} ModalData */ /** @@ -161,7 +169,7 @@ class ModalSubmitInteraction extends BaseInteraction { /* eslint-disable max-depth */ if (resolved) { - const { members, users, channels, roles } = resolved; + const { members, users, channels, roles, attachments } = resolved; const valueSet = new Set(rawComponent.values); if (users) { @@ -204,6 +212,15 @@ class ModalSubmitInteraction extends BaseInteraction { } } } + + if (attachments) { + data.attachments = new Collection(); + for (const [id, attachment] of Object.entries(attachments)) { + if (valueSet.has(id)) { + data.attachments.set(id, new (getAttachment())(attachment)); + } + } + } } /* eslint-enable max-depth */ diff --git a/packages/discord.js/src/util/Components.js b/packages/discord.js/src/util/Components.js index b75f2945b..2342c57b5 100644 --- a/packages/discord.js/src/util/Components.js +++ b/packages/discord.js/src/util/Components.js @@ -23,7 +23,8 @@ const { ComponentType } = require('discord-api-types/v10'); /** * @typedef {StringSelectMenuComponentData|TextInputComponentData|UserSelectMenuComponentData| - * RoleSelectMenuComponentData|MentionableSelectMenuComponentData|ChannelSelectMenuComponentData} ComponentInLabelData + * RoleSelectMenuComponentData|MentionableSelectMenuComponentData|ChannelSelectMenuComponentData| + * FileUploadComponentData} ComponentInLabelData */ /** @@ -43,6 +44,14 @@ const { ComponentType } = require('discord-api-types/v10'); * @property {string} [url] The URL of the button */ +/** + * @typedef {BaseComponentData} FileUploadComponentData + * @property {string} customId The custom id of the file upload + * @property {number} [minValues] The minimum number of files that can be uploaded (0-10) + * @property {number} [maxValues] The maximum number of files that can be uploaded (1-10) + * @property {boolean} [required] Whether this component is required in modals + */ + /** * @typedef {BaseComponentData} BaseSelectMenuComponentData * @property {string} customId The custom id of the select menu diff --git a/packages/discord.js/typings/index.d.ts b/packages/discord.js/typings/index.d.ts index deb0bdf2c..f475371e9 100644 --- a/packages/discord.js/typings/index.d.ts +++ b/packages/discord.js/typings/index.d.ts @@ -367,7 +367,8 @@ export type ComponentInLabelData = | UserSelectMenuComponentData | ChannelSelectMenuComponentData | RoleSelectMenuComponentData - | MentionableSelectMenuComponentData; + | MentionableSelectMenuComponentData + | FileUploadComponentData; export interface LabelComponentData extends BaseComponentData { type: ComponentType.Label; @@ -2823,7 +2824,12 @@ export interface SelectMenuModalData values: readonly string[]; } -export type ModalData = SelectMenuModalData | TextInputModalData; +export interface FileUploadModalData extends BaseModalData { + customId: string; + files: readonly Attachment[]; +} + +export type ModalData = FileUploadModalData | SelectMenuModalData | TextInputModalData; export interface LabelModalData extends BaseModalData { component: readonly ModalData[]; @@ -2900,6 +2906,8 @@ export class ModalSubmitFields { public getSelectedMentionables(customId: string, required: true): ModalSelectedMentionables; public getSelectedMentionables(customId: string, required?: boolean): ModalSelectedMentionables | null; + public getUploadedFiles(customId: string, required: true): ReadonlyCollection; + public getUploadedFiles(customId: string, required?: boolean): ReadonlyCollection | null; } export interface ModalMessageModalSubmitInteraction @@ -6184,6 +6192,7 @@ export interface CommandInteractionOption } export interface BaseInteractionResolvedData { + attachments?: ReadonlyCollection; channels?: ReadonlyCollection>; members?: ReadonlyCollection>; roles?: ReadonlyCollection>; @@ -6192,7 +6201,6 @@ export interface BaseInteractionResolvedData extends BaseInteractionResolvedData { - attachments?: ReadonlyCollection; messages?: ReadonlyCollection>; } @@ -7430,6 +7438,14 @@ export interface TextInputComponentData extends BaseComponentData { placeholder?: string; } +export interface FileUploadComponentData extends BaseComponentData { + customId: string; + maxValues?: number; + minValues?: number; + required?: number; + type: ComponentType.FileUpload; +} + export type MessageTarget = | Interaction | InteractionWebhook