mirror of
https://github.com/tiramisulabs/seyfert.git
synced 2025-07-01 20:46:08 +00:00
feat: add polls (#188)
This commit is contained in:
parent
d55e904366
commit
9e54231d02
@ -21,7 +21,7 @@
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"chokidar": "^3.6.0",
|
||||
"discord-api-types": "^0.37.76",
|
||||
"discord-api-types": "^0.37.80",
|
||||
"magic-bytes.js": "^1.10.0",
|
||||
"ts-mixer": "^6.0.4",
|
||||
"ws": "^8.16.0"
|
||||
|
1934
pnpm-lock.yaml
generated
1934
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@ -24,6 +24,8 @@ import type {
|
||||
RESTGetAPIChannelThreadsArchivedQuery,
|
||||
RESTGetAPIChannelUsersThreadsArchivedResult,
|
||||
RESTGetAPIGuildWebhooksResult,
|
||||
RESTGetAPIPollAnswerVotersQuery,
|
||||
RESTGetAPIPollAnswerVotersResult,
|
||||
RESTPatchAPIChannelJSONBody,
|
||||
RESTPatchAPIChannelMessageJSONBody,
|
||||
RESTPatchAPIChannelMessageResult,
|
||||
@ -45,6 +47,7 @@ import type {
|
||||
RESTPostAPIChannelWebhookJSONBody,
|
||||
RESTPostAPIChannelWebhookResult,
|
||||
RESTPostAPIGuildForumThreadsJSONBody,
|
||||
RESTPostAPIPollExpireResult,
|
||||
RESTPutAPIChannelMessageReactionResult,
|
||||
RESTPutAPIChannelPermissionJSONBody,
|
||||
RESTPutAPIChannelPermissionResult,
|
||||
@ -256,5 +259,17 @@ export interface ChannelRoutes {
|
||||
'voice-status': {
|
||||
put(args: RestArguments<ProxyRequestMethod.Put, { status: string | null }>): Promise<never>;
|
||||
};
|
||||
polls(messageId: string): {
|
||||
answers(id: ValidAnswerId): {
|
||||
get(
|
||||
args?: RestArguments<ProxyRequestMethod.Get, never, RESTGetAPIPollAnswerVotersQuery>,
|
||||
): Promise<RESTGetAPIPollAnswerVotersResult>;
|
||||
};
|
||||
expire: {
|
||||
post(args?: RestArguments<ProxyRequestMethod.Post>): Promise<RESTPostAPIPollExpireResult>;
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export type ValidAnswerId = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10;
|
||||
|
51
src/builders/Poll.ts
Normal file
51
src/builders/Poll.ts
Normal file
@ -0,0 +1,51 @@
|
||||
import { type APIPollMedia, PollLayoutType, type RESTAPIPollCreate } from 'discord-api-types/v10';
|
||||
import type { DeepPartial, EmojiResolvable, RestOrArray } from '../common';
|
||||
import { throwError } from '..';
|
||||
import { resolvePartialEmoji } from '../structures/extra/functions';
|
||||
|
||||
export class PollBuilder {
|
||||
constructor(
|
||||
public data: DeepPartial<Omit<RESTAPIPollCreate, 'answers'> & { answers: { media: APIPollMedia }[] }> = {},
|
||||
) {
|
||||
this.data.layout_type = PollLayoutType.Default;
|
||||
}
|
||||
|
||||
addAnswers(...answers: RestOrArray<PollMedia>) {
|
||||
this.data.answers = (this.data.answers ?? []).concat(
|
||||
answers.flat().map(x => ({ media: this.resolvedPollMedia(x) })),
|
||||
);
|
||||
return this;
|
||||
}
|
||||
|
||||
setAnswers(...answers: RestOrArray<PollMedia>) {
|
||||
this.data.answers = answers.flat().map(x => ({ media: this.resolvedPollMedia(x) }));
|
||||
return this;
|
||||
}
|
||||
|
||||
setQuestion(data: PollMedia) {
|
||||
this.data.question ??= {};
|
||||
const { emoji, text } = this.resolvedPollMedia(data);
|
||||
this.data.question.text = text;
|
||||
this.data.question.emoji = emoji;
|
||||
return this;
|
||||
}
|
||||
|
||||
setDuration(hours: number) {
|
||||
this.data.duration = hours;
|
||||
return this;
|
||||
}
|
||||
|
||||
allowMultiselect(value = true) {
|
||||
this.data.allow_multiselect = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
private resolvedPollMedia(data: PollMedia) {
|
||||
if (!data.emoji) return { text: data.text };
|
||||
const resolve = resolvePartialEmoji(data.emoji);
|
||||
if (!resolve) return throwError('Invalid Emoji');
|
||||
return { text: data.text, emoji: resolve };
|
||||
}
|
||||
}
|
||||
|
||||
export type PollMedia = { text?: string; emoji?: EmojiResolvable };
|
@ -18,6 +18,7 @@ export * from './Button';
|
||||
export * from './Embed';
|
||||
export * from './Modal';
|
||||
export * from './SelectMenu';
|
||||
export * from './Poll';
|
||||
export * from './types';
|
||||
|
||||
export function fromComponent(
|
||||
|
@ -4,10 +4,11 @@ import type {
|
||||
RESTPostAPIChannelMessagesThreadsJSONBody,
|
||||
} from 'discord-api-types/v10';
|
||||
import { resolveFiles } from '../../builders';
|
||||
import { Message, MessagesMethods } from '../../structures';
|
||||
import { Message, MessagesMethods, User } from '../../structures';
|
||||
|
||||
import type { MessageCreateBodyRequest, MessageUpdateBodyRequest } from '../types/write';
|
||||
import { BaseShorter } from './base';
|
||||
import type { ValidAnswerId } from '../../api/Routes/channels';
|
||||
|
||||
export class MessageShorter extends BaseShorter {
|
||||
async write(channelId: string, { files, ...body }: MessageCreateBodyRequest) {
|
||||
@ -88,4 +89,21 @@ export class MessageShorter extends BaseShorter {
|
||||
) {
|
||||
return this.client.threads.fromMessage(channelId, messageId, options);
|
||||
}
|
||||
|
||||
endPoll(channelId: string, messageId: string) {
|
||||
return this.client.proxy
|
||||
.channels(channelId)
|
||||
.polls(messageId)
|
||||
.expire.post()
|
||||
.then(message => new Message(this.client, message));
|
||||
}
|
||||
|
||||
getAnswerVoters(channelId: string, messageId: string, answerId: ValidAnswerId) {
|
||||
return this.client.proxy
|
||||
.channels(channelId)
|
||||
.polls(messageId)
|
||||
.answers(answerId)
|
||||
.get()
|
||||
.then(data => data.users.map(user => new User(this.client, user)));
|
||||
}
|
||||
}
|
||||
|
@ -5,13 +5,22 @@ import type {
|
||||
APIInteractionResponseChannelMessageWithSource,
|
||||
APIMessageActionRowComponent,
|
||||
APIModalInteractionResponse,
|
||||
RESTAPIPollCreate,
|
||||
RESTPatchAPIChannelMessageJSONBody,
|
||||
RESTPatchAPIWebhookWithTokenMessageJSONBody,
|
||||
RESTPostAPIChannelMessageJSONBody,
|
||||
RESTPostAPIWebhookWithTokenJSONBody,
|
||||
} from 'discord-api-types/v10';
|
||||
import type { RawFile } from '../../api';
|
||||
import type { ActionRow, Attachment, AttachmentBuilder, BuilderComponents, Embed, Modal } from '../../builders';
|
||||
import type {
|
||||
ActionRow,
|
||||
Attachment,
|
||||
AttachmentBuilder,
|
||||
BuilderComponents,
|
||||
Embed,
|
||||
Modal,
|
||||
PollBuilder,
|
||||
} from '../../builders';
|
||||
|
||||
import type { OmitInsert } from './util';
|
||||
|
||||
@ -21,10 +30,14 @@ export interface ResolverProps {
|
||||
files?: AttachmentBuilder[] | Attachment[] | RawFile[] | undefined;
|
||||
}
|
||||
|
||||
export interface SendResolverProps extends ResolverProps {
|
||||
poll?: PollBuilder | RESTAPIPollCreate | undefined;
|
||||
}
|
||||
|
||||
export type MessageCreateBodyRequest = OmitInsert<
|
||||
RESTPostAPIChannelMessageJSONBody,
|
||||
'components' | 'embeds',
|
||||
ResolverProps
|
||||
'components' | 'embeds' | 'poll',
|
||||
SendResolverProps
|
||||
>;
|
||||
|
||||
export type MessageUpdateBodyRequest = OmitInsert<
|
||||
@ -35,8 +48,8 @@ export type MessageUpdateBodyRequest = OmitInsert<
|
||||
|
||||
export type MessageWebhookCreateBodyRequest = OmitInsert<
|
||||
RESTPostAPIWebhookWithTokenJSONBody,
|
||||
'components' | 'embeds',
|
||||
ResolverProps
|
||||
'components' | 'embeds' | 'poll',
|
||||
SendResolverProps
|
||||
>;
|
||||
|
||||
export type MessageWebhookUpdateBodyRequest = OmitInsert<
|
||||
|
@ -3,6 +3,7 @@ import type {
|
||||
GatewayMessageCreateDispatchData,
|
||||
GatewayMessageDeleteBulkDispatchData,
|
||||
GatewayMessageDeleteDispatchData,
|
||||
GatewayMessagePollVoteDispatchData,
|
||||
GatewayMessageReactionAddDispatchData,
|
||||
GatewayMessageReactionRemoveAllDispatchData,
|
||||
GatewayMessageReactionRemoveDispatchData,
|
||||
@ -53,3 +54,11 @@ export const MESSAGE_UPDATE = (
|
||||
> => {
|
||||
return new Message(self, data as APIMessage);
|
||||
};
|
||||
|
||||
export const MESSAGE_POLL_VOTE_ADD = (_: BaseClient, data: GatewayMessagePollVoteDispatchData) => {
|
||||
return toCamelCase(data);
|
||||
};
|
||||
|
||||
export const MESSAGE_POLL_VOTE_REMOVE = (_: BaseClient, data: GatewayMessagePollVoteDispatchData) => {
|
||||
return toCamelCase(data);
|
||||
};
|
||||
|
@ -17,18 +17,20 @@ import { User } from './User';
|
||||
import type { MessageWebhookMethodEditParams, MessageWebhookMethodWriteParams } from './Webhook';
|
||||
import { DiscordBase } from './extra/DiscordBase';
|
||||
import { messageLink } from './extra/functions';
|
||||
import { Poll } from '..';
|
||||
|
||||
export type MessageData = APIMessage | GatewayMessageCreateDispatchData;
|
||||
|
||||
export interface BaseMessage
|
||||
extends DiscordBase,
|
||||
ObjectToLower<Omit<MessageData, 'timestamp' | 'author' | 'mentions' | 'components'>> {}
|
||||
ObjectToLower<Omit<MessageData, 'timestamp' | 'author' | 'mentions' | 'components' | 'poll'>> {}
|
||||
export class BaseMessage extends DiscordBase {
|
||||
guildId: string | undefined;
|
||||
timestamp?: number;
|
||||
author!: User;
|
||||
member?: GuildMember;
|
||||
components: MessageActionRowComponent<ActionRowMessageComponents>[];
|
||||
poll?: Poll;
|
||||
mentions: {
|
||||
roles: string[];
|
||||
channels: APIChannelMention[];
|
||||
@ -111,12 +113,16 @@ export class BaseMessage extends DiscordBase {
|
||||
)
|
||||
: data.mentions.map(u => new User(this.client, u));
|
||||
}
|
||||
|
||||
if (data.poll) {
|
||||
this.poll = new Poll(this.client, data.poll, this.channelId, this.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export interface Message
|
||||
extends BaseMessage,
|
||||
ObjectToLower<Omit<MessageData, 'timestamp' | 'author' | 'mentions' | 'components'>> {}
|
||||
ObjectToLower<Omit<MessageData, 'timestamp' | 'author' | 'mentions' | 'components' | 'poll'>> {}
|
||||
|
||||
export class Message extends BaseMessage {
|
||||
constructor(client: UsingClient, data: MessageData) {
|
||||
|
29
src/structures/Poll.ts
Normal file
29
src/structures/Poll.ts
Normal file
@ -0,0 +1,29 @@
|
||||
import type { APIPoll } from 'discord-api-types/v10';
|
||||
import { toCamelCase, type ObjectToLower } from '../common';
|
||||
import { Base } from './extra/Base';
|
||||
import type { UsingClient } from '../commands';
|
||||
import type { ValidAnswerId } from '../api/Routes/channels';
|
||||
|
||||
export interface Poll extends ObjectToLower<Omit<APIPoll, 'expiry'>> {}
|
||||
|
||||
export class Poll extends Base {
|
||||
expiry: number;
|
||||
constructor(
|
||||
client: UsingClient,
|
||||
data: APIPoll,
|
||||
readonly channelId: string,
|
||||
readonly messageId: string,
|
||||
) {
|
||||
super(client);
|
||||
this.expiry = Date.parse(data.expiry);
|
||||
Object.assign(this, toCamelCase(data));
|
||||
}
|
||||
end() {
|
||||
return this.client.messages.endPoll(this.channelId, this.messageId);
|
||||
}
|
||||
|
||||
getAnswerVoters(id: ValidAnswerId) {
|
||||
if (!this.answers.find(x => x.answerId === id)) throw new Error('Invalid answer id');
|
||||
return this.client.messages.getAnswerVoters(this.channelId, this.messageId, id);
|
||||
}
|
||||
}
|
@ -14,3 +14,4 @@ export * from './User';
|
||||
export * from './VoiceState';
|
||||
export * from './Webhook';
|
||||
export * from './channels';
|
||||
export * from './Poll';
|
||||
|
@ -56,6 +56,7 @@ import {
|
||||
type GatewayVoiceStateUpdateData,
|
||||
type GatewayWebhooksUpdateDispatchData,
|
||||
type PresenceUpdateStatus,
|
||||
type GatewayMessagePollVoteDispatchData,
|
||||
} from 'discord-api-types/v10';
|
||||
import type { RestToKeys } from '../common';
|
||||
import type { GatewayGuildMemberAddDispatchDataFixed } from '../structures';
|
||||
@ -155,6 +156,14 @@ export type StageSameEvents = RestToKeys<
|
||||
]
|
||||
>;
|
||||
|
||||
export type PollVoteSameEvents = RestToKeys<
|
||||
[
|
||||
GatewayMessagePollVoteDispatchData,
|
||||
GatewayDispatchEvents.MessagePollVoteRemove,
|
||||
GatewayDispatchEvents.MessagePollVoteAdd,
|
||||
]
|
||||
>;
|
||||
|
||||
export type IntegrationSameEvents = RestToKeys<
|
||||
[
|
||||
GatewayIntegrationCreateDispatchData,
|
||||
@ -214,6 +223,7 @@ export type NormalizeEvents = Events &
|
||||
GuildScheduledUserSameEvents &
|
||||
IntegrationSameEvents &
|
||||
EntitlementEvents &
|
||||
PollVoteSameEvents &
|
||||
StageSameEvents & { RAW: GatewayDispatchEvents };
|
||||
|
||||
export type GatewayEvents = { [x in keyof NormalizeEvents]: NormalizeEvents[x] };
|
||||
|
Loading…
x
Reference in New Issue
Block a user