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",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"chokidar": "^3.6.0",
|
"chokidar": "^3.6.0",
|
||||||
"discord-api-types": "^0.37.76",
|
"discord-api-types": "^0.37.80",
|
||||||
"magic-bytes.js": "^1.10.0",
|
"magic-bytes.js": "^1.10.0",
|
||||||
"ts-mixer": "^6.0.4",
|
"ts-mixer": "^6.0.4",
|
||||||
"ws": "^8.16.0"
|
"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,
|
RESTGetAPIChannelThreadsArchivedQuery,
|
||||||
RESTGetAPIChannelUsersThreadsArchivedResult,
|
RESTGetAPIChannelUsersThreadsArchivedResult,
|
||||||
RESTGetAPIGuildWebhooksResult,
|
RESTGetAPIGuildWebhooksResult,
|
||||||
|
RESTGetAPIPollAnswerVotersQuery,
|
||||||
|
RESTGetAPIPollAnswerVotersResult,
|
||||||
RESTPatchAPIChannelJSONBody,
|
RESTPatchAPIChannelJSONBody,
|
||||||
RESTPatchAPIChannelMessageJSONBody,
|
RESTPatchAPIChannelMessageJSONBody,
|
||||||
RESTPatchAPIChannelMessageResult,
|
RESTPatchAPIChannelMessageResult,
|
||||||
@ -45,6 +47,7 @@ import type {
|
|||||||
RESTPostAPIChannelWebhookJSONBody,
|
RESTPostAPIChannelWebhookJSONBody,
|
||||||
RESTPostAPIChannelWebhookResult,
|
RESTPostAPIChannelWebhookResult,
|
||||||
RESTPostAPIGuildForumThreadsJSONBody,
|
RESTPostAPIGuildForumThreadsJSONBody,
|
||||||
|
RESTPostAPIPollExpireResult,
|
||||||
RESTPutAPIChannelMessageReactionResult,
|
RESTPutAPIChannelMessageReactionResult,
|
||||||
RESTPutAPIChannelPermissionJSONBody,
|
RESTPutAPIChannelPermissionJSONBody,
|
||||||
RESTPutAPIChannelPermissionResult,
|
RESTPutAPIChannelPermissionResult,
|
||||||
@ -256,5 +259,17 @@ export interface ChannelRoutes {
|
|||||||
'voice-status': {
|
'voice-status': {
|
||||||
put(args: RestArguments<ProxyRequestMethod.Put, { status: string | null }>): Promise<never>;
|
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 './Embed';
|
||||||
export * from './Modal';
|
export * from './Modal';
|
||||||
export * from './SelectMenu';
|
export * from './SelectMenu';
|
||||||
|
export * from './Poll';
|
||||||
export * from './types';
|
export * from './types';
|
||||||
|
|
||||||
export function fromComponent(
|
export function fromComponent(
|
||||||
|
@ -4,10 +4,11 @@ import type {
|
|||||||
RESTPostAPIChannelMessagesThreadsJSONBody,
|
RESTPostAPIChannelMessagesThreadsJSONBody,
|
||||||
} from 'discord-api-types/v10';
|
} from 'discord-api-types/v10';
|
||||||
import { resolveFiles } from '../../builders';
|
import { resolveFiles } from '../../builders';
|
||||||
import { Message, MessagesMethods } from '../../structures';
|
import { Message, MessagesMethods, User } from '../../structures';
|
||||||
|
|
||||||
import type { MessageCreateBodyRequest, MessageUpdateBodyRequest } from '../types/write';
|
import type { MessageCreateBodyRequest, MessageUpdateBodyRequest } from '../types/write';
|
||||||
import { BaseShorter } from './base';
|
import { BaseShorter } from './base';
|
||||||
|
import type { ValidAnswerId } from '../../api/Routes/channels';
|
||||||
|
|
||||||
export class MessageShorter extends BaseShorter {
|
export class MessageShorter extends BaseShorter {
|
||||||
async write(channelId: string, { files, ...body }: MessageCreateBodyRequest) {
|
async write(channelId: string, { files, ...body }: MessageCreateBodyRequest) {
|
||||||
@ -88,4 +89,21 @@ export class MessageShorter extends BaseShorter {
|
|||||||
) {
|
) {
|
||||||
return this.client.threads.fromMessage(channelId, messageId, options);
|
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,
|
APIInteractionResponseChannelMessageWithSource,
|
||||||
APIMessageActionRowComponent,
|
APIMessageActionRowComponent,
|
||||||
APIModalInteractionResponse,
|
APIModalInteractionResponse,
|
||||||
|
RESTAPIPollCreate,
|
||||||
RESTPatchAPIChannelMessageJSONBody,
|
RESTPatchAPIChannelMessageJSONBody,
|
||||||
RESTPatchAPIWebhookWithTokenMessageJSONBody,
|
RESTPatchAPIWebhookWithTokenMessageJSONBody,
|
||||||
RESTPostAPIChannelMessageJSONBody,
|
RESTPostAPIChannelMessageJSONBody,
|
||||||
RESTPostAPIWebhookWithTokenJSONBody,
|
RESTPostAPIWebhookWithTokenJSONBody,
|
||||||
} from 'discord-api-types/v10';
|
} from 'discord-api-types/v10';
|
||||||
import type { RawFile } from '../../api';
|
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';
|
import type { OmitInsert } from './util';
|
||||||
|
|
||||||
@ -21,10 +30,14 @@ export interface ResolverProps {
|
|||||||
files?: AttachmentBuilder[] | Attachment[] | RawFile[] | undefined;
|
files?: AttachmentBuilder[] | Attachment[] | RawFile[] | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface SendResolverProps extends ResolverProps {
|
||||||
|
poll?: PollBuilder | RESTAPIPollCreate | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
export type MessageCreateBodyRequest = OmitInsert<
|
export type MessageCreateBodyRequest = OmitInsert<
|
||||||
RESTPostAPIChannelMessageJSONBody,
|
RESTPostAPIChannelMessageJSONBody,
|
||||||
'components' | 'embeds',
|
'components' | 'embeds' | 'poll',
|
||||||
ResolverProps
|
SendResolverProps
|
||||||
>;
|
>;
|
||||||
|
|
||||||
export type MessageUpdateBodyRequest = OmitInsert<
|
export type MessageUpdateBodyRequest = OmitInsert<
|
||||||
@ -35,8 +48,8 @@ export type MessageUpdateBodyRequest = OmitInsert<
|
|||||||
|
|
||||||
export type MessageWebhookCreateBodyRequest = OmitInsert<
|
export type MessageWebhookCreateBodyRequest = OmitInsert<
|
||||||
RESTPostAPIWebhookWithTokenJSONBody,
|
RESTPostAPIWebhookWithTokenJSONBody,
|
||||||
'components' | 'embeds',
|
'components' | 'embeds' | 'poll',
|
||||||
ResolverProps
|
SendResolverProps
|
||||||
>;
|
>;
|
||||||
|
|
||||||
export type MessageWebhookUpdateBodyRequest = OmitInsert<
|
export type MessageWebhookUpdateBodyRequest = OmitInsert<
|
||||||
|
@ -3,6 +3,7 @@ import type {
|
|||||||
GatewayMessageCreateDispatchData,
|
GatewayMessageCreateDispatchData,
|
||||||
GatewayMessageDeleteBulkDispatchData,
|
GatewayMessageDeleteBulkDispatchData,
|
||||||
GatewayMessageDeleteDispatchData,
|
GatewayMessageDeleteDispatchData,
|
||||||
|
GatewayMessagePollVoteDispatchData,
|
||||||
GatewayMessageReactionAddDispatchData,
|
GatewayMessageReactionAddDispatchData,
|
||||||
GatewayMessageReactionRemoveAllDispatchData,
|
GatewayMessageReactionRemoveAllDispatchData,
|
||||||
GatewayMessageReactionRemoveDispatchData,
|
GatewayMessageReactionRemoveDispatchData,
|
||||||
@ -53,3 +54,11 @@ export const MESSAGE_UPDATE = (
|
|||||||
> => {
|
> => {
|
||||||
return new Message(self, data as APIMessage);
|
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 type { MessageWebhookMethodEditParams, MessageWebhookMethodWriteParams } from './Webhook';
|
||||||
import { DiscordBase } from './extra/DiscordBase';
|
import { DiscordBase } from './extra/DiscordBase';
|
||||||
import { messageLink } from './extra/functions';
|
import { messageLink } from './extra/functions';
|
||||||
|
import { Poll } from '..';
|
||||||
|
|
||||||
export type MessageData = APIMessage | GatewayMessageCreateDispatchData;
|
export type MessageData = APIMessage | GatewayMessageCreateDispatchData;
|
||||||
|
|
||||||
export interface BaseMessage
|
export interface BaseMessage
|
||||||
extends DiscordBase,
|
extends DiscordBase,
|
||||||
ObjectToLower<Omit<MessageData, 'timestamp' | 'author' | 'mentions' | 'components'>> {}
|
ObjectToLower<Omit<MessageData, 'timestamp' | 'author' | 'mentions' | 'components' | 'poll'>> {}
|
||||||
export class BaseMessage extends DiscordBase {
|
export class BaseMessage extends DiscordBase {
|
||||||
guildId: string | undefined;
|
guildId: string | undefined;
|
||||||
timestamp?: number;
|
timestamp?: number;
|
||||||
author!: User;
|
author!: User;
|
||||||
member?: GuildMember;
|
member?: GuildMember;
|
||||||
components: MessageActionRowComponent<ActionRowMessageComponents>[];
|
components: MessageActionRowComponent<ActionRowMessageComponents>[];
|
||||||
|
poll?: Poll;
|
||||||
mentions: {
|
mentions: {
|
||||||
roles: string[];
|
roles: string[];
|
||||||
channels: APIChannelMention[];
|
channels: APIChannelMention[];
|
||||||
@ -111,12 +113,16 @@ export class BaseMessage extends DiscordBase {
|
|||||||
)
|
)
|
||||||
: data.mentions.map(u => new User(this.client, u));
|
: 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
|
export interface Message
|
||||||
extends BaseMessage,
|
extends BaseMessage,
|
||||||
ObjectToLower<Omit<MessageData, 'timestamp' | 'author' | 'mentions' | 'components'>> {}
|
ObjectToLower<Omit<MessageData, 'timestamp' | 'author' | 'mentions' | 'components' | 'poll'>> {}
|
||||||
|
|
||||||
export class Message extends BaseMessage {
|
export class Message extends BaseMessage {
|
||||||
constructor(client: UsingClient, data: MessageData) {
|
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 './VoiceState';
|
||||||
export * from './Webhook';
|
export * from './Webhook';
|
||||||
export * from './channels';
|
export * from './channels';
|
||||||
|
export * from './Poll';
|
||||||
|
@ -56,6 +56,7 @@ import {
|
|||||||
type GatewayVoiceStateUpdateData,
|
type GatewayVoiceStateUpdateData,
|
||||||
type GatewayWebhooksUpdateDispatchData,
|
type GatewayWebhooksUpdateDispatchData,
|
||||||
type PresenceUpdateStatus,
|
type PresenceUpdateStatus,
|
||||||
|
type GatewayMessagePollVoteDispatchData,
|
||||||
} from 'discord-api-types/v10';
|
} from 'discord-api-types/v10';
|
||||||
import type { RestToKeys } from '../common';
|
import type { RestToKeys } from '../common';
|
||||||
import type { GatewayGuildMemberAddDispatchDataFixed } from '../structures';
|
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<
|
export type IntegrationSameEvents = RestToKeys<
|
||||||
[
|
[
|
||||||
GatewayIntegrationCreateDispatchData,
|
GatewayIntegrationCreateDispatchData,
|
||||||
@ -214,6 +223,7 @@ export type NormalizeEvents = Events &
|
|||||||
GuildScheduledUserSameEvents &
|
GuildScheduledUserSameEvents &
|
||||||
IntegrationSameEvents &
|
IntegrationSameEvents &
|
||||||
EntitlementEvents &
|
EntitlementEvents &
|
||||||
|
PollVoteSameEvents &
|
||||||
StageSameEvents & { RAW: GatewayDispatchEvents };
|
StageSameEvents & { RAW: GatewayDispatchEvents };
|
||||||
|
|
||||||
export type GatewayEvents = { [x in keyof NormalizeEvents]: NormalizeEvents[x] };
|
export type GatewayEvents = { [x in keyof NormalizeEvents]: NormalizeEvents[x] };
|
||||||
|
Loading…
x
Reference in New Issue
Block a user