From 4705fc4c3a369ac1aa17dc5da8acdfe42f849f11 Mon Sep 17 00:00:00 2001 From: Snazzah Date: Tue, 17 Sep 2024 09:04:13 -0500 Subject: [PATCH] feat: support polls --- src/constants.ts | 5 ++ .../interfaces/messageInteraction.ts | 29 +++++++--- src/structures/message.ts | 57 ++++++++++++++++++- src/util.ts | 3 + 4 files changed, 85 insertions(+), 9 deletions(-) diff --git a/src/constants.ts b/src/constants.ts index ac5e5ec8..ca29da00 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -141,6 +141,11 @@ export enum StickerFormat { GIF = 4 } +/** The layouts polls can be in. */ +export enum PollLayoutType { + DEFAULT = 1 +} + /** * An partial application command in Discord. * @private diff --git a/src/structures/interfaces/messageInteraction.ts b/src/structures/interfaces/messageInteraction.ts index 4e594396..b30756b6 100644 --- a/src/structures/interfaces/messageInteraction.ts +++ b/src/structures/interfaces/messageInteraction.ts @@ -12,7 +12,7 @@ import { FormattedAllowedMentions, MessageAllowedMentions } from '../../util'; -import { Message, MessageEmbedOptions } from '../message'; +import { CreatePollOptions, Message, MessageEmbedOptions } from '../message'; import { BaseInteractionContext } from './baseInteraction'; /** Represents a interaction context that handles messages. */ @@ -71,7 +71,8 @@ export class MessageInteractionContext< const options = typeof content === 'string' ? { content } : content; if (typeof options !== 'object') throw new Error('Message options is not an object.'); - if (!options.content && !options.embeds && !options.files) throw new Error('No valid options were given.'); + if (!options.content && !options.embeds && !options.files && !options.poll) + throw new Error('No valid options were given.'); if (options.ephemeral && !options.flags) options.flags = InteractionResponseFlags.EPHEMERAL; const allowedMentions = options.allowedMentions @@ -92,7 +93,8 @@ export class MessageInteractionContext< flags: options.flags, allowed_mentions: allowedMentions, components: options.components, - attachments: options.attachments + attachments: options.attachments, + poll: options.poll } }, files: options.files @@ -111,8 +113,8 @@ export class MessageInteractionContext< const options = typeof content === 'string' ? { content } : content; if (typeof options !== 'object') throw new Error('Message options is not an object.'); - if (!options.content && !options.embeds && !options.files) - throw new Error('Message content, embeds or files need to be given.'); + if (!options.content && !options.embeds && !options.files && !options.poll) + throw new Error('No valid options were given.'); if (options.ephemeral && !options.flags) options.flags = InteractionResponseFlags.EPHEMERAL; const allowedMentions = options.allowedMentions @@ -129,7 +131,8 @@ export class MessageInteractionContext< allowed_mentions: allowedMentions, components: options.components, flags: options.flags, - attachments: options.attachments + attachments: options.attachments, + poll: options.poll }, options.files ); @@ -146,7 +149,14 @@ export class MessageInteractionContext< const options = typeof content === 'string' ? { content } : content; if (typeof options !== 'object') throw new Error('Message options is not an object.'); - if (!options.content && !options.embeds && !options.components && !options.files && !options.attachments) + if ( + !options.content && + !options.embeds && + !options.components && + !options.files && + !options.attachments && + !options.poll + ) throw new Error('No valid options were given.'); const allowedMentions = options.allowedMentions @@ -162,7 +172,8 @@ export class MessageInteractionContext< embeds: options.embeds, allowed_mentions: allowedMentions, components: options.components, - attachments: options.attachments + attachments: options.attachments, + poll: options.poll }, options.files ); @@ -401,6 +412,8 @@ export interface EditMessageOptions { components?: AnyComponent[]; /** The attachment data of the message. */ attachments?: MessageAttachmentOptions[]; + /** A poll. */ + poll?: CreatePollOptions; } /** A file within {@link EditMessageOptions}. */ diff --git a/src/structures/message.ts b/src/structures/message.ts index f9351553..cc079653 100644 --- a/src/structures/message.ts +++ b/src/structures/message.ts @@ -3,6 +3,8 @@ import { ApplicationIntegrationType, CommandChannel, InteractionType, + PartialEmoji, + PollLayoutType, StickerFormat, UserObject } from '../constants'; @@ -11,6 +13,7 @@ import { BaseSlashCreator } from '../creator'; import { MessageInteractionContext } from './interfaces/messageInteraction'; import { User } from './user'; import { Channel } from './channel'; +import { PartialBy } from '../util'; /** Represents a Discord message. */ export class Message { @@ -46,6 +49,8 @@ export class Message { readonly pinned: boolean; /** The approximate position of the message in a thread. */ readonly position?: number; + /** The poll in the message. */ + readonly poll?: PollObject; /** The thread that was started from this message. */ readonly thread?: Channel; /** The timestamp of the message */ @@ -100,7 +105,7 @@ export class Message { participants: data.call.participants, endedTimestamp: data.call.ended_timestamp }; - this.call = data.call; + this.poll = data.poll; this.position = data.position; this.timestamp = Date.parse(data.timestamp); if (data.edited_timestamp) this.editedTimestamp = Date.parse(data.edited_timestamp); @@ -266,6 +271,55 @@ export interface MessageAttachment { flags?: number; } +export interface CreatePollOptions { + /** The question of the poll. */ + question: PollMedia; + /** The answers of the poll. `answer_id` is optional. */ + answers: PartialBy[]; + /** The duration (in hours) the poll will be open for */ + duration?: number; + /** Whether to allow for multiple options to be selected */ + allow_multiselect?: boolean; + /** The layout type of the poll */ + layout_type?: PollLayoutType; +} + +export interface PollObject { + /** The question of the poll. */ + question: PollMedia; + /** The answers of the poll. */ + answers: PollAnswer[]; + /** The expiration of the poll */ + expiry: string | null; + /** Whether you can select multiple options in thie poll */ + allow_multiselect: boolean; + /** The layout type of the poll */ + layout_type: PollLayoutType; + /** The results of the poll if finished */ + results?: PollResults; +} + +export interface PollResults { + is_finalized: boolean; + answer_counts: PollAnswerCount[]; +} + +export interface PollAnswerCount { + id: number; + count: number; + me_voted: boolean; +} + +export interface PollMedia { + text?: string; + emoji?: PartialEmoji; +} + +export interface PollAnswer { + answer_id: number; + poll_media: PollMedia; +} + /** Options to creating a message embed. */ export interface MessageEmbedOptions { author?: EmbedAuthorOptions; @@ -369,6 +423,7 @@ export interface MessageData { participants: string[]; ended_timestamp?: string; }; + poll?: PollObject; position?: number; thread?: CommandChannel; timestamp: string; diff --git a/src/util.ts b/src/util.ts index a1f3d403..aac5a06d 100644 --- a/src/util.ts +++ b/src/util.ts @@ -177,3 +177,6 @@ export interface FormattedAllowedMentions { roles?: string[]; users?: string[]; } + +/** @hidden */ +export type PartialBy = Omit & Partial>;