From 966530cdf028d68f84a276018913adc516710f9a Mon Sep 17 00:00:00 2001 From: Autuamn_End Date: Sat, 17 Aug 2024 04:58:42 +0800 Subject: [PATCH 1/8] =?UTF-8?q?:alien:=20=E6=A0=B9=E6=8D=AE=E6=96=87?= =?UTF-8?q?=E6=A1=A3=E6=9B=B4=E6=96=B0=E9=83=A8=E5=88=86=20model=20?= =?UTF-8?q?=E5=92=8C=20types?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nonebot/adapters/discord/api/model.py | 581 +++++++++++++++++++++++--- nonebot/adapters/discord/api/types.py | 270 +++++++++++- 2 files changed, 775 insertions(+), 76 deletions(-) diff --git a/nonebot/adapters/discord/api/model.py b/nonebot/adapters/discord/api/model.py index e418886..0b6469e 100644 --- a/nonebot/adapters/discord/api/model.py +++ b/nonebot/adapters/discord/api/model.py @@ -175,6 +175,14 @@ class ApplicationCommand(BaseModel): when the app is added to a guild, defaults to true""" nsfw: Missing[bool] = UNSET """Indicates whether the command is age-restricted, defaults to false""" + integration_types: Missing[list[ApplicationIntegrationType]] = UNSET + """Installation contexts where the command is available, + only for globally-scoped commands. Defaults to your + app's configured contexts""" + contexts: MissingOrNullable[list[InteractionContextType]] = UNSET + """Interaction context(s) where the command can be used, + only for globally-scoped commands. By default, all + interaction context types included for new commands.""" version: Snowflake """Autoincrementing version identifier updated during substantial record changes""" @@ -478,6 +486,9 @@ class Button(BaseModel): """emoji name, id, and animated""" custom_id: Missing[str] = UNSET """Developer-defined identifier for the button; max 100 characters""" + sku_id: Missing[Snowflake] = UNSET + """Identifier for a purchasable SKU, only + available when using premium-style buttons""" url: Missing[str] = UNSET """URL for link-style buttons""" disabled: Missing[bool] = UNSET @@ -518,15 +529,25 @@ class SelectMenu(BaseModel): """List of channel types to include in the channel select component""" placeholder: Missing[str] = UNSET """Placeholder text if nothing is selected; max 150 characters""" + default_values: Missing["SelectDefaultValue"] = UNSET + """List of default values for auto-populated select + menu components; number of default values must be in + the range defined by min_values and max_values""" min_values: Missing[int] = UNSET """Minimum number of items that must be chosen (defaults to 1); min 0, max 25""" max_values: Missing[int] = UNSET """Maximum number of items that can be chosen (defaults to 1); max 25""" disabled: Missing[bool] = UNSET """Whether select menu is disabled (defaults to false)""" - resolved: Missing["SelectMenuResolved"] = UNSET - """Resolved values for user, role, and channel selects, - can be returned only by the payload, but cannot be set actively""" + + +class SelectDefaultValue(BaseModel): + """see https://discord.com/developers/docs/interactions/message-components#select-menu-object-select-default-value-structure""" + + id: Snowflake + """ID of a user, role, or channel""" + type: Literal["user", "role", "channel"] + """Type of value that `id` represents.""" class SelectOption(BaseModel): @@ -615,13 +636,15 @@ class Interaction(BaseModel): This is always present on application command, message component, and modal submit interaction types. It is optional for future-proofing against new interaction types""" + guild: Missing["Guild"] = UNSET # partial guild object + """Guild that the interaction was sent from""" guild_id: Missing[Snowflake] = UNSET """Guild that the interaction was sent from""" - channel: Missing["Channel"] = UNSET + channel: Missing["Channel"] = UNSET # partial channel object """Channel that the interaction was sent from""" channel_id: Missing[Snowflake] = UNSET """Channel that the interaction was sent from""" - member: Missing["GuildMember"] = UNSET + member: Missing["GuildMember"] = UNSET # guild member object """Guild member data for the invoking user, including permissions""" user: Missing["User"] = UNSET """User object for the invoking user, if invoked in a DM""" @@ -638,6 +661,17 @@ class Interaction(BaseModel): """Selected language of the invoking user""" guild_locale: Missing[str] = UNSET """Guild's preferred locale, if invoked in a guild""" + entitlements: Missing["Entitlement"] = UNSET + """For monetized apps, any entitlements for the + invoking user, representing access to premium SKUs""" + authorizing_integration_owners: dict[ + ApplicationIntegrationType, Union[Snowflake, Literal["0"]] + ] + """Mapping of installation contexts that the interaction + was authorized for to related user or guild IDs. + See Authorizing Integration Owners Object for details""" + context: Missing[InteractionContextType] = UNSET + """Context where the interaction was triggered from""" class ApplicationCommandData(BaseModel): @@ -676,8 +710,10 @@ class MessageComponentData(BaseModel): """the custom_id of the component""" component_type: ComponentType """the type of the component""" - values: Missing[list[str]] = UNSET + values: Missing[list[SelectOption]] = UNSET """values the user selected in a select menu component""" + resolved: Missing["ResolvedData"] = UNSET + """resolved entities from selected options""" class ModalSubmitData(BaseModel): @@ -748,7 +784,7 @@ class ApplicationCommandInteractionDataOption(BaseModel): class MessageInteraction(BaseModel): """Message interaction. - see https://discord.com/developers/docs/interactions/receiving-and-responding#interaction-object + see https://discord.com/developers/docs/interactions/receiving-and-responding#message-interaction-object """ id: Snowflake @@ -759,10 +795,39 @@ class MessageInteraction(BaseModel): """Name of the application command, including subcommands and subcommand groups""" user: "User" """User who invoked the interaction""" - member: Missing["GuildMember"] = UNSET + member: Missing["GuildMember"] = UNSET # partial member object """Member who invoked the interaction in the guild""" +class MessageInteractionMetadata(BaseModel): + """Message Interaction Metadata + + Metadata about the interaction, including the source of the interaction and relevant server and user IDs. + + see https://discord.com/developers/docs/resources/message#message-interaction-metadata-object + """ + + id: Snowflake + """ID of the interaction""" + type: InteractionType + """Type of interaction""" + user: "User" + """User who triggered the interaction""" + authorizing_integration_owners: dict[ + ApplicationIntegrationType, Union[Snowflake, Literal["0"]] + ] + """IDs for installation context(s) related to an interaction. + Details in Authorizing Integration Owners Object""" + original_response_message_id: Missing[Snowflake] = UNSET + """ID of the original response message, present only on follow-up messages""" + interacted_message_id: Missing[Snowflake] = UNSET + """ID of the message that contained interactive component, + present only on messages created from component interactions""" + triggering_interaction_metadata: Missing["MessageInteractionMetadata"] = UNSET + """Metadata for the interaction that was used to open the modal, + present only on modal submit interactions""" + + class InteractionResponse(BaseModel): """Interaction response. @@ -861,6 +926,8 @@ class Application(BaseModel): bot_require_code_grant: bool """when true the app's bot will only join upon completion of the full oauth2 code grant flow""" + bot: Missing["User"] = UNSET # partial user object + """Partial user object for the bot user associated with the app""" terms_of_service_url: Missing[str] = UNSET """the url of the app's terms of service""" privacy_policy_url: Missing[str] = UNSET @@ -876,6 +943,8 @@ class Application(BaseModel): guild_id: Missing[Snowflake] = UNSET """if this application is a game sold on Discord, this field will be the guild to which it has been linked""" + guild: Missing["Guild"] = UNSET # partial guild object + """Partial object of the associated guild""" primary_sku_id: Missing[Snowflake] = UNSET """if this application is a game sold on Discord, this field will be the id of the "Game SKU" that is created, if exists""" @@ -886,16 +955,31 @@ class Application(BaseModel): """the application's default rich presence invite cover image hash""" flags: Missing[ApplicationFlag] = UNSET """the application's public flags""" + approximate_guild_count: Missing[int] = UNSET + """Approximate count of guilds the app has been added to""" + approximate_user_install_count: Missing[int] = UNSET + """Approximate count of users that have installed the app""" + redirect_uris: Missing[list[str]] = UNSET + """Array of redirect URIs for the app""" + interactions_endpoint_url: Missing[str] = UNSET + """Interactions endpoint URL for the app""" + role_connections_verification_url: Missing[str] = UNSET + """Role connection verification URL for the app""" tags: Missing[list[str]] = UNSET """up to 5 tags describing the content and functionality of the application""" install_params: Missing["InstallParams"] = UNSET """settings for the application's default in-app authorization link, if enabled""" + integration_types_config: Missing[ + dict[ + ApplicationIntegrationType, + "ApplicationIntegrationTypeConfiguration", + ] + ] = UNSET + """Default scopes and permissions for each supported + installation context. Value for each key is an integration + type configuration object""" custom_install_url: Missing[str] = UNSET """the application's default custom authorization link, if enabled""" - role_connections_verification_url: Missing[str] = UNSET - """the application's role connection verification entry point, - which when configured will render the app as a verification method - in the guild role verification configuration""" class InstallParams(BaseModel): @@ -910,6 +994,15 @@ class InstallParams(BaseModel): """ the permissions to request for the bot role""" +class ApplicationIntegrationTypeConfiguration(BaseModel): + """Application Integration Type Configuration + + see https://discord.com/developers/docs/resources/application#application-object-application-integration-type-configuration-object + """ + + oauth2_install_params: Missing["InstallParams"] = UNSET + + # Application Role Connection Metadata # see https://discord.com/developers/docs/resources/application-role-connection-metadata @@ -1012,6 +1105,8 @@ class OptionalAuditEntryInfo(BaseModel): """Name of the role if type is "0" (not present if type is "1")""" type: str """Type of overwritten entity - role ("0") or member ("1")""" + integration_type: str + """The type of integration which performed the action""" class AuditLogChange(BaseModel): @@ -1091,6 +1186,8 @@ class TriggerMetadata(BaseModel): mention_total_limit: int """total number of unique role and user mentions allowed per message (Maximum of 50)""" + mention_raid_protection_enabled: bool + """whether to automatically detect mention raids""" class AutoModerationAction(BaseModel): @@ -1190,7 +1287,7 @@ class Channel(BaseModel): """for guild channels: id of the parent category for a channel (each parent category can contain up to 50 channels), for threads: id of the text channel this thread was created""" - last_pin_timestamp: MissingOrNullable[str] = UNSET + last_pin_timestamp: MissingOrNullable[datetime.datetime] = UNSET """when the last pinned message was pinned. This may be null in events such as GUILD_CREATE when a message is not pinned.""" rtc_region: MissingOrNullable[str] = UNSET @@ -1221,10 +1318,10 @@ class Channel(BaseModel): """number of messages ever sent in a thread, it's similar to message_count on message creation, but will not decrement the number when a message is deleted""" available_tags: Missing[list["ForumTag"]] = UNSET - """the set of tags that can be used in a GUILD_FORUM channel""" + """the set of tags that can be used in a GUILD_FORUM or a GUILD_MEDIA channel""" applied_tags: Missing[list[Snowflake]] = UNSET """the IDs of the set of tags that have been applied to a - thread in a GUILD_FORUM channel""" + thread in a GUILD_FORUM or a GUILD_MEDIA channel""" default_reaction_emoji: MissingOrNullable["DefaultReaction"] = UNSET """the emoji to show in the add reaction button on a thread in a GUILD_FORUM channel""" @@ -1243,7 +1340,7 @@ class Channel(BaseModel): class MessageGet(BaseModel): """Message - see https://discord.com/developers/docs/resources/channel#message-object""" + see https://discord.com/developers/docs/resources/message#message-object""" id: Snowflake channel_id: Snowflake @@ -1254,7 +1351,7 @@ class MessageGet(BaseModel): tts: bool mention_everyone: bool mentions: list["User"] - mention_roles: list[str] + mention_roles: list[Snowflake] mention_channels: Missing[list["ChannelMention"]] = UNSET attachments: list["Attachment"] embeds: list["Embed"] @@ -1268,7 +1365,9 @@ class MessageGet(BaseModel): application_id: Missing[Snowflake] = UNSET message_reference: Missing["MessageReference"] = UNSET flags: Missing[MessageFlag] = UNSET + message_snapshots: Missing[list["MessageSnapshot"]] = UNSET referenced_message: MissingOrNullable["MessageGet"] = UNSET + interaction_metadata: Missing[MessageInteractionMetadata] = UNSET interaction: Missing[MessageInteraction] = UNSET thread: Missing[Channel] = UNSET components: Missing[list[DirectComponent]] = UNSET @@ -1276,24 +1375,39 @@ class MessageGet(BaseModel): stickers: Missing[list["Sticker"]] = UNSET position: Missing[int] = UNSET role_subscription_data: Missing["RoleSubscriptionData"] = UNSET + resolved: Missing[ResolvedData] = UNSET + poll: Missing["Poll"] = UNSET + call: Missing["MessageCall"] = UNSET class MessageActivity(BaseModel): """Message activity. - see https://discord.com/developers/docs/resources/channel#message-object-message-activity-structure + see https://discord.com/developers/docs/resources/message#message-object-message-activity-structure """ type: MessageActivityType - party_id: Optional[str] = None + party_id: Missing[str] = UNSET + + +class MessageCall(BaseModel): + """Information about the call in a private channel. + + see https://discord.com/developers/docs/resources/message#message-call-object + """ + + participants: list[Snowflake] + ended_timestamp: MissingOrNullable[datetime.datetime] = UNSET class MessageReference(BaseModel): """Message reference. - see https://discord.com/developers/docs/resources/channel#message-reference-object + see https://discord.com/developers/docs/resources/message#message-reference-object """ + type: Missing[MessageReferenceType] = UNSET + """type of reference.""" message_id: Missing[Snowflake] = UNSET """id of the originating message""" channel_id: Missing[Snowflake] = UNSET @@ -1309,6 +1423,32 @@ class MessageReference(BaseModel): as a normal (non-reply) message, default true""" +class MessageSnapshot(BaseModel): + """Message Snapshot + + While message snapshots are able to support nested snapshots, we currently limit the depth of nesting to 1. + see https://discord.com/developers/docs/resources/message#message-snapshot-object + """ + + message: "MessageSnapshotMessage" + + +class MessageSnapshotMessage(BaseModel): + """partial message object for Message Snapshot + + see https://discord.com/developers/docs/resources/message#message-snapshot-object""" + + type: MessageType + content: str + embeds: list["Embed"] + attachments: list["Attachment"] + timestamp: datetime.datetime + edited_timestamp: Optional[datetime.datetime] = Field(...) + flags: Missing[MessageFlag] = UNSET + mentions: list["User"] + mention_roles: list[Snowflake] + + class FollowedChannel(BaseModel): """Followed channel. @@ -1321,11 +1461,24 @@ class FollowedChannel(BaseModel): class Reaction(BaseModel): """Reaction. - see https://discord.com/developers/docs/resources/channel#reaction-object""" + see https://discord.com/developers/docs/resources/message#reaction-object""" count: int + count_details: "CountDetails" me: bool + me_burst: bool emoji: "Emoji" + burst_colors: list + + +class CountDetails(BaseModel): + """Reaction Count Details + + see https://discord.com/developers/docs/resources/message#reaction-count-details-object + """ + + burst: int + normal: int class Overwrite(BaseModel): @@ -1333,7 +1486,7 @@ class Overwrite(BaseModel): see https://discord.com/developers/docs/resources/channel#overwrite-object""" - id: str + id: Snowflake type: OverwriteType allow: str deny: str @@ -1346,10 +1499,10 @@ class ThreadMetadata(BaseModel): archived: bool auto_archive_duration: int - archive_timestamp: str + archive_timestamp: datetime.datetime locked: bool - invitable: Optional[bool] = None - create_timestamp: Optional[str] = None + invitable: Missing[bool] = UNSET + create_timestamp: MissingOrNullable[datetime.datetime] = UNSET class ThreadMember(BaseModel): @@ -1357,11 +1510,11 @@ class ThreadMember(BaseModel): see https://discord.com/developers/docs/resources/channel#thread-member-object""" - id: Optional[str] = None - user_id: Optional[str] = None - join_timestamp: str + id: Missing[Snowflake] = UNSET + user_id: Missing[Snowflake] = UNSET + join_timestamp: datetime.datetime flags: int - member: Optional["GuildMember"] = None + member: Missing["GuildMember"] = UNSET class DefaultReaction(BaseModel): @@ -1375,14 +1528,14 @@ class DefaultReaction(BaseModel): class ForumTag(BaseModel): """An object that represents a tag that is able to be applied - to a thread in a GUILD_FORUM channel. + to a thread in a GUILD_FORUM or GUILD_MEDIA channel. see https://discord.com/developers/docs/resources/channel#forum-tag-object""" id: Snowflake name: str moderated: bool - emoji_id: MissingOrNullable[Snowflake] = UNSET + emoji_id: Optional[Snowflake] = None emoji_name: Optional[str] = None @@ -1395,7 +1548,7 @@ class Embed(BaseModel): type: Missing[EmbedTypes] = UNSET description: Missing[str] = UNSET url: Missing[str] = UNSET - timestamp: Missing[str] = UNSET + timestamp: Missing[datetime.datetime] = UNSET color: Missing[int] = UNSET footer: Missing["EmbedFooter"] = UNSET image: Missing["EmbedImage"] = UNSET @@ -1409,7 +1562,7 @@ class Embed(BaseModel): class EmbedThumbnail(BaseModel): """Embed thumbnail. - see https://discord.com/developers/docs/resources/channel#embed-object-embed-thumbnail-structure + see https://discord.com/developers/docs/resources/message#embed-object-embed-thumbnail-structure """ url: str @@ -1421,7 +1574,7 @@ class EmbedThumbnail(BaseModel): class EmbedVideo(BaseModel): """Embed video. - see https://discord.com/developers/docs/resources/channel#embed-object-embed-video-structure + see https://discord.com/developers/docs/resources/message#embed-object-embed-video-structure """ url: Missing[str] = UNSET @@ -1433,7 +1586,7 @@ class EmbedVideo(BaseModel): class EmbedImage(BaseModel): """Embed image. - see https://discord.com/developers/docs/resources/channel#embed-object-embed-image-structure + see https://discord.com/developers/docs/resources/message#embed-object-embed-image-structure """ url: str @@ -1445,7 +1598,7 @@ class EmbedImage(BaseModel): class EmbedProvider(BaseModel): """Embed provider. - see https://discord.com/developers/docs/resources/channel#embed-object-embed-provider-structure + see https://discord.com/developers/docs/resources/message#embed-object-embed-provider-structure """ name: Missing[str] = UNSET @@ -1455,7 +1608,7 @@ class EmbedProvider(BaseModel): class EmbedAuthor(BaseModel): """Embed author. - see https://discord.com/developers/docs/resources/channel#embed-object-embed-author-structure + see https://discord.com/developers/docs/resources/message#embed-object-embed-author-structure """ name: str @@ -1467,7 +1620,7 @@ class EmbedAuthor(BaseModel): class EmbedFooter(BaseModel): """Embed footer. - see https://discord.com/developers/docs/resources/channel#embed-object-embed-footer-structure + see https://discord.com/developers/docs/resources/message#embed-object-embed-footer-structure """ text: str @@ -1478,7 +1631,7 @@ class EmbedFooter(BaseModel): class EmbedField(BaseModel): """Embed field. - see https://discord.com/developers/docs/resources/channel#embed-object-embed-field-structure + see https://discord.com/developers/docs/resources/message#embed-object-embed-field-structure """ name: str @@ -1489,10 +1642,11 @@ class EmbedField(BaseModel): class Attachment(BaseModel): """Attachment - see https://discord.com/developers/docs/resources/channel#attachment-object""" + see https://discord.com/developers/docs/resources/message#attachment-object""" - id: str + id: Snowflake filename: str + title: Missing[str] = UNSET description: Missing[str] = UNSET content_type: Missing[str] = UNSET size: int @@ -1500,15 +1654,16 @@ class Attachment(BaseModel): proxy_url: str height: MissingOrNullable[int] = UNSET width: MissingOrNullable[int] = UNSET - ephemeral: MissingOrNullable[bool] = UNSET + ephemeral: Missing[bool] = UNSET duration_secs: Missing[float] = UNSET waveform: Missing[str] = UNSET + flags: Missing[AttachmentFlag] = UNSET class ChannelMention(BaseModel): """Channel mention. - see https://discord.com/developers/docs/resources/channel#channel-mention-object""" + see https://discord.com/developers/docs/resources/message#channel-mention-object""" id: str guild_id: str @@ -1524,7 +1679,7 @@ class AllowedMention(BaseModel): still have @everyone in the message content), and check against user/bot permissions. - see https://discord.com/developers/docs/resources/channel#allowed-mentions-object""" + see https://discord.com/developers/docs/resources/message#allowed-mentions-object""" parse: list[AllowedMentionType] """An array of allowed mention types to parse from the content.""" @@ -1540,7 +1695,7 @@ class AllowedMention(BaseModel): class RoleSubscriptionData(BaseModel): """Role subscription data. - see https://discord.com/developers/docs/resources/channel#role-subscription-data-object + see https://discord.com/developers/docs/resources/message#role-subscription-data-object """ role_subscription_listing_id: str @@ -1628,7 +1783,7 @@ class Emoji(BaseModel): see https://discord.com/developers/docs/resources/emoji#emoji-object""" - id: Optional[str] = None + id: Optional[Snowflake] = None """emoji id""" name: Optional[str] = None """emoji name(can be null only in reaction emoji objects)""" @@ -1695,6 +1850,7 @@ class Guild(BaseModel): nsfw_level: GuildNSFWLevel stickers: Missing[list["Sticker"]] = UNSET premium_progress_bar_enabled: bool + safety_alerts_channel_id: Optional[Snowflake] = Field(...) class CurrentUserGuild(BaseModel): @@ -1708,6 +1864,8 @@ class CurrentUserGuild(BaseModel): owner: Missing[bool] = UNSET permissions: Missing[str] = UNSET features: list[GuildFeature] + approximate_member_count: Missing[int] = UNSET + approximate_presence_count: Missing[int] = UNSET class UnavailableGuild(BaseModel): @@ -1755,11 +1913,38 @@ class GuildWidget(BaseModel): id: Snowflake name: str instant_invite: Optional[str] = None - channels: list["Channel"] # partial channel objects - members: list["User"] # partial user objects + channels: list["GuildWidgetChannel"] + members: list["GuildWidgetUser"] presence_count: int +class GuildWidgetChannel(BaseModel): + """partial channel objects for Guild Widget + + see https://discord.com/developers/docs/resources/guild#guild-widget-object-example-guild-widget + """ + + id: Snowflake + name: str + position: Missing[int] = UNSET + + +class GuildWidgetUser(BaseModel): + """partial user objects for Guild Widget + + The fields id, discriminator and avatar are anonymized to prevent abuse. + + see https://discord.com/developers/docs/resources/guild#guild-widget-object-example-guild-widget + """ + + id: str + username: str + discriminator: str + avatar: Optional[str] = None + status: str + avatar_url: str + + class GuildMember(BaseModel): """Guild Member @@ -1777,6 +1962,7 @@ class GuildMember(BaseModel): pending: Missing[bool] = UNSET permissions: Missing[str] = UNSET communication_disabled_until: MissingOrNullable[datetime.datetime] = UNSET + avatar_decoration_data: MissingOrNullable["AvatarDecorationData"] = UNSET class Integration(BaseModel): @@ -1794,7 +1980,7 @@ class Integration(BaseModel): expire_behavior: Missing[IntegrationExpireBehaviors] = UNSET expire_grace_period: Missing[int] = UNSET user: Missing["User"] = UNSET - account: Optional["IntegrationAccount"] = None + account: "IntegrationAccount" synced_at: Missing[datetime.datetime] = UNSET subscriber_count: Missing[int] = UNSET revoked: Missing[bool] = UNSET @@ -1864,6 +2050,7 @@ class GuildOnboarding(BaseModel): prompts: list["OnboardingPrompt"] default_channel_ids: list[Snowflake] enabled: bool + mode: OnboardingMode class OnboardingPrompt(BaseModel): @@ -1884,13 +2071,19 @@ class OnboardingPrompt(BaseModel): class OnboardingPromptOption(BaseModel): """Onboarding prompt option. + When creating or updating a prompt option, the `emoji_id`, `emoji_name`, and + `emoji_animated` fields must be used instead of the emoji object. + see https://discord.com/developers/docs/resources/guild#guild-onboarding-object-onboarding-prompt-option-structure """ id: Snowflake channel_ids: list[Snowflake] role_ids: list[Snowflake] - emoji: Emoji + emoji: Missing[Emoji] = UNSET + emoji_id: Missing[Snowflake] = UNSET + emoji_name: Missing[str] = UNSET + emoji_animated: Missing[bool] = UNSET title: str description: Optional[str] = None @@ -1926,7 +2119,7 @@ class ModifyGuildParams(BaseModel): see https://discord.com/developers/docs/resources/guild#modify-guild""" - name: str + name: Optional[str] = None region: Optional[str] = None verification_level: Optional[VerificationLevel] = None default_message_notifications: Optional[DefaultMessageNotificationLevel] = None @@ -1969,6 +2162,8 @@ class CreateGuildChannelParams(BaseModel): default_reaction_emoji: Optional[DefaultReaction] = None available_tags: Optional[list[ForumTag]] = None default_sort_order: Optional[SortOrderTypes] = None + default_forum_layout: Optional[ForumLayoutTypes] = None + default_thread_rate_limit_per_user: Optional[int] = None class ListActiveGuildThreadsResponse(BaseModel): @@ -2017,6 +2212,7 @@ class GuildScheduledEvent(BaseModel): creator: Missing["User"] = UNSET user_count: Missing[int] = UNSET image: MissingOrNullable[str] = UNSET + recurrence_rule: Optional["RecurrenceRule"] = None class GuildScheduledEventEntityMetadata(BaseModel): @@ -2054,6 +2250,7 @@ class CreateGuildScheduledEventParams(BaseModel): description: Optional[str] = None entity_type: GuildScheduledEventEntityType image: Optional[str] = None + recurrence_rule: Optional["RecurrenceRule"] = None class ModifyGuildScheduledEventParams(BaseModel): @@ -2072,6 +2269,7 @@ class ModifyGuildScheduledEventParams(BaseModel): entity_type: Optional[GuildScheduledEventEntityType] = None status: Optional[GuildScheduledEventStatus] = None image: Optional[str] = None + recurrence_rule: Optional["RecurrenceRule"] = None # Guild Template @@ -2091,10 +2289,76 @@ class GuildTemplate(BaseModel): created_at: datetime.datetime updated_at: datetime.datetime source_guild_id: Snowflake - serialized_source_guild: "Guild" # partial guild object + serialized_source_guild: "GuildTemplateGuild" is_dirty: Optional[bool] = None +class GuildTemplateGuild(BaseModel): + """partial guild object for GuildTemplate + + see https://discord.com/developers/docs/resources/guild-template#guild-template-object-example-guild-template-object + """ + + name: str + description: Optional[str] = None + region: MissingOrNullable[str] = UNSET + verification_level: VerificationLevel + default_message_notifications: DefaultMessageNotificationLevel + explicit_content_filter: ExplicitContentFilterLevel + preferred_locale: str + afk_channel_id: Optional[Snowflake] = None + afk_timeout: int + system_channel_id: Optional[Snowflake] = None + system_channel_flags: SystemChannelFlags + icon_hash: MissingOrNullable[str] = UNSET + roles: list["GuildTemplateGuildRole"] + channels: list["GuildTemplateGuildChannel"] + + +class GuildTemplateGuildRole(BaseModel): + """partial role object for GuildTemplateGuild + + see https://discord.com/developers/docs/resources/guild-template#guild-template-object-example-guild-template-object + """ + + id: Snowflake + name: str + permissions: str + color: int + hoist: bool + mentionable: bool + icon: MissingOrNullable[str] = UNSET + unicode_emoji: MissingOrNullable[str] = UNSET + + +class GuildTemplateGuildChannel(BaseModel): + """partial role object for GuildTemplateGuild + + see https://discord.com/developers/docs/resources/guild-template#guild-template-object-example-guild-template-object + """ + + id: Snowflake + type: ChannelType + name: MissingOrNullable[str] = UNSET + position: Missing[int] = UNSET + topic: MissingOrNullable[str] = UNSET + bitrate: Missing[int] = UNSET + user_limit: Missing[int] = UNSET + nsfw: Missing[bool] = UNSET + rate_limit_per_user: Missing[int] = UNSET + parent_id: MissingOrNullable[Snowflake] = UNSET + default_auto_archive_duration: MissingOrNullable[int] = UNSET + permission_overwrites: Missing[list["Overwrite"]] = UNSET + available_tags: MissingOrNullable[list["ForumTag"]] = UNSET + template: Missing[str] = UNSET + default_reaction_emoji: MissingOrNullable["DefaultReaction"] = UNSET + default_thread_rate_limit_per_user: MissingOrNullable[int] = UNSET + default_sort_order: MissingOrNullable[SortOrderTypes] = UNSET + default_forum_layout: MissingOrNullable[ForumLayoutTypes] = UNSET + icon_emoji: MissingOrNullable[Emoji] = UNSET + theme_color: MissingOrNullable[int] = UNSET + + # Invite # see https://discord.com/developers/docs/resources/invite class Invite(BaseModel): @@ -2102,14 +2366,14 @@ class Invite(BaseModel): see https://discord.com/developers/docs/resources/invite#invite-object""" + type: InviteType code: str guild: Missing[Guild] = UNSET # partial guild object channel: Optional[Channel] = Field(...) # partial channel object inviter: Missing["User"] = UNSET target_type: Missing["InviteTargetType"] = UNSET target_user: Missing["User"] = UNSET - # partial application object - target_application: Missing["Application"] = UNSET + target_application: Missing["Application"] = UNSET # partial application object approximate_presence_count: Missing[int] = UNSET approximate_member_count: Missing[int] = UNSET expires_at: Missing[datetime.datetime] = UNSET @@ -2132,6 +2396,8 @@ class InviteMetadata(BaseModel): class InviteStageInstance(BaseModel): """Invite Stage Instance + This is deprecated. + see https://discord.com/developers/docs/resources/invite#invite-stage-instance-object """ @@ -2173,6 +2439,7 @@ class Sticker(BaseModel): description: Optional[str] = Field(...) tags: str asset: Missing[str] = UNSET + """Deprecated. previously the sticker asset hash, now an empty string""" type: StickerType format_type: StickerFormatType available: Missing[bool] = UNSET @@ -2228,7 +2495,17 @@ class User(BaseModel): flags: Missing[int] = UNSET premium_type: Missing[PremiumType] = UNSET public_flags: Missing[UserFlags] = UNSET - avatar_decoration: MissingOrNullable[str] = UNSET + avatar_decoration_data: MissingOrNullable["AvatarDecorationData"] = UNSET + + +class AvatarDecorationData(BaseModel): + """Avatar Decoration Data + + see https://discord.com/developers/docs/resources/user#avatar-decoration-data-object + """ + + asset: str + sku_id: Snowflake class Connection(BaseModel): @@ -2240,7 +2517,7 @@ class Connection(BaseModel): name: str type: ConnectionServiceType revoked: Missing[bool] = UNSET - integrations: Missing[list["Integration"]] = UNSET + integrations: Missing[list["Integration"]] = UNSET # partial server integrations verified: bool friend_sync: bool show_activity: bool @@ -2296,14 +2573,21 @@ class VoiceRegion(BaseModel): # Webhook # see https://discord.com/developers/docs/resources/webhook class SourceGuild(BaseModel): - # partial guild object + """partial guild object for Webhook.source_guild + + see https://discord.com/developers/docs/resources/webhook#webhook-object-example-channel-follower-webhook + """ + id: Snowflake name: str icon: Optional[str] = None class SourceChannel(BaseModel): - # partial channel object + """partial channel object for Webhook.source_channel + + see https://discord.com/developers/docs/resources/webhook#webhook-object-example-channel-follower-webhook""" + id: Snowflake name: str @@ -2343,6 +2627,8 @@ class ExecuteWebhookParams(BaseModel): attachments: Optional[list[AttachmentSend]] = None flags: Optional[MessageFlag] = None thread_name: Optional[str] = None + applied_tags: Optional[list[Snowflake]] = None + poll: Optional["Poll"] = None # gateway @@ -2567,7 +2853,7 @@ class ThreadDelete(BaseModel): class ThreadListSync(BaseModel): """Thread List Sync Event Fields - see https://discord.com/developers/docs/topics/gateway-events#thread-list-sync-thread-list-sync-event + see https://discord.com/developers/docs/topics/gateway-events#thread-list-sync """ guild_id: Snowflake @@ -2588,7 +2874,7 @@ class ThreadMemberUpdate(ThreadMember): class ThreadMembersUpdate(BaseModel): """Thread Members Update Event Fields - see https://discord.com/developers/docs/topics/gateway-events#thread-members-update-thread-members-update-event + see https://discord.com/developers/docs/topics/gateway-events#thread-members-update """ id: Snowflake @@ -2761,12 +3047,15 @@ class GuildMemberUpdate(BaseModel): roles: list[Snowflake] user: User nick: MissingOrNullable[str] = UNSET + avatar: Optional[str] = Field(...) joined_at: Optional[datetime.datetime] = Field(...) premium_since: MissingOrNullable[datetime.datetime] = UNSET deaf: Missing[bool] = UNSET mute: Missing[bool] = UNSET pending: Missing[bool] = UNSET communication_disabled_until: MissingOrNullable[datetime.datetime] = UNSET + flags: Missing[GuildMemberFlags] = UNSET + avatar_decoration_data: MissingOrNullable[AvatarDecorationData] = UNSET class GuildMembersChunk(BaseModel): @@ -2893,7 +3182,7 @@ class InviteCreate(BaseModel): max_uses: int target_type: Missing[InviteTargetType] = UNSET target_user: Missing[User] = UNSET - target_application: Missing[Application] = UNSET + target_application: Missing[Application] = UNSET # partial application object temporary: bool uses: int @@ -2999,6 +3288,10 @@ class MessageReactionAdd(BaseModel): guild_id: Missing[Snowflake] = UNSET member: Missing[GuildMember] = UNSET emoji: Emoji # partial emoji object + message_author_id: Missing[Snowflake] = UNSET + burst: bool + burst_colors: Missing[list[str]] = UNSET + type: ReactionType class MessageReactionRemove(BaseModel): @@ -3012,6 +3305,8 @@ class MessageReactionRemove(BaseModel): message_id: Snowflake guild_id: Missing[Snowflake] = UNSET emoji: Emoji # partial emoji object + burst: bool + type: ReactionType class MessageReactionRemoveAll(BaseModel): @@ -3066,7 +3361,7 @@ class PresenceUpdate(BaseModel): """ user: PresenceUpdateUser - guild_id: Missing[Snowflake] = UNSET + guild_id: Snowflake status: PresenceStatus activities: list["Activity"] client_status: "ClientStatus" @@ -3108,7 +3403,7 @@ class Activity(BaseModel): class ActivityTimestamps(BaseModel): """Activity Timestamps - see https://discord.com/developers/docs/topics/gateway-events#activity-object-activity-types + see https://discord.com/developers/docs/topics/gateway-events#activity-object-activity-timestamps """ start: Missing[int] = UNSET @@ -3275,6 +3570,7 @@ class Role(BaseModel): managed: bool mentionable: bool tags: Missing["RoleTags"] = UNSET + flags: RoleFlag class RoleTags(BaseModel): @@ -3312,9 +3608,9 @@ class TeamMember(BaseModel): """ membership_state: MembershipState - permissions: list[str] team_id: Snowflake user: "TeamMemberUser" + role: TeamMemberRoleType class TeamMemberUser(BaseModel): @@ -3338,6 +3634,143 @@ class AuthorizationResponse(BaseModel): user: Missing[User] = UNSET +class Poll(BaseModel): + """The poll object has a lot of levels and nested structures. + It was also designed to support future extensibility, + so some fields may appear to be more complex than necessary. + + see https://discord.com/developers/docs/resources/poll#poll-object + """ + + question: "PollMedia" + """The question of the poll. Only `text` is supported.""" + answers: list["PollAnswer"] + """Each of the answers available in the poll.""" + expiry: datetime.datetime + """The time when the poll ends.""" + allow_multiselect: bool + """Whether a user can select multiple answers""" + layout_type: int + """The layout type of the poll""" + results: Missing["PollResults"] = UNSET + """The results of the poll""" + + +class PollAnswer(BaseModel): + """answer_id: Only sent as part of responses from Discord's API/Gateway. + + see https://discord.com/developers/docs/resources/poll#poll-answer-object + """ + + answer_id: int + poll_media: "PollMedia" + + +class PollMedia(BaseModel): + """The poll media object is a common object that backs both the question and + answers. The intention is that it allows us to extensibly add new ways to + display things in the future. For now, `question` only supports `text`, while + answers can have an optional `emoji`. + + see https://discord.com/developers/docs/resources/poll#poll-media-object + """ + + text: Missing[str] = UNSET + emoji: Missing["Emoji"] = UNSET # partial emoji + + +class PollResults(BaseModel): + """Poll Results + + see https://discord.com/developers/docs/resources/poll#poll-results-object + """ + + is_finalized: bool + answer_counts: list["PollAnswerCount"] + + +class PollAnswerCount(BaseModel): + """Poll Answer Count + + see https://discord.com/developers/docs/resources/poll#poll-results-object-poll-answer-count-object-structure + """ + + id: int + count: int + me_voted: bool + + +class Entitlement(BaseModel): + """see https://discord.com/developers/docs/monetization/entitlements#entitlement-object""" + + id: Snowflake + """ID of the entitlement""" + sku_id: Snowflake + """ID of the SKU""" + application_id: Snowflake + """ID of the parent application""" + user_id: Missing[Snowflake] = UNSET + """ID of the user that is granted access to the entitlement's sku""" + type: EntitlementType + """Type of entitlement""" + deleted: bool + """Entitlement was deleted""" + starts_at: Missing[datetime.datetime] = UNSET + """Start date at which the entitlement is valid. + Not present when using test entitlements.""" + ends_at: Missing[datetime.datetime] = UNSET + """Date at which the entitlement is no longer valid. + Not present when using test entitlements.""" + guild_id: Missing[Snowflake] = UNSET + """ID of the guild that is granted access to the entitlement's sku""" + consumed: Missing[bool] = UNSET + """For consumable items, whether or not the entitlement has been consumed""" + + +class RecurrenceRule(BaseModel): + """Discord's recurrence rule is a subset of the behaviors defined + in the iCalendar RFC and implemented by python's dateutil rrule + + see https://discord.com/developers/docs/resources/guild-scheduled-event#guild-scheduled-event-recurrence-rule-object + """ + + start: datetime.datetime + """Starting time of the recurrence interval""" + end: Optional[datetime.datetime] = None + """Ending time of the recurrence interval""" + frequency: GuildScheduledEventRecurrenceRuleFrequency + """How often the event occurs""" + interval: int + """The spacing between the events, defined by frequency. For example, + frecency of WEEKLY and an interval of 2 would be "every-other week""" + by_weekday: Optional[list[GuildScheduledEventRecurrenceRuleWeekday]] = None + """Set of specific days within a week for the event to recur on""" + by_n_weekday: Optional[ + list["GuildScheduledEventRecurrenceRuleN_WeekdayStructure"] + ] = None + """List of specific days within a specific week (1-5) to recur on""" + by_month: Optional[list[GuildScheduledEventRecurrenceRuleMonth]] = None + """Set of specific months to recur on""" + by_month_day: Optional[int] = None + """Set of specific dates within a month to recur on""" + by_year_day: Optional[int] = None + """Set of days within a year to recur on (1-364)""" + count: Optional[int] = None + """The total amount of times that the event is allowed to recur before stopping""" + + +class GuildScheduledEventRecurrenceRuleN_WeekdayStructure(BaseModel): + """Guild Scheduled Event Recurrence Rule - N_Weekday Structure + + see https://discord.com/developers/docs/resources/guild-scheduled-event#guild-scheduled-event-recurrence-rule-object-guild-scheduled-event-recurrence-rule-nweekday-structure + """ + + n: int + """The week to reoccur on. 1 - 5""" + day: GuildScheduledEventRecurrenceRuleWeekday + """The day within the week to reoccur on""" + + for name, obj in inspect.getmembers(sys.modules[__name__]): if inspect.isclass(obj) and issubclass(obj, BaseModel) and obj is not BaseModel: if PYDANTIC_V2: @@ -3373,6 +3806,7 @@ class AuthorizationResponse(BaseModel): "ComponentEmoji", "Button", "SelectMenu", + "SelectDefaultValue", "SelectOption", "SelectMenuResolved", "TextInput", @@ -3386,6 +3820,7 @@ class AuthorizationResponse(BaseModel): "ResolvedData", "ApplicationCommandInteractionDataOption", "MessageInteraction", + "MessageInteractionMetadata", "InteractionResponse", "InteractionCallbackMessage", "InteractionCallbackAutocomplete", @@ -3393,6 +3828,7 @@ class AuthorizationResponse(BaseModel): "InteractionCallbackData", "Application", "InstallParams", + "ApplicationIntegrationTypeConfiguration", "ApplicationRoleConnectionMetadata", "AuditLog", "AuditLogEntry", @@ -3408,8 +3844,11 @@ class AuthorizationResponse(BaseModel): "MessageGet", "MessageActivity", "MessageReference", + "MessageSnapshot", + "MessageSnapshotMessage", "FollowedChannel", "Reaction", + "CountDetails", "Overwrite", "ThreadMetadata", "ThreadMember", @@ -3439,6 +3878,8 @@ class AuthorizationResponse(BaseModel): "GuildPreview", "GuildWidgetSettings", "GuildWidget", + "GuildWidgetChannel", + "GuildWidgetUser", "GuildMember", "Integration", "IntegrationAccount", @@ -3461,6 +3902,9 @@ class AuthorizationResponse(BaseModel): "CreateGuildScheduledEventParams", "ModifyGuildScheduledEventParams", "GuildTemplate", + "GuildTemplateGuild", + "GuildTemplateGuildRole", + "GuildTemplateGuildChannel", "Invite", "InviteMetadata", "InviteStageInstance", @@ -3469,6 +3913,7 @@ class AuthorizationResponse(BaseModel): "StickerItem", "StickerPack", "User", + "AvatarDecorationData", "Connection", "ApplicationRoleConnection", "VoiceState", @@ -3561,4 +4006,12 @@ class AuthorizationResponse(BaseModel): "TeamMember", "TeamMemberUser", "AuthorizationResponse", + "Poll", + "PollAnswer", + "PollMedia", + "PollResults", + "PollAnswerCount", + "Entitlement", + "RecurrenceRule", + "GuildScheduledEventRecurrenceRuleN_WeekdayStructure", ] diff --git a/nonebot/adapters/discord/api/types.py b/nonebot/adapters/discord/api/types.py index 7542344..aab84ec 100644 --- a/nonebot/adapters/discord/api/types.py +++ b/nonebot/adapters/discord/api/types.py @@ -209,6 +209,18 @@ class ApplicationFlag(IntFlag): """Indicates if an app has registered global application commands""" +class ApplicationIntegrationType(IntEnum): + """Application Integration Type + + see https://discord.com/developers/docs/resources/application#application-object-application-integration-types + """ + + GUILD_INSTALL = 0 + """App is installable to servers""" + USER_INSTALL = 1 + """App is installable to users""" + + class ApplicationRoleConnectionMetadataType(IntEnum): """Application role connection metadata type. @@ -244,7 +256,7 @@ class ApplicationRoleConnectionMetadataType(IntEnum): class AllowedMentionType(StrEnum): """Allowed mentions types. - see https://discord.com/developers/docs/resources/channel#allowed-mentions-object-allowed-mention-types + see https://discord.com/developers/docs/resources/message#allowed-mentions-object-allowed-mention-types """ RoleMentions = "roles" @@ -255,6 +267,16 @@ class AllowedMentionType(StrEnum): """Controls @everyone and @here mentions""" +class AttachmentFlag(IntFlag): + """Attachment Flags + + see https://discord.com/developers/docs/resources/message#attachment-object-attachment-flags + """ + + IS_REMIX = 1 << 2 + """this attachment has been edited using the remix feature on mobile""" + + class AuditLogEventType(IntEnum): """Audit Log Event Type @@ -315,6 +337,15 @@ class AuditLogEventType(IntEnum): AUTO_MODERATION_BLOCK_MESSAGE = 143 AUTO_MODERATION_FLAG_TO_CHANNEL = 144 AUTO_MODERATION_USER_COMMUNICATION_DISABLED = 145 + CREATOR_MONETIZATION_REQUEST_CREATED = 150 + CREATOR_MONETIZATION_TERMS_ACCEPTED = 151 + ONBOARDING_PROMPT_CREATE = 163 + ONBOARDING_PROMPT_UPDATE = 164 + ONBOARDING_PROMPT_DELETE = 165 + ONBOARDING_CREATE = 166 + ONBOARDING_UPDATE = 167 + HOME_SETTINGS_CREATE = 190 + HOME_SETTINGS_UPDATE = 191 class AutoModerationActionType(IntEnum): @@ -330,9 +361,12 @@ class AutoModerationActionType(IntEnum): SEND_ALERT_MESSAGE = 2 """logs user content to a specified channel""" TIMEOUT = 3 - """timeout user for a specified duration. + """timeout user for a specified duration + A TIMEOUT action can only be set up for KEYWORD and MENTION_SPAM rules. The MODERATE_MEMBERS permission is required to use the TIMEOUT action type.""" + BLOCK_MEMBER_INTERACTION = 4 + """prevents a member from using text, voice, or other interactions""" class AutoModerationRuleEventType(IntEnum): @@ -343,6 +377,8 @@ class AutoModerationRuleEventType(IntEnum): MESSAGE_SEND = 1 """when a member sends or edits a message in the guild""" + MEMBER_UPDATE = 2 + """when a member edits their profile""" class ButtonStyle(IntEnum): @@ -361,6 +397,8 @@ class ButtonStyle(IntEnum): """color: red, required field: custom_id""" Link = 5 """color: grey, navigates to a URL, required field: url""" + Premium = 6 + """color: blurple, required field: sku_id""" class ChannelFlags(IntFlag): @@ -375,11 +413,21 @@ class ChannelFlags(IntFlag): """whether a tag is required to be specified when creating a thread in a GUILD_FORUM channel. Tags are specified in the applied_tags field.""" + HIDE_MEDIA_DOWNLOAD_OPTIONS = 1 << 15 + """when set hides the embedded media download options. Available only for + media channels""" class ChannelType(IntEnum): """Channel type. + Type ANNOUNCEMENT_THREAD(10), PUBLIC_THREAD(11) and PRIVATE_THREAD(12) are only + available in API v9 and above. + + The GUILD_MEDIA(16) channel type is still in active development. + Avoid implementing any features that are not documented here, since they are + subject to change without notice! + see https://discord.com/developers/docs/resources/channel#channel-object-channel-types """ @@ -409,6 +457,8 @@ class ChannelType(IntEnum): """the channel in a hub containing the listed servers""" GUILD_FORUM = 15 """Channel that can only contain threads""" + GUILD_MEDIA = 16 + """Channel that can only contain threads, similar to GUILD_FORUM channels""" class ComponentType(IntEnum): @@ -441,16 +491,19 @@ class ConnectionServiceType(StrEnum): see https://discord.com/developers/docs/resources/user#connection-object-services""" Battle_net = "battlenet" + Bungie_net = "bungie" + Domain = "domain" eBay = "ebay" Epic_Games = "epicgames" Facebook = "facebook" - GitHub = "gitHub" + GitHub = "github" Instagram = "instagram" League_of_Legends = "leagueoflegends" - PayPal = "payPal" + PayPal = "paypal" PlayStation_Network = "playstation" Reddit = "reddit" Riot_Games = "riotgames" + Roblox = "roblox" Spotify = "spotify" Skype = "skype" Steam = "steam" @@ -478,7 +531,7 @@ class EmbedTypes(StrEnum): """ Embed types. - see https://discord.com/developers/docs/resources/channel#embed-object-embed-types + see https://discord.com/developers/docs/resources/message#embed-object-embed-types """ rich = "rich" @@ -495,6 +548,30 @@ class EmbedTypes(StrEnum): """link embed""" +class EntitlementType(IntEnum): + """Entitlement Types + + see https://discord.com/developers/docs/monetization/entitlements#entitlement-object-entitlement-types + """ + + PURCHASE = 1 + """Entitlement was purchased by user""" + PREMIUM_SUBSCRIPTION = 2 + """Entitlement for Discord Nitro subscription""" + DEVELOPER_GIFT = 3 + """Entitlement was gifted by developer""" + TEST_MODE_PURCHASE = 4 + """Entitlement was purchased by a dev in application test mode""" + FREE_PURCHASE = 5 + """Entitlement was granted when the SKU was free""" + USER_GIFT = 6 + """Entitlement was gifted by another user""" + PREMIUM_PURCHASE = 7 + """Entitlement was claimed by user for free as a Nitro Subscriber""" + APPLICATION_SUBSCRIPTION = 8 + """Entitlement was purchased as an app subscription""" + + class ExplicitContentFilterLevel(IntEnum): """Explicit content filter level. @@ -798,6 +875,53 @@ class GuildScheduledEventPrivacyLevel(IntEnum): GUILD_ONLY = 2 +class GuildScheduledEventRecurrenceRuleFrequency(IntEnum): + """Guild Scheduled Event Recurrence Rule - Frequency + + see https://discord.com/developers/docs/resources/guild-scheduled-event#guild-scheduled-event-recurrence-rule-object-guild-scheduled-event-recurrence-rule-frequency + """ + + YEARLY = 0 + MONTHLY = 1 + WEEKLY = 2 + DAILY = 3 + + +class GuildScheduledEventRecurrenceRuleWeekday(IntEnum): + """Guild Scheduled Event Recurrence Rule - Weekday + + see https://discord.com/developers/docs/resources/guild-scheduled-event#guild-scheduled-event-recurrence-rule-object-guild-scheduled-event-recurrence-rule-weekday + """ + + MONDAY = 0 + TUESDAY = 1 + WEDNESDAY = 2 + THURSDAY = 3 + FRIDAY = 4 + SATURDAY = 5 + SUNDAY = 6 + + +class GuildScheduledEventRecurrenceRuleMonth(IntEnum): + """Guild Scheduled Event Recurrence Rule - Month + + see https://discord.com/developers/docs/resources/guild-scheduled-event#guild-scheduled-event-recurrence-rule-object-guild-scheduled-event-recurrence-rule-month + """ + + JANUARY = 1 + FEBRUARY = 2 + MARCH = 3 + APRIL = 4 + MAY = 5 + JUNE = 6 + JULY = 7 + AUGUST = 8 + SEPTEMBER = 9 + OCTOBER = 10 + NOVEMBER = 11 + DECEMBER = 12 + + class GuildScheduledEventStatus(IntEnum): """Guild Scheduled Event Status @@ -812,6 +936,20 @@ class GuildScheduledEventStatus(IntEnum): CANCELED = 4 +class InteractionContextType(IntEnum): + """Interaction Context Type + + see https://discord.com/developers/docs/interactions/receiving-and-responding#interaction-object-interaction-context-types + """ + + GUILD = 0 + """Interaction can be used within servers""" + BOT_DM = 1 + """Interaction can be used within DMs with the app's bot user""" + PRIVATE_CHANNEL = 2 + """Interaction can be used within Group DMs and DMs other than the app's bot user""" + + class IntegrationExpireBehaviors(IntEnum): """Integration Expire Behaviors @@ -819,7 +957,7 @@ class IntegrationExpireBehaviors(IntEnum): """ RemoveRole = 0 - Kick = 0 + Kick = 1 class InteractionType(IntEnum): @@ -870,6 +1008,17 @@ class InviteTargetType(IntEnum): EMBEDDED_APPLICATION = 2 +class InviteType(IntEnum): + """Invite Types + + see https://discord.com/developers/docs/resources/invite#invite-object-invite-types + """ + + GUILD = 0 + GROUP_DM = 1 + FRIEND = 2 + + class KeywordPresetType(IntEnum): """Keyword preset type. @@ -887,7 +1036,7 @@ class KeywordPresetType(IntEnum): class MessageActivityType(IntEnum): """Message activity type. - see https://discord.com/developers/docs/resources/channel#message-object-message-activity-types + see https://discord.com/developers/docs/resources/message#message-object-message-activity-types """ JOIN = 1 @@ -899,7 +1048,7 @@ class MessageActivityType(IntEnum): class MessageFlag(IntFlag): """Message flags. - see https://discord.com/developers/docs/resources/channel#message-object-message-flags + see https://discord.com/developers/docs/resources/message#message-object-message-flags """ CROSSPOSTED = 1 << 0 @@ -922,7 +1071,25 @@ class MessageFlag(IntFlag): FAILED_TO_MENTION_SOME_ROLES_IN_THREAD = 1 << 8 """this message failed to mention some roles and add their members to the thread""" SUPPRESS_NOTIFICATIONS = 1 << 12 - """ this message will not trigger push and desktop notifications""" + """this message will not trigger push and desktop notifications""" + IS_VOICE_MESSAGE = 1 << 13 + """this message is a voice message""" + + +class MessageReferenceType(IntEnum): + """Message Reference Types + + Determines how associated data is populated. + + see https://discord.com/developers/docs/resources/message#message-reference-types + """ + + DEFAULT = 0 + """A standard reference used by replies. + Coupled Message Field: `referenced_message`""" + FORWARD = 1 + """Reference used to point to a message at a point in time. + Coupled Message Field: `message_snapshot`""" class MessageType(IntEnum): @@ -930,7 +1097,7 @@ class MessageType(IntEnum): In v6, they are represented as type DEFAULT(0). Additionally, type THREAD_STARTER_MESSAGE(21) is only available in API v9 and above. - see https://discord.com/developers/docs/resources/channel#message-object-message-types + see https://discord.com/developers/docs/resources/message#message-object-message-types """ DEFAULT = 0 @@ -964,6 +1131,11 @@ class MessageType(IntEnum): STAGE_SPEAKER = 29 STAGE_TOPIC = 31 GUILD_APPLICATION_PREMIUM_SUBSCRIPTION = 32 + GUILD_INCIDENT_ALERT_MODE_ENABLED = 36 + GUILD_INCIDENT_ALERT_MODE_DISABLED = 37 + GUILD_INCIDENT_REPORT_RAID = 38 + GUILD_INCIDENT_REPORT_FALSE_ALARM = 39 + PURCHASE_NOTIFICATION = 44 class MembershipState(IntEnum): @@ -995,10 +1167,24 @@ class MutableGuildFeature(StrEnum): COMMUNITY = "COMMUNITY" """Enables Community Features in the guild""" - INVITES_DISABLED = "INVITES_DISABLED" - """Pauses all invites/access to the server""" DISCOVERABLE = "DISCOVERABLE" """Enables discovery in the guild, making it publicly listed""" + INVITES_DISABLED = "INVITES_DISABLED" + """Pauses all invites/access to the server""" + RAID_ALERTS_DISABLED = "RAID_ALERTS_DISABLED" + """Disables alerts for join raids""" + + +class OnboardingMode(IntEnum): + """Defines the criteria used to satisfy Onboarding constraints that are required for enabling. + + see https://discord.com/developers/docs/resources/guild#guild-onboarding-object-onboarding-mode + """ + + ONBOARDING_DEFAULT = 0 + """Counts only Default Channels towards constraints""" + ONBOARDING_ADVANCED = 1 + """Counts Default Channels and Questions towards constraints""" class OnboardingPromptType(IntEnum): @@ -1059,6 +1245,26 @@ class PresenceStatus(StrEnum): OFFLINE = "offline" +class ReactionType(IntEnum): + """Reaction Types + + see https://discord.com/developers/docs/resources/message#get-reactions-reaction-types + """ + + NORMAL = 0 + BURST = 1 + + +class RoleFlag(IntFlag): + """Role Flags + + see https://discord.com/developers/docs/topics/permissions#role-object-role-flags + """ + + IN_PROMPT = 1 << 0 + """role can be selected by members in an onboarding prompt""" + + class SortOrderTypes(IntEnum): """Sort order types. @@ -1127,6 +1333,31 @@ class SystemChannelFlags(IntFlag): """Hide role subscription sticker reply buttons""" +class TeamMemberRoleType(StrEnum): + """Team Member Role Types + + see https://discord.com/developers/docs/topics/teams#team-member-roles""" + + # Owner = "" + # """Owners are the most permissible role, and can take destructive, + # irreversible actions like deleting team-owned apps or the team itself. + # Teams are limited to 1 owner.""" + Admin = "admin" + """Admins have similar access as owners, except they cannot take + destructive actions on the team or team-owned apps.""" + Developer = "developer" + """Developers can access information about team-owned apps, + like the client secret or public key. They can also take limited + actions on team-owned apps, like configuring interaction endpoints or + resetting the bot token. Members with the Developer role cannot manage + the team or its members, or take destructive actions on team-owned apps.""" + Read_only = "read_only" + """Read-only members can access information about a team and + any team-owned apps. Some examples include getting the IDs of + applications and exporting payout records. Members can also + invite bots associated with team-owned apps that are marked private.""" + + class TextInputStyle(IntEnum): """TextSegment input style. @@ -1175,6 +1406,8 @@ class TriggerType(IntEnum): """check if content contains words from internal pre-defined wordsets""" MENTION_SPAM = 5 """check if content contains more unique mentions than allowed""" + MEMBER_PROFILE = 6 + """check if member profile contains words from a user defined list of keywords""" class UpdatePresenceStatusType(StrEnum): @@ -1301,8 +1534,10 @@ class WebhookType(IntEnum): "ApplicationCommandPermissionsType", "ApplicationCommandType", "ApplicationFlag", + "ApplicationIntegrationType", "ApplicationRoleConnectionMetadataType", "AllowedMentionType", + "AttachmentFlag", "AuditLogEventType", "AutoModerationActionType", "AutoModerationRuleEventType", @@ -1313,6 +1548,7 @@ class WebhookType(IntEnum): "ConnectionServiceType", "DefaultMessageNotificationLevel", "EmbedTypes", + "EntitlementType", "ExplicitContentFilterLevel", "ForumLayoutTypes", "GuildFeature", @@ -1320,28 +1556,38 @@ class WebhookType(IntEnum): "GuildNSFWLevel", "GuildScheduledEventEntityType", "GuildScheduledEventPrivacyLevel", + "GuildScheduledEventRecurrenceRuleFrequency", + "GuildScheduledEventRecurrenceRuleWeekday", + "GuildScheduledEventRecurrenceRuleMonth", "GuildScheduledEventStatus", + "InteractionContextType", "IntegrationExpireBehaviors", "InteractionType", "InteractionCallbackType", "InviteTargetType", + "InviteType", "KeywordPresetType", "MessageActivityType", "MessageFlag", + "MessageReferenceType", "MessageType", "MembershipState", "MFALevel", "MutableGuildFeature", + "OnboardingMode", "OnboardingPromptType", "OverwriteType", "PremiumTier", "PremiumType", "PresenceStatus", + "ReactionType", + "RoleFlag", "SortOrderTypes", "StagePrivacyLevel", "StickerFormatType", "StickerType", "SystemChannelFlags", + "TeamMemberRoleType", "TextInputStyle", "TimeStampStyle", "TriggerType", From d4b218fc8dd847d5ffab9793bf45eea33d93f69a Mon Sep 17 00:00:00 2001 From: Autuamn_End Date: Wed, 4 Sep 2024 21:47:13 +0800 Subject: [PATCH 2/8] =?UTF-8?q?:bug:=20=E9=AA=8C=E8=AF=81=E9=83=A8?= =?UTF-8?q?=E5=88=86=20partial=20types?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nonebot/adapters/discord/api/model.py | 48 ++++++++++++++++++++++----- 1 file changed, 40 insertions(+), 8 deletions(-) diff --git a/nonebot/adapters/discord/api/model.py b/nonebot/adapters/discord/api/model.py index 0b6469e..fed5bf2 100644 --- a/nonebot/adapters/discord/api/model.py +++ b/nonebot/adapters/discord/api/model.py @@ -636,7 +636,7 @@ class Interaction(BaseModel): This is always present on application command, message component, and modal submit interaction types. It is optional for future-proofing against new interaction types""" - guild: Missing["Guild"] = UNSET # partial guild object + guild: Missing["InteractionGuild"] = UNSET """Guild that the interaction was sent from""" guild_id: Missing[Snowflake] = UNSET """Guild that the interaction was sent from""" @@ -661,7 +661,7 @@ class Interaction(BaseModel): """Selected language of the invoking user""" guild_locale: Missing[str] = UNSET """Guild's preferred locale, if invoked in a guild""" - entitlements: Missing["Entitlement"] = UNSET + entitlements: Missing[list["Entitlement"]] = UNSET """For monetized apps, any entitlements for the invoking user, representing access to premium SKUs""" authorizing_integration_owners: dict[ @@ -674,6 +674,14 @@ class Interaction(BaseModel): """Context where the interaction was triggered from""" +class InteractionGuild(BaseModel): + """partial guild object for Interaction""" + + id: Snowflake + locale: Missing[str] = UNSET + features: list[GuildFeature] + + class ApplicationCommandData(BaseModel): """Sent in APPLICATION_COMMAND and APPLICATION_COMMAND_AUTOCOMPLETE interactions. @@ -961,9 +969,13 @@ class Application(BaseModel): """Approximate count of users that have installed the app""" redirect_uris: Missing[list[str]] = UNSET """Array of redirect URIs for the app""" - interactions_endpoint_url: Missing[str] = UNSET + interactions_endpoint_url: MissingOrNullable[str] = ( + UNSET # return type not match the docs + ) """Interactions endpoint URL for the app""" - role_connections_verification_url: Missing[str] = UNSET + role_connections_verification_url: MissingOrNullable[str] = ( + UNSET # return type not match the docs + ) """Role connection verification URL for the app""" tags: Missing[list[str]] = UNSET """up to 5 tags describing the content and functionality of the application""" @@ -1919,7 +1931,7 @@ class GuildWidget(BaseModel): class GuildWidgetChannel(BaseModel): - """partial channel objects for Guild Widget + """partial channel objects for GuildWidget.channels see https://discord.com/developers/docs/resources/guild#guild-widget-object-example-guild-widget """ @@ -1930,7 +1942,7 @@ class GuildWidgetChannel(BaseModel): class GuildWidgetUser(BaseModel): - """partial user objects for Guild Widget + """partial user objects for GuildWidget.members The fields id, discriminator and avatar are anonymized to prevent abuse. @@ -2368,7 +2380,7 @@ class Invite(BaseModel): type: InviteType code: str - guild: Missing[Guild] = UNSET # partial guild object + guild: Missing["InviteGuild"] = Field(...) channel: Optional[Channel] = Field(...) # partial channel object inviter: Missing["User"] = UNSET target_type: Missing["InviteTargetType"] = UNSET @@ -2376,11 +2388,30 @@ class Invite(BaseModel): target_application: Missing["Application"] = UNSET # partial application object approximate_presence_count: Missing[int] = UNSET approximate_member_count: Missing[int] = UNSET - expires_at: Missing[datetime.datetime] = UNSET + expires_at: MissingOrNullable[datetime.datetime] = UNSET stage_instance: Missing["StageInstance"] = UNSET guild_scheduled_event: Missing["GuildScheduledEvent"] = UNSET +class InviteGuild(BaseModel): + """partial guild object for Invite.guild + + see https://discord.com/developers/docs/resources/invite#invite-object-example-invite-object + """ + + id: Snowflake + name: str + splash: Optional[str] = None + banner: Optional[str] = None + description: Optional[str] = None + icon: Optional[str] = None + features: list[GuildFeature] + verification_level: VerificationLevel + vanity_url_code: Optional[str] = None + nsfw_level: GuildNSFWLevel + premium_subscription_count: Optional[int] = None + + class InviteMetadata(BaseModel): """Invite Metadata @@ -3906,6 +3937,7 @@ class GuildScheduledEventRecurrenceRuleN_WeekdayStructure(BaseModel): "GuildTemplateGuildRole", "GuildTemplateGuildChannel", "Invite", + "InviteGuild", "InviteMetadata", "InviteStageInstance", "StageInstance", From 43b6ea709b6740b1933f11c1075884f027f7d8f5 Mon Sep 17 00:00:00 2001 From: Autuamn_End Date: Wed, 11 Sep 2024 13:01:58 +0800 Subject: [PATCH 3/8] =?UTF-8?q?:sparkles:=20=E6=89=A9=E5=85=85=20API?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nonebot/adapters/discord/api/client.pyi | 238 ++++++++- nonebot/adapters/discord/api/handle.py | 617 +++++++++++++++++++++--- nonebot/adapters/discord/api/model.py | 117 +++++ nonebot/adapters/discord/api/types.py | 49 ++ 4 files changed, 922 insertions(+), 99 deletions(-) diff --git a/nonebot/adapters/discord/api/client.pyi b/nonebot/adapters/discord/api/client.pyi index 5342601..4d66aea 100644 --- a/nonebot/adapters/discord/api/client.pyi +++ b/nonebot/adapters/discord/api/client.pyi @@ -205,9 +205,47 @@ class ApiClient: interaction_token: str, message_id: SnowflakeType, ) -> None: ... - async def get_current_application( - self, *, application_id: SnowflakeType - ) -> Application: ... + async def get_current_application(self) -> Application: + """Returns the application object associated with the requesting bot user + + see https://discord.com/developers/docs/resources/application#get-current-application + """ + ... + + async def edit_current_application( + self, + *, + custom_install_url: str | None = ..., + description: str | None = ..., + role_connections_verification_url: str | None = ..., + install_params: InstallParams | None = ..., + integration_types_config: ( + dict[ + ApplicationIntegrationType, + ApplicationIntegrationTypeConfiguration, + ] + | None + ) = ..., + flags: ApplicationFlag | None = ..., + icon: str | None = ..., + cover_image: str | None = ..., + interactions_endpoint_url: str | None = ..., + tags: list[str] | None = ..., + ) -> Application: + """Edit properties of the app associated with the requesting bot user. + + see https://discord.com/developers/docs/resources/application#edit-current-application + """ + ... + + async def get_application_activity_instance( + self, *, application_id: SnowflakeType, instance_id: str + ) -> ActivityInstance: + """Returns a serialized activity instance, if it exists. Useful for preventing unwanted activity sessions. + + see https://discord.com/developers/docs/resources/application#get-application-activity-instance + """ + ... async def get_application_role_connection_metadata_records( self, *, application_id: SnowflakeType ) -> list[ApplicationRoleConnectionMetadata]: @@ -393,7 +431,7 @@ class ApiClient: ) -> list[MessageGet]: """get channel messages - see https://discord.com/developers/docs/resources/channel#get-channel-messages + see https://discord.com/developers/docs/resources/message#get-channel-messages """ ... @@ -402,7 +440,7 @@ class ApiClient: ) -> MessageGet: """get channel message - see https://discord.com/developers/docs/resources/channel#get-channel-message""" + see https://discord.com/developers/docs/resources/message#get-channel-message""" ... async def create_message( @@ -423,7 +461,7 @@ class ApiClient: ) -> MessageGet: """create message - see https://discord.com/developers/docs/resources/channel#create-message + see https://discord.com/developers/docs/resources/message#create-message """ ... @@ -432,7 +470,7 @@ class ApiClient: ) -> MessageGet: """crosspost message - see https://discord.com/developers/docs/resources/channel#crosspost-message""" + see https://discord.com/developers/docs/resources/message#crosspost-message""" ... async def create_reaction( @@ -445,7 +483,7 @@ class ApiClient: ) -> None: """create reaction - see https://discord.com/developers/docs/resources/channel#create-reaction""" + see https://discord.com/developers/docs/resources/message#create-reaction""" ... async def delete_own_reaction( @@ -458,7 +496,7 @@ class ApiClient: ) -> None: """delete own reaction - see https://discord.com/developers/docs/resources/channel#delete-own-reaction""" + see https://discord.com/developers/docs/resources/message#delete-own-reaction""" ... async def delete_user_reaction( @@ -472,7 +510,7 @@ class ApiClient: ) -> None: """delete user reaction - see https://discord.com/developers/docs/resources/channel#delete-user-reaction + see https://discord.com/developers/docs/resources/message#delete-user-reaction """ ... @@ -488,7 +526,7 @@ class ApiClient: ) -> list[User]: """get reactions - see https://discord.com/developers/docs/resources/channel#get-reactions""" + see https://discord.com/developers/docs/resources/message#get-reactions""" ... async def delete_all_reactions( @@ -499,7 +537,7 @@ class ApiClient: ) -> None: """ - see https://discord.com/developers/docs/resources/channel#delete-all-reactions + see https://discord.com/developers/docs/resources/message#delete-all-reactions """ ... @@ -513,7 +551,7 @@ class ApiClient: ) -> None: """ - see https://discord.com/developers/docs/resources/channel#delete-all-reactions + see https://discord.com/developers/docs/resources/message#delete-all-reactions """ ... @@ -530,7 +568,7 @@ class ApiClient: files: list[File] | None = ..., attachments: list[AttachmentSend] | None = ..., ) -> MessageGet: - """see https://discord.com/developers/docs/resources/channel#edit-message""" + """see https://discord.com/developers/docs/resources/message#edit-message""" ... async def delete_message( @@ -540,7 +578,7 @@ class ApiClient: message_id: SnowflakeType, reason: str | None = ..., ) -> None: - """https://discord.com/developers/docs/resources/channel#delete-message""" + """https://discord.com/developers/docs/resources/message#delete-message""" ... async def bulk_delete_message( @@ -550,7 +588,7 @@ class ApiClient: messages: list[SnowflakeType], reason: str | None = ..., ) -> None: - """https://discord.com/developers/docs/resources/channel#bulk-delete-messages""" + """https://discord.com/developers/docs/resources/message#bulk-delete-messages""" ... async def edit_channel_permissions( @@ -810,6 +848,83 @@ class ApiClient: """https://discord.com/developers/docs/resources/emoji#delete-guild-emoji""" ... + async def list_application_emojis( + self, *, application_id: SnowflakeType + ) -> ApplicationEmojis: + """https://discord.com/developers/docs/resources/emoji#list-application-emojis""" + ... + + async def get_application_emoji( + self, + *, + application_id: SnowflakeType, + emoji_id: SnowflakeType, + ) -> Emoji: + """https://discord.com/developers/docs/resources/emoji#get-application-emoji""" + ... + + async def create_application_emoji( + self, *, application_id: SnowflakeType, name: str = ..., image: str = ... + ) -> Emoji: + """https://discord.com/developers/docs/resources/emoji#create-application-emoji""" + ... + + async def modify_application_emoji( + self, *, application_id: SnowflakeType, emoji_id: SnowflakeType, name: str = ... + ) -> Emoji: + """https://discord.com/developers/docs/resources/emoji#modify-application-emoji""" + ... + + async def delete_application_emoji( + self, *, application_id: SnowflakeType, emoji_id: SnowflakeType + ) -> None: + """https://discord.com/developers/docs/resources/emoji#delete-application-emoji""" + ... + + async def list_entitlements( + self, + *, + application_id: SnowflakeType, + user_id: SnowflakeType | None = ..., + sku_ids: tuple[SnowflakeType] | None = ..., + before: SnowflakeType | None = ..., + after: SnowflakeType | None = ..., + limit: int | None = ..., + guild_id: SnowflakeType | None = ..., + exclude_ended: bool | None = ..., + ) -> list[Entitlement]: + """https://discord.com/developers/docs/resources/entitlement#list-entitlements""" + ... + + async def consume_an_entitlement( + self, + *, + application_id: SnowflakeType, + entitlement_id: SnowflakeType, + ) -> None: + """https://discord.com/developers/docs/resources/entitlement#consume-an-entitlement""" + ... + + async def create_test_entitlement( + self, + *, + application_id: SnowflakeType, + sku_id: str = ..., + owner_id: str = ..., + owner_type: int = ..., + ) -> Entitlement: + """https://discord.com/developers/docs/resources/entitlement#create-test-entitlement""" + ... + + async def delete_test_entitlement( + self, + *, + application_id: SnowflakeType, + entitlement_id: SnowflakeType, + ) -> None: + """https://discord.com/developers/docs/resources/entitlement#create-test-entitlement""" + ... + async def create_guild( self, *, @@ -1067,10 +1182,27 @@ class ApiClient: """https://discord.com/developers/docs/resources/guild#remove-guild-ban""" ... + async def bulk_guild_ban( + self, + *, + guild_id: SnowflakeType, + user_ids: list[SnowflakeType] = ..., + delete_message_seconds: int | None = ..., + reason: str | None = ..., + ) -> BulkBan: + """https://discord.com/developers/docs/resources/guild#bulk-guild-ban""" + ... + async def get_guild_roles(self, *, guild_id: SnowflakeType) -> list[Role]: """https://discord.com/developers/docs/resources/guild#get-guild-roles""" ... + async def get_guild_role( + self, *, guild_id: SnowflakeType, role_id: SnowflakeType + ) -> Role: + """https://discord.com/developers/docs/resources/guild#get-guild-role""" + ... + async def create_guild_role( self, *, @@ -1233,6 +1365,35 @@ class ApiClient: """https://discord.com/developers/docs/resources/guild#get-guild-onboarding""" ... + async def modify_guild_onboarding( + self, + *, + guild_id: SnowflakeType, + prompts: list[OnboardingPrompt] = ..., + default_channel_ids: list[Snowflake] = ..., + enabled: bool = ..., + mode: OnboardingMode = ..., + reason: str | None = ..., + ) -> GuildOnboarding: + """https://discord.com/developers/docs/resources/guild#get-guild-onboarding""" + ... + + async def list_voice_regions(self) -> list[VoiceRegion]: + """https://discord.com/developers/docs/resources/voice#list-voice-regions""" + ... + + async def get_current_user_voice_state( + self, *, guild_id: SnowflakeType + ) -> VoiceState: + """https://discord.com/developers/docs/resources/voice#get-current-user-voice-state""" + ... + + async def get_user_voice_state( + self, *, guild_id: SnowflakeType, user_id: SnowflakeType + ) -> VoiceState: + """https://discord.com/developers/docs/resources/voice#get-user-voice-state""" + ... + async def modify_current_user_voice_state( self, *, @@ -1390,6 +1551,31 @@ class ApiClient: """https://discord.com/developers/docs/resources/invite#delete-invite""" ... + async def get_answer_voters( + self, + *, + channel_id: SnowflakeType, + message_id: SnowflakeType, + answer_id: int, + after: SnowflakeType | None = ..., + limit: int | None = ..., + ) -> AnswerVoters: + """https://discord.com/developers/docs/resources/poll#get-answer-voters""" + ... + + async def end_poll( + self, + *, + channel_id: SnowflakeType, + message_id: SnowflakeType, + ) -> MessageGet: + """https://discord.com/developers/docs/resources/poll#end-poll""" + ... + + async def list_SKUs(self, *, application_id: SnowflakeType) -> list[SKU]: + """https://discord.com/developers/docs/resources/sku#list-skus""" + ... + async def create_stage_instance( self, *, @@ -1433,6 +1619,10 @@ class ApiClient: """https://discord.com/developers/docs/resources/sticker#list-nitro-sticker-packs""" ... + async def get_sticker_packs(self, *, pack_id: SnowflakeType) -> StickerPack: + """https://discord.com/developers/docs/resources/sticker#get-sticker-pack""" + ... + async def list_guild_stickers(self, *, guild_id: SnowflakeType) -> list[Sticker]: """https://discord.com/developers/docs/resources/sticker#list-guild-stickers""" ... @@ -1475,6 +1665,16 @@ class ApiClient: """https://discord.com/developers/docs/resources/sticker#delete-guild-sticker""" ... + async def list_SKU_subscriptions( + self, *, sku_id: SnowflakeType + ) -> list[Subscription]: + """https://discord.com/developers/docs/resources/subscription#list-sku-subscriptions""" + ... + + async def get_SKU_subscription(self, *, sku_id: SnowflakeType) -> Subscription: + """https://discord.com/developers/docs/resources/subscription#list-sku-subscriptions""" + ... + async def get_current_user(self) -> User: """https://discord.com/developers/docs/resources/user#get-current-user""" ... @@ -1540,10 +1740,6 @@ class ApiClient: """https://discord.com/developers/docs/resources/user#modify-current-user""" ... - async def list_voice_regions(self) -> list[VoiceRegion]: - """https://discord.com/developers/docs/resources/voice#list-voice-regions""" - ... - async def create_webhook( self, *, @@ -1742,7 +1938,7 @@ class ApiClient: ... async def get_current_bot_application_information(self) -> Application: - """https://discord.com/developers/docs/resources/user#get-current-application-information""" + """https://discord.com/developers/docs/topics/oauth2#get-current-bot-application-information""" ... async def get_current_authorization_information(self) -> AuthorizationResponse: diff --git a/nonebot/adapters/discord/api/handle.py b/nonebot/adapters/discord/api/handle.py index a9c21ed..ba3734e 100644 --- a/nonebot/adapters/discord/api/handle.py +++ b/nonebot/adapters/discord/api/handle.py @@ -376,7 +376,7 @@ async def _edit_application_command_permissions( You can add up to 100 permission overwrites for a command. - see https://discord.com/developers/docs/interactions/application-commands#get-guild-application-command-permissions + see https://discord.com/developers/docs/interactions/application-commands#edit-application-command-permissions """ headers = {"Authorization": adapter.get_authorization(bot.bot_info)} request = Request( @@ -402,6 +402,7 @@ async def _create_interaction_response( interaction_token: str, response: InteractionResponse, ) -> None: + """https://discord.com/developers/docs/interactions/receiving-and-responding#create-interaction-response""" params = parse_interaction_response(response) headers = {"Authorization": adapter.get_authorization(bot.bot_info)} request = Request( @@ -420,6 +421,7 @@ async def _get_origin_interaction_response( application_id: SnowflakeType, interaction_token: str, ) -> MessageGet: + """https://discord.com/developers/docs/interactions/receiving-and-responding#get-original-interaction-response""" headers = {"Authorization": adapter.get_authorization(bot.bot_info)} request = Request( headers=headers, @@ -437,6 +439,7 @@ async def _edit_origin_interaction_response( interaction_token: str, **data, ) -> MessageGet: + """https://discord.com/developers/docs/interactions/receiving-and-responding#edit-original-interaction-response""" params = {} if data.get("thread_id"): params["thread_id"] = data.pop("thread_id") @@ -459,6 +462,7 @@ async def _delete_origin_interaction_response( interaction_token: str, **data, ) -> None: + """https://discord.com/developers/docs/interactions/receiving-and-responding#delete-original-interaction-response""" headers = {"Authorization": adapter.get_authorization(bot.bot_info)} request = Request( headers=headers, @@ -477,6 +481,7 @@ async def _create_followup_message( interaction_token: str, **data, ) -> MessageGet: + """https://discord.com/developers/docs/interactions/receiving-and-responding#create-followup-message""" data = parse_data(data, ExecuteWebhookParams) headers = {"Authorization": adapter.get_authorization(bot.bot_info)} request = Request( @@ -496,6 +501,10 @@ async def _get_followup_message( message_id: SnowflakeType, **params, ) -> MessageGet: + """Returns a followup message for an Interaction. Functions the same as Get Webhook Message. + + see https://discord.com/developers/docs/interactions/receiving-and-responding#get-followup-message + """ headers = {"Authorization": adapter.get_authorization(bot.bot_info)} request = Request( headers=headers, @@ -515,6 +524,10 @@ async def _edit_followup_message( message_id: SnowflakeType, **data, ): + """Edits a followup message for an Interaction. Functions the same as Edit Webhook Message. + + see https://discord.com/developers/docs/interactions/receiving-and-responding#edit-followup-message + """ params = {} if data.get("thread_id"): params["thread_id"] = data.pop("thread_id") @@ -538,6 +551,10 @@ async def _delete_followup_message( interaction_token: str, message_id: SnowflakeType, ): + """Deletes a followup message for an Interaction. + + see https://discord.com/developers/docs/interactions/receiving-and-responding#delete-followup-message + """ headers = {"Authorization": adapter.get_authorization(bot.bot_info)} request = Request( headers=headers, @@ -548,8 +565,8 @@ async def _delete_followup_message( await _request(adapter, bot, request) -# Application Role Connection Metadata -# see https://discord.com/developers/docs/resources/application-role-connection-metadata +# Application +# see https://discord.com/developers/docs/resources/application async def _get_current_application( @@ -569,6 +586,50 @@ async def _get_current_application( return type_validate_python(Application, await _request(adapter, bot, request)) +async def _edit_current_application( + adapter: "Adapter", + bot: "Bot", + **data, +) -> Application: + """Edit properties of the app associated with the requesting bot user. + + see https://discord.com/developers/docs/resources/application#edit-current-application + """ + headers = {"Authorization": adapter.get_authorization(bot.bot_info)} + request = Request( + headers=headers, + method="PATCH", + url=adapter.base_url / "applications/@me", + json=data, + ) + return type_validate_python(Application, await _request(adapter, bot, request)) + + +async def _get_application_activity_instance( + adapter: "Adapter", + bot: "Bot", + application_id: SnowflakeType, + instance_id: str, +) -> ActivityInstance: + """Returns a serialized activity instance, if it exists. + Useful for preventing unwanted activity sessions. + + see https://discord.com/developers/docs/resources/application#get-application-activity-instance + """ + headers = {"Authorization": adapter.get_authorization(bot.bot_info)} + request = Request( + headers=headers, + method="GET", + url=adapter.base_url + / f"applications/{application_id}/activity-instances/{instance_id}", + ) + return type_validate_python(ActivityInstance, await _request(adapter, bot, request)) + + +# Application Role Connection Metadata +# see https://discord.com/developers/docs/resources/application-role-connection-metadata + + async def _get_application_role_connection_metadata_records( adapter: "Adapter", bot: "Bot", application_id: SnowflakeType ) -> list[ApplicationRoleConnectionMetadata]: @@ -607,10 +668,23 @@ async def _update_application_role_connection_metadata_records( ) +# Audit Logs +# see https://discord.com/developers/docs/resources/audit-log + + async def _get_guild_audit_log( adapter: "Adapter", bot: "Bot", guild_id: SnowflakeType, **data ) -> AuditLog: - """get guild audit log + """Returns an audit log object for the guild. + Requires the VIEW_AUDIT_LOG permission. + + The returned list of audit log entries is ordered based on whether you use + before or after. When using before, the list is ordered by the audit log entry + ID descending (newer entries first). If after is used, the list is reversed and + appears in ascending order (older entries first). Omitting both before and after + defaults to before the current timestamp and will show the most recent entries + in descending order by ID, the opposite can be achieved using after=0 (showing + oldest entries). see https://discord.com/developers/docs/resources/audit-log#get-guild-audit-log""" headers = {"Authorization": adapter.get_authorization(bot.bot_info)} @@ -623,6 +697,10 @@ async def _get_guild_audit_log( return type_validate_python(AuditLog, await _request(adapter, bot, request)) +# Auto Moderation +# see https://discord.com/developers/docs/resources/auto-moderation + + async def _list_auto_moderation_rules_for_guild( adapter: "Adapter", bot: "Bot", guild_id: SnowflakeType ) -> list[AutoModerationRule]: @@ -735,6 +813,10 @@ async def _delete_auto_moderation_rule( await _request(adapter, bot, request) +# Channels +# https://discord.com/developers/docs/resources/channel + + async def _get_channel( adapter: "Adapter", bot: "Bot", channel_id: SnowflakeType ) -> Channel: @@ -771,9 +853,7 @@ async def _modify_DM( async def _modify_channel( adapter: "Adapter", bot: "Bot", channel_id: SnowflakeType, **data ) -> Channel: - """modify channel - - see https://discord.com/developers/docs/resources/channel#modify-channel""" + """https://discord.com/developers/docs/resources/channel#modify-channel""" headers = {"Authorization": adapter.get_authorization(bot.bot_info)} if data.get("reason"): headers["X-Audit-Log-Reason"] = data.pop("reason") @@ -792,9 +872,7 @@ async def _modify_channel( async def _modify_thread( adapter: "Adapter", bot: "Bot", channel_id: SnowflakeType, **data ) -> Channel: - """modify channel - - see https://discord.com/developers/docs/resources/channel#modify-channel""" + """https://discord.com/developers/docs/resources/channel#modify-channel""" headers = {"Authorization": adapter.get_authorization(bot.bot_info)} if data.get("reason"): headers["X-Audit-Log-Reason"] = data.pop("reason") @@ -813,9 +891,7 @@ async def _delete_channel( channel_id: SnowflakeType, reason: Optional[str] = None, ) -> Channel: - """delete channel - - see https://discord.com/developers/docs/resources/channel#deleteclose-channel""" + """https://discord.com/developers/docs/resources/channel#deleteclose-channel""" headers = {"Authorization": adapter.get_authorization(bot.bot_info)} if reason: headers["X-Audit-Log-Reason"] = reason @@ -827,12 +903,14 @@ async def _delete_channel( return type_validate_python(Channel, await _request(adapter, bot, request)) +# Messages +# see https://discord.com/developers/docs/resources/message + + async def _get_channel_messages( adapter: "Adapter", bot: "Bot", channel_id: SnowflakeType, **data ) -> list[MessageGet]: - """get channel messages - - see https://discord.com/developers/docs/resources/channel#get-channel-messages""" + """https://discord.com/developers/docs/resources/message#get-channel-messages""" headers = {"Authorization": adapter.get_authorization(bot.bot_info)} request = Request( headers=headers, @@ -846,9 +924,7 @@ async def _get_channel_messages( async def _get_channel_message( adapter: "Adapter", bot: "Bot", channel_id: SnowflakeType, message_id: SnowflakeType ) -> MessageGet: - """get channel message - - see https://discord.com/developers/docs/resources/channel#get-channel-message""" + """https://discord.com/developers/docs/resources/message#get-channel-message""" headers = {"Authorization": adapter.get_authorization(bot.bot_info)} request = Request( headers=headers, @@ -861,10 +937,7 @@ async def _get_channel_message( async def _create_message( adapter: "Adapter", bot: "Bot", channel_id: SnowflakeType, **data ) -> MessageGet: - """create message - - see https://discord.com/developers/docs/resources/channel#create-message - """ + """https://discord.com/developers/docs/resources/message#create-message""" params = parse_data(data, MessageSend) headers = {"Authorization": adapter.get_authorization(bot.bot_info)} request = Request( @@ -879,9 +952,7 @@ async def _create_message( async def _crosspost_message( adapter: "Adapter", bot: "Bot", channel_id: SnowflakeType, message_id: SnowflakeType ) -> MessageGet: - """crosspost message - - see https://discord.com/developers/docs/resources/channel#crosspost-message""" + """https://discord.com/developers/docs/resources/message#crosspost-message""" headers = {"Authorization": adapter.get_authorization(bot.bot_info)} request = Request( headers=headers, @@ -899,9 +970,7 @@ async def _create_reaction( emoji: str, emoji_id: Optional[SnowflakeType] = None, ) -> None: - """create reaction - - see https://discord.com/developers/docs/resources/channel#create-reaction""" + """https://discord.com/developers/docs/resources/message#create-reaction""" if emoji_id is not None: emoji = f"{emoji}:{emoji_id}" headers = {"Authorization": adapter.get_authorization(bot.bot_info)} @@ -922,9 +991,7 @@ async def _delete_own_reaction( emoji: str, emoji_id: Optional[SnowflakeType] = None, ) -> None: - """delete own reaction - - see https://discord.com/developers/docs/resources/channel#delete-own-reaction""" + """https://discord.com/developers/docs/resources/message#delete-own-reaction""" if emoji_id is not None: emoji = f"{emoji}:{emoji_id}" headers = {"Authorization": adapter.get_authorization(bot.bot_info)} @@ -946,9 +1013,7 @@ async def _delete_user_reaction( emoji: str, emoji_id: Optional[SnowflakeType] = None, ) -> None: - """delete user reaction - - see https://discord.com/developers/docs/resources/channel#delete-user-reaction""" + """https://discord.com/developers/docs/resources/message#delete-user-reaction""" if emoji_id is not None: emoji = f"{emoji}:{emoji_id}" headers = {"Authorization": adapter.get_authorization(bot.bot_info)} @@ -970,9 +1035,7 @@ async def _get_reactions( emoji_id: Optional[SnowflakeType] = None, **params, ) -> list[User]: - """get reactions - - see https://discord.com/developers/docs/resources/channel#get-reactions""" + """https://discord.com/developers/docs/resources/message#get-reactions""" if emoji_id is not None: emoji = f"{emoji}:{emoji_id}" headers = {"Authorization": adapter.get_authorization(bot.bot_info)} @@ -992,10 +1055,7 @@ async def _delete_all_reactions( channel_id: SnowflakeType, message_id: SnowflakeType, ): - """ - - see https://discord.com/developers/docs/resources/channel#delete-all-reactions - """ + """https://discord.com/developers/docs/resources/message#delete-all-reactions""" headers = {"Authorization": adapter.get_authorization(bot.bot_info)} request = Request( headers=headers, @@ -1013,10 +1073,7 @@ async def _delete_all_reactions_for_emoji( emoji: str, emoji_id: Optional[SnowflakeType] = None, ): - """ - - see https://discord.com/developers/docs/resources/channel#delete-all-reactions - """ + """https://discord.com/developers/docs/resources/message#delete-all-reactions-for-emoji""" if emoji_id is not None: emoji = f"{emoji}:{emoji_id}" headers = {"Authorization": adapter.get_authorization(bot.bot_info)} @@ -1036,7 +1093,7 @@ async def _edit_message( message_id: SnowflakeType, **data, ) -> MessageGet: - """see https://discord.com/developers/docs/resources/channel#edit-message""" + """https://discord.com/developers/docs/resources/message#edit-message""" params = parse_data(data, MessageSend) headers = {"Authorization": adapter.get_authorization(bot.bot_info)} request = Request( @@ -1055,7 +1112,7 @@ async def _delete_message( message_id: SnowflakeType, reason: Optional[str] = None, ): - """https://discord.com/developers/docs/resources/channel#delete-message""" + """https://discord.com/developers/docs/resources/message#delete-message""" headers = {"Authorization": adapter.get_authorization(bot.bot_info)} if reason: headers["X-Audit-Log-Reason"] = reason @@ -1070,7 +1127,7 @@ async def _delete_message( async def _bulk_delete_message( adapter: "Adapter", bot: "Bot", channel_id: SnowflakeType, **data ): - """https://discord.com/developers/docs/resources/channel#bulk-delete-messages""" + """https://discord.com/developers/docs/resources/message#bulk-delete-messages""" headers = {"Authorization": adapter.get_authorization(bot.bot_info)} if data.get("reason"): headers["X-Audit-Log-Reason"] = data.pop("reason") @@ -1153,7 +1210,7 @@ async def _delete_channel_permission( async def _follow_announcement_channel( adapter: "Adapter", bot: "Bot", channel_id: SnowflakeType, **data ) -> FollowedChannel: - """https://discord.com/developers/docs/resources/channel#follow-news-channel""" + """https://discord.com/developers/docs/resources/channel#follow-announcement-channel""" headers = {"Authorization": adapter.get_authorization(bot.bot_info)} request = Request( headers=headers, @@ -1197,7 +1254,7 @@ async def _pin_message( message_id: SnowflakeType, reason: Optional[str] = None, ): - """https://discord.com/developers/docs/resources/channel#add-pinned-channel-message""" + """https://discord.com/developers/docs/resources/channel#pin-message""" headers = {"Authorization": adapter.get_authorization(bot.bot_info)} if reason: headers["X-Audit-Log-Reason"] = reason @@ -1216,7 +1273,7 @@ async def _unpin_message( message_id: SnowflakeType, reason: Optional[str] = None, ): - """https://discord.com/developers/docs/resources/channel#delete-pinned-channel-message""" + """https://discord.com/developers/docs/resources/channel#unpin-message""" headers = {"Authorization": adapter.get_authorization(bot.bot_info)} if reason: headers["X-Audit-Log-Reason"] = reason @@ -1266,7 +1323,7 @@ async def _start_thread_from_message( message_id: SnowflakeType, **data, ) -> Channel: - """https://discord.com/developers/docs/resources/channel#start-thread-with-message""" + """https://discord.com/developers/docs/resources/channel#start-thread-from-message""" headers = {"Authorization": adapter.get_authorization(bot.bot_info)} if data.get("reason"): headers["X-Audit-Log-Reason"] = data.pop("reason") @@ -1298,7 +1355,7 @@ async def _start_thread_without_message( async def _start_thread_in_forum_channel( adapter: "Adapter", bot: "Bot", channel_id: SnowflakeType, **data ) -> Channel: - """https://discord.com/developers/docs/resources/channel#start-thread-in-forum-channel""" + """https://discord.com/developers/docs/resources/channel#start-thread-in-forum-or-media-channel""" params = parse_forum_thread_message(data) headers = {"Authorization": adapter.get_authorization(bot.bot_info)} if data.get("reason"): @@ -1449,6 +1506,10 @@ async def _list_joined_private_archived_threads( ) +# Emoji +# see https://discord.com/developers/docs/resources/emoji + + async def _list_guild_emojis( adapter: "Adapter", bot: "Bot", guild_id: SnowflakeType ) -> list[Emoji]: @@ -1530,6 +1591,160 @@ async def _delete_guild_emoji( await _request(adapter, bot, request) +async def _list_application_emojis( + adapter: "Adapter", bot: "Bot", application_id: SnowflakeType +) -> ApplicationEmojis: + """https://discord.com/developers/docs/resources/emoji#list-application-emojis""" + headers = {"Authorization": adapter.get_authorization(bot.bot_info)} + request = Request( + headers=headers, + method="GET", + url=adapter.base_url / f"applications/{application_id}/emojis", + ) + return type_validate_python( + ApplicationEmojis, await _request(adapter, bot, request) + ) + + +async def _get_application_emoji( + adapter: "Adapter", + bot: "Bot", + application_id: SnowflakeType, + emoji_id: SnowflakeType, +) -> Emoji: + """https://discord.com/developers/docs/resources/emoji#get-application-emoji""" + headers = {"Authorization": adapter.get_authorization(bot.bot_info)} + request = Request( + headers=headers, + method="GET", + url=adapter.base_url / f"applications/{application_id}/emojis/{emoji_id}", + ) + return type_validate_python(Emoji, await _request(adapter, bot, request)) + + +async def _create_application_emoji( + adapter: "Adapter", bot: "Bot", application_id: SnowflakeType, **data +) -> Emoji: + """https://discord.com/developers/docs/resources/emoji#create-application-emoji""" + headers = {"Authorization": adapter.get_authorization(bot.bot_info)} + request = Request( + headers=headers, + method="POST", + url=adapter.base_url / f"applications/{application_id}/emojis", + json=data, + ) + return type_validate_python(Emoji, await _request(adapter, bot, request)) + + +async def _modify_application_emoji( + adapter: "Adapter", + bot: "Bot", + application_id: SnowflakeType, + emoji_id: SnowflakeType, + **data, +) -> Emoji: + """https://discord.com/developers/docs/resources/emoji#modify-application-emoji""" + headers = {"Authorization": adapter.get_authorization(bot.bot_info)} + request = Request( + headers=headers, + method="PATCH", + url=adapter.base_url / f"applications/{application_id}/emojis/{emoji_id}", + json=data, + ) + return type_validate_python(Emoji, await _request(adapter, bot, request)) + + +async def _delete_application_emoji( + adapter: "Adapter", + bot: "Bot", + application_id: SnowflakeType, + emoji_id: SnowflakeType, +) -> None: + """https://discord.com/developers/docs/resources/emoji#delete-application-emoji""" + headers = {"Authorization": adapter.get_authorization(bot.bot_info)} + request = Request( + headers=headers, + method="DELETE", + url=adapter.base_url / f"applications/{application_id}/emojis/{emoji_id}", + ) + await _request(adapter, bot, request) + + +# Entitlements +# see https://discord.com/developers/docs/resources/entitlement + + +async def _list_entitlements( + adapter: "Adapter", bot: "Bot", application_id: SnowflakeType, **params +) -> list[Entitlement]: + """https://discord.com/developers/docs/resources/entitlement#list-entitlements""" + headers = {"Authorization": adapter.get_authorization(bot.bot_info)} + request = Request( + headers=headers, + method="GET", + url=adapter.base_url / f"applications/{application_id}/entitlements", + params=params, + ) + return type_validate_python( + list[Entitlement], await _request(adapter, bot, request) + ) + + +async def _consume_an_entitlement( + adapter: "Adapter", + bot: "Bot", + application_id: SnowflakeType, + entitlement_id: SnowflakeType, +) -> None: + """https://discord.com/developers/docs/resources/entitlement#consume-an-entitlement""" + headers = {"Authorization": adapter.get_authorization(bot.bot_info)} + request = Request( + headers=headers, + method="POST", + url=adapter.base_url + / f"applications/{application_id}/entitlements/{entitlement_id}/consume", + ) + await _request(adapter, bot, request) + + +async def _create_test_entitlement( + adapter: "Adapter", + bot: "Bot", + application_id: SnowflakeType, + **data, +) -> Entitlement: + """https://discord.com/developers/docs/resources/entitlement#create-test-entitlement""" + headers = {"Authorization": adapter.get_authorization(bot.bot_info)} + request = Request( + headers=headers, + method="POST", + url=adapter.base_url / f"applications/{application_id}/entitlements", + json=data, + ) + return type_validate_python(Entitlement, await _request(adapter, bot, request)) + + +async def _delete_test_entitlement( + adapter: "Adapter", + bot: "Bot", + application_id: SnowflakeType, + entitlement_id: SnowflakeType, +) -> None: + """https://discord.com/developers/docs/resources/entitlement#create-test-entitlement""" + headers = {"Authorization": adapter.get_authorization(bot.bot_info)} + request = Request( + headers=headers, + method="POST", + url=adapter.base_url + / f"applications/{application_id}/entitlements/{entitlement_id}", + ) + await _request(adapter, bot, request) + + +# Guild +# see https://discord.com/developers/docs/resources/guild + + async def _create_guild(adapter: "Adapter", bot: "Bot", **data) -> Guild: """https://discord.com/developers/docs/resources/guild#create-guild""" data = model_dump(type_validate_python(CreateGuildParams, data), exclude_unset=True) @@ -1578,7 +1793,7 @@ async def _modify_guild( request = Request( headers=headers, method="PATCH", - url=adapter.base_url / f"guilds/{guild_id}/preview", + url=adapter.base_url / f"guilds/{guild_id}", json=data, ) return type_validate_python(Guild, await _request(adapter, bot, request)) @@ -1760,7 +1975,9 @@ async def _modify_current_member( async def _modify_current_user_nick( adapter: "Adapter", bot: "Bot", guild_id: SnowflakeType, **data ) -> GuildMember: - """https://discord.com/developers/docs/resources/guild#modify-current-user-nick""" + """Deprecated in favor of Modify Current Member. + + https://discord.com/developers/docs/resources/guild#modify-current-user-nick""" headers = {"Authorization": adapter.get_authorization(bot.bot_info)} if data.get("reason"): headers["X-Audit-Log-Reason"] = data.pop("reason") @@ -1898,6 +2115,25 @@ async def _remove_guild_ban( await _request(adapter, bot, request) +async def _bulk_guild_ban( + adapter: "Adapter", + bot: "Bot", + guild_id: SnowflakeType, + **data, +) -> BulkBan: + """https://discord.com/developers/docs/resources/guild#bulk-guild-ban""" + headers = {"Authorization": adapter.get_authorization(bot.bot_info)} + if data.get("reason"): + headers["X-Audit-Log-Reason"] = data.pop("reason") + request = Request( + headers=headers, + method="POST", + url=adapter.base_url / f"guilds/{guild_id}/bulk-ban", + json=data, + ) + return type_validate_python(BulkBan, await _request(adapter, bot, request)) + + async def _get_guild_roles( adapter: "Adapter", bot: "Bot", guild_id: SnowflakeType ) -> list[Role]: @@ -1911,6 +2147,19 @@ async def _get_guild_roles( return type_validate_python(list[Role], await _request(adapter, bot, request)) +async def _get_guild_role( + adapter: "Adapter", bot: "Bot", guild_id: SnowflakeType, role_id: SnowflakeType +) -> Role: + """https://discord.com/developers/docs/resources/guild#get-guild-role""" + headers = {"Authorization": adapter.get_authorization(bot.bot_info)} + request = Request( + headers=headers, + method="GET", + url=adapter.base_url / f"guilds/{guild_id}/roles/{role_id}", + ) + return type_validate_python(Role, await _request(adapter, bot, request)) + + async def _create_guild_role( adapter: "Adapter", bot: "Bot", guild_id: SnowflakeType, **data ) -> Role: @@ -2208,10 +2457,72 @@ async def _get_guild_onboarding( return type_validate_python(GuildOnboarding, await _request(adapter, bot, request)) +async def _modify_guild_onboarding( + adapter: "Adapter", bot: "Bot", guild_id: SnowflakeType, **data +) -> GuildOnboarding: + """https://discord.com/developers/docs/resources/guild#get-guild-onboarding""" + headers = {"Authorization": adapter.get_authorization(bot.bot_info)} + if data.get("reason"): + headers["X-Audit-Log-Reason"] = data.pop("reason") + data = model_dump( + type_validate_python(ModifyGuildOnboardingParams, data), exclude_unset=True + ) + request = Request( + headers=headers, + method="PUT", + url=adapter.base_url / f"guilds/{guild_id}/onboarding", + json=data, + ) + return type_validate_python(GuildOnboarding, await _request(adapter, bot, request)) + + +# Voice +# https://discord.com/developers/docs/resources/voice + + +async def _list_voice_regions(adapter: "Adapter", bot: "Bot") -> list[VoiceRegion]: + """https://discord.com/developers/docs/resources/voice#list-voice-regions""" + headers = {"Authorization": adapter.get_authorization(bot.bot_info)} + request = Request( + headers=headers, + method="GET", + url=adapter.base_url / "voice/regions", + ) + return type_validate_python( + list[VoiceRegion], await _request(adapter, bot, request) + ) + + +async def _get_current_user_voice_state( + adapter: "Adapter", bot: "Bot", guild_id: SnowflakeType +) -> VoiceState: + """https://discord.com/developers/docs/resources/voice#get-current-user-voice-state""" + headers = {"Authorization": adapter.get_authorization(bot.bot_info)} + request = Request( + headers=headers, + method="GET", + url=adapter.base_url / f"guilds/{guild_id}/voice-states/@me", + ) + return type_validate_python(VoiceState, await _request(adapter, bot, request)) + + +async def _get_user_voice_state( + adapter: "Adapter", bot: "Bot", guild_id: SnowflakeType, user_id: SnowflakeType +) -> VoiceState: + """https://discord.com/developers/docs/resources/voice#get-user-voice-state""" + headers = {"Authorization": adapter.get_authorization(bot.bot_info)} + request = Request( + headers=headers, + method="GET", + url=adapter.base_url / f"guilds/{guild_id}/voice-states/{user_id}", + ) + return type_validate_python(VoiceState, await _request(adapter, bot, request)) + + async def _modify_current_user_voice_state( adapter: "Adapter", bot: "Bot", guild_id: SnowflakeType, **data ) -> None: - """https://discord.com/developers/docs/resources/guild#modify-current-user-voice-state""" + """https://discord.com/developers/docs/resources/voice#modify-current-user-voice-state""" headers = {"Authorization": adapter.get_authorization(bot.bot_info)} request = Request( headers=headers, @@ -2229,7 +2540,7 @@ async def _modify_user_voice_state( user_id: SnowflakeType, **data, ) -> None: - """https://discord.com/developers/docs/resources/guild#modify-user-voice-state""" + """https://discord.com/developers/docs/resources/voice#modify-user-voice-state""" headers = {"Authorization": adapter.get_authorization(bot.bot_info)} request = Request( headers=headers, @@ -2240,6 +2551,10 @@ async def _modify_user_voice_state( await _request(adapter, bot, request) +# Guild Scheduled Event +# see https://discord.com/developers/docs/resources/guild-scheduled-event + + async def _list_scheduled_events_for_guild( adapter: "Adapter", bot: "Bot", guild_id: SnowflakeType, **params ) -> list[GuildScheduledEvent]: @@ -2355,6 +2670,10 @@ async def _get_guild_scheduled_event_users( ) +# Guild Template +# see https://discord.com/developers/docs/resources/guild-template + + async def _get_guild_template( adapter: "Adapter", bot: "Bot", template_code: str ) -> GuildTemplate: @@ -2371,7 +2690,7 @@ async def _get_guild_template( async def _create_guild_from_guild_template( adapter: "Adapter", bot: "Bot", template_code: str, **data ) -> Guild: - """https://discord.com/developers/docs/resources/guild-template#create-guild-from-template""" + """https://discord.com/developers/docs/resources/guild-template#create-guild-from-guild-template""" headers = {"Authorization": adapter.get_authorization(bot.bot_info)} request = Request( headers=headers, @@ -2451,6 +2770,10 @@ async def _delete_guild_template( await _request(adapter, bot, request) +# Invite +# see https://discord.com/developers/docs/resources/invite + + async def _get_invite( adapter: "Adapter", bot: "Bot", invite_code: str, **params ) -> Invite: @@ -2480,6 +2803,67 @@ async def _delete_invite( return type_validate_python(Invite, await _request(adapter, bot, request)) +# Poll +# see https://discord.com/developers/docs/resources/poll + + +async def _get_answer_voters( + adapter: "Adapter", + bot: "Bot", + channel_id: SnowflakeType, + message_id: SnowflakeType, + answer_id: int, + **params, +) -> AnswerVoters: + """https://discord.com/developers/docs/resources/poll#get-answer-voters""" + headers = {"Authorization": adapter.get_authorization(bot.bot_info)} + request = Request( + headers=headers, + method="GET", + url=adapter.base_url + / f"channels/{channel_id}/polls/{message_id}/answers/{answer_id}", + params=params, + ) + return type_validate_python(AnswerVoters, await _request(adapter, bot, request)) + + +async def _end_poll( + adapter: "Adapter", + bot: "Bot", + channel_id: SnowflakeType, + message_id: SnowflakeType, +) -> MessageGet: + """https://discord.com/developers/docs/resources/poll#end-poll""" + headers = {"Authorization": adapter.get_authorization(bot.bot_info)} + request = Request( + headers=headers, + method="POST", + url=adapter.base_url / f"channels/{channel_id}/polls/{message_id}/expire", + ) + return type_validate_python(MessageGet, await _request(adapter, bot, request)) + + +# SKU +# see https://discord.com/developers/docs/resources/sku + + +async def _list_SKUs( + adapter: "Adapter", bot: "Bot", application_id: SnowflakeType +) -> list[SKU]: + """https://discord.com/developers/docs/resources/sku#list-skus""" + headers = {"Authorization": adapter.get_authorization(bot.bot_info)} + request = Request( + headers=headers, + method="GET", + url=adapter.base_url / f"applications/{application_id}/skus", + ) + return type_validate_python(list[SKU], await _request(adapter, bot, request)) + + +# Stage Instance +# see https://discord.com/developers/docs/resources/stage-instance + + async def _create_stage_instance( adapter: "Adapter", bot: "Bot", **data ) -> StageInstance: @@ -2546,6 +2930,10 @@ async def _delete_stage_instance( await _request(adapter, bot, request) +# Sticker +# see https://discord.com/developers/docs/resources/sticker + + async def _get_sticker( adapter: "Adapter", bot: "Bot", sticker_id: SnowflakeType ) -> Sticker: @@ -2562,7 +2950,7 @@ async def _get_sticker( async def _list_nitro_sticker_packs( adapter: "Adapter", bot: "Bot" ) -> list[StickerPack]: - """https://discord.com/developers/docs/resources/sticker#list-nitro-sticker-packs""" + """https://discord.com/developers/docs/resources/sticker#list-sticker-packs""" headers = {"Authorization": adapter.get_authorization(bot.bot_info)} request = Request( headers=headers, @@ -2574,6 +2962,19 @@ async def _list_nitro_sticker_packs( ) +async def _get_sticker_packs( + adapter: "Adapter", bot: "Bot", pack_id: SnowflakeType +) -> StickerPack: + """https://discord.com/developers/docs/resources/sticker#get-sticker-pack""" + headers = {"Authorization": adapter.get_authorization(bot.bot_info)} + request = Request( + headers=headers, + method="GET", + url=adapter.base_url / f"sticker-packs/{pack_id}", + ) + return type_validate_python(StickerPack, await _request(adapter, bot, request)) + + async def _list_guild_stickers( adapter: "Adapter", bot: "Bot", guild_id: SnowflakeType ) -> list[Sticker]: @@ -2668,6 +3069,44 @@ async def _delete_guild_sticker( await _request(adapter, bot, request) +# Subscription +# see https://discord.com/developers/docs/resources/subscription + + +async def _list_SKU_subscriptions( + adapter: "Adapter", bot: "Bot", sku_id: SnowflakeType +) -> list[Subscription]: + """https://discord.com/developers/docs/resources/subscription#list-sku-subscriptions""" + headers = {"Authorization": adapter.get_authorization(bot.bot_info)} + request = Request( + headers=headers, + method="GET", + url=adapter.base_url / f"gskus/{sku_id}/subscriptions", + ) + return type_validate_python( + list[Subscription], await _request(adapter, bot, request) + ) + + +async def _get_SKU_subscription( + adapter: "Adapter", + bot: "Bot", + sku_id: SnowflakeType, +) -> Subscription: + """https://discord.com/developers/docs/resources/subscription#list-sku-subscriptions""" + headers = {"Authorization": adapter.get_authorization(bot.bot_info)} + request = Request( + headers=headers, + method="GET", + url=adapter.base_url / f"gskus/{sku_id}/subscriptions", + ) + return type_validate_python(Subscription, await _request(adapter, bot, request)) + + +# Users +# see https://discord.com/developers/docs/resources/user + + async def _get_current_user(adapter: "Adapter", bot: "Bot") -> User: """https://discord.com/developers/docs/resources/user#get-current-user""" headers = {"Authorization": adapter.get_authorization(bot.bot_info)} @@ -2721,7 +3160,7 @@ async def _get_current_user_guilds( async def _get_current_user_guild_member( adapter: "Adapter", bot: "Bot", guild_id: SnowflakeType ) -> GuildMember: - """https://discord.com/developers/docs/resources/user#get-current-user-guilds-member""" + """https://discord.com/developers/docs/resources/user#get-current-user-guild-member""" headers = {"Authorization": adapter.get_authorization(bot.bot_info)} request = Request( headers=headers, @@ -2770,7 +3209,7 @@ async def _get_user_connections( adapter: "Adapter", bot: "Bot", ) -> list[Connection]: - """https://discord.com/developers/docs/resources/user#get-user-connections""" + """https://discord.com/developers/docs/resources/user#get-current-user-connections""" headers = {"Authorization": adapter.get_authorization(bot.bot_info)} request = Request( headers=headers, @@ -2783,7 +3222,7 @@ async def _get_user_connections( async def _get_user_application_role_connection( adapter: "Adapter", bot: "Bot", application_id: SnowflakeType ) -> ApplicationRoleConnection: - """https://discord.com/developers/docs/resources/user#get-user-application-connections""" + """https://discord.com/developers/docs/resources/user#get-current-user-application-role-connection""" headers = {"Authorization": adapter.get_authorization(bot.bot_info)} request = Request( headers=headers, @@ -2799,7 +3238,7 @@ async def _get_user_application_role_connection( async def _update_user_application_role_connection( adapter: "Adapter", bot: "Bot", application_id: SnowflakeType, **data ) -> ApplicationRoleConnection: - """https://discord.com/developers/docs/resources/user#modify-current-user""" + """https://discord.com/developers/docs/resources/user#update-current-user-application-role-connection""" if "metadata" in data and isinstance( data["metadata"], ApplicationRoleConnectionMetadata ): @@ -2817,17 +3256,8 @@ async def _update_user_application_role_connection( ) -async def _list_voice_regions(adapter: "Adapter", bot: "Bot") -> list[VoiceRegion]: - """https://discord.com/developers/docs/resources/voice#list-voice-regions""" - headers = {"Authorization": adapter.get_authorization(bot.bot_info)} - request = Request( - headers=headers, - method="GET", - url=adapter.base_url / "voice/regions", - ) - return type_validate_python( - list[VoiceRegion], await _request(adapter, bot, request) - ) +# Webhook +# see https://discord.com/developers/docs/resources/webhook async def _create_webhook( @@ -3060,6 +3490,10 @@ async def _delete_webhook_message( await _request(adapter, bot, request) +# Gateway +# see https://discord.com/developers/docs/topics/gateway + + async def _get_gateway(adapter: "Adapter", bot: "Bot") -> Gateway: """https://discord.com/developers/docs/topics/gateway#get-gateway""" headers = {"Authorization": adapter.get_authorization(bot.bot_info)} @@ -3072,6 +3506,7 @@ async def _get_gateway(adapter: "Adapter", bot: "Bot") -> Gateway: async def _get_gateway_bot(adapter: "Adapter", bot: "Bot") -> GatewayBot: + """https://discord.com/developers/docs/topics/gateway#get-gateway-bot""" headers = {"Authorization": adapter.get_authorization(bot.bot_info)} request = Request( headers=headers, @@ -3081,10 +3516,14 @@ async def _get_gateway_bot(adapter: "Adapter", bot: "Bot") -> GatewayBot: return type_validate_python(GatewayBot, await _request(adapter, bot, request)) +# OAuth2 +# see https://discord.com/developers/docs/topics/oauth2 + + async def _get_current_bot_application_information( adapter: "Adapter", bot: "Bot" ) -> Application: - """https://discord.com/developers/docs/resources/user#get-current-application-information""" + """https://discord.com/developers/docs/topics/oauth2#get-current-bot-application-information""" headers = {"Authorization": adapter.get_authorization(bot.bot_info)} request = Request( headers=headers, @@ -3097,7 +3536,7 @@ async def _get_current_bot_application_information( async def _get_current_authorization_information( adapter: "Adapter", bot: "Bot" ) -> AuthorizationResponse: - """https://discord.com/developers/docs/resources/user#get-current-authorization-information""" + """https://discord.com/developers/docs/topics/oauth2#get-current-authorization-information""" headers = {"Authorization": adapter.get_authorization(bot.bot_info)} request = Request( headers=headers, @@ -3140,6 +3579,8 @@ async def _get_current_authorization_information( "edit_followup_message": _edit_followup_message, "delete_followup_message": _delete_followup_message, "get_current_application": _get_current_application, + "edit_current_application": _edit_current_application, + "get_application_activity_instance": _get_application_activity_instance, "get_application_role_connection_metadata_records": ( _get_application_role_connection_metadata_records ), @@ -3198,6 +3639,15 @@ async def _get_current_authorization_information( "create_guild_emoji": _create_guild_emoji, "modify_guild_emoji": _modify_guild_emoji, "delete_guild_emoji": _delete_guild_emoji, + "list_application_emojis": _list_application_emojis, + "get_application_emoji": _get_application_emoji, + "create_application_emoji": _create_application_emoji, + "modify_application_emoji": _modify_application_emoji, + "delete_application_emoji": _delete_application_emoji, + "list_entitlements": _list_entitlements, + "consume_an_entitlement": _consume_an_entitlement, + "create_test_entitlement": _create_test_entitlement, + "delete_test_entitlement": _delete_test_entitlement, "create_guild": _create_guild, "get_guild": _get_guild, "get_guild_preview": _get_guild_preview, @@ -3221,7 +3671,9 @@ async def _get_current_authorization_information( "get_guild_ban": _get_guild_ban, "create_guild_ban": _create_guild_ban, "remove_guild_ban": _remove_guild_ban, + "bulk_guild_ban": _bulk_guild_ban, "get_guild_roles": _get_guild_roles, + "get_guild_role": _get_guild_role, "create_guild_role": _create_guild_role, "modify_guild_role_positions": _modify_guild_role_positions, "modify_guild_role": _modify_guild_role, @@ -3241,6 +3693,10 @@ async def _get_current_authorization_information( "get_guild_welcome_screen": _get_guild_welcome_screen, "modify_guild_welcome_screen": _modify_guild_welcome_screen, "get_guild_onboarding": _get_guild_onboarding, + "modify_guild_onboarding": _modify_guild_onboarding, + "list_voice_regions": _list_voice_regions, + "get_current_user_voice_state": _get_current_user_voice_state, + "get_user_voice_state": _get_user_voice_state, "modify_current_user_voice_state": _modify_current_user_voice_state, "modify_user_voice_state": _modify_user_voice_state, "list_scheduled_events_for_guild": _list_scheduled_events_for_guild, @@ -3258,17 +3714,23 @@ async def _get_current_authorization_information( "delete_guild_template": _delete_guild_template, "get_invite": _get_invite, "delete_invite": _delete_invite, + "get_answer_voters": _get_answer_voters, + "end_poll": _end_poll, + "list_SKUs": _list_SKUs, "create_stage_instance": _create_stage_instance, "get_stage_instance": _get_stage_instance, "modify_stage_instance": _modify_stage_instance, "delete_stage_instance": _delete_stage_instance, "get_sticker": _get_sticker, "list_nitro_sticker_packs": _list_nitro_sticker_packs, + "get_sticker_packs": _get_sticker_packs, "list_guild_stickers": _list_guild_stickers, "get_guild_sticker": _get_guild_sticker, "create_guild_sticker": _create_guild_sticker, "modify_guild_sticker": _modify_guild_sticker, "delete_guild_sticker": _delete_guild_sticker, + "list_SKU_subscriptions": _list_SKU_subscriptions, + "get_SKU_subscription": _get_SKU_subscription, "get_current_user": _get_current_user, "get_user": _get_user, "modify_current_user": _modify_current_user, @@ -3280,7 +3742,6 @@ async def _get_current_authorization_information( "get_user_connections": _get_user_connections, "get_user_application_role_connection": _get_user_application_role_connection, "update_user_application_role_connection": _update_user_application_role_connection, - "list_voice_regions": _list_voice_regions, "create_webhook": _create_webhook, "get_channel_webhooks": _get_channel_webhooks, "get_guild_webhooks": _get_guild_webhooks, diff --git a/nonebot/adapters/discord/api/model.py b/nonebot/adapters/discord/api/model.py index fed5bf2..574fdd9 100644 --- a/nonebot/adapters/discord/api/model.py +++ b/nonebot/adapters/discord/api/model.py @@ -3802,6 +3802,115 @@ class GuildScheduledEventRecurrenceRuleN_WeekdayStructure(BaseModel): """The day within the week to reoccur on""" +class ModifyGuildOnboardingParams(BaseModel): + """Modify Guild Onboarding Params + + see https://discord.com/developers/docs/resources/guild#modify-guild-onboarding + """ + + prompts: list[OnboardingPrompt] + """Prompts shown during onboarding and in customize community""" + default_channel_ids: list[Snowflake] + """Channel IDs that members get opted into automatically""" + enabled: bool + """Whether onboarding is enabled in the guild""" + mode: OnboardingMode + """Current mode of onboarding""" + + +class ActivityInstance(BaseModel): + """Activity Instance + + see https://discord.com/developers/docs/resources/application#get-application-activity-instance-activity-instance-object + """ + + application_id: Snowflake + """Application ID""" + instance_id: str + """Activity Instance ID""" + launch_id: Snowflake + """Unique identifier for the launch""" + location: "ActivityLocation" + """The Location the instance is runnning in""" + users: list[Snowflake] + """The IDs of the Users currently connected to the instance""" + + +class ActivityLocation(BaseModel): + """The Activity Location is an object that describes + the location in which an activity instance is running. + + see https://discord.com/developers/docs/resources/application#get-application-activity-instance-activity-location-object + """ + + id: str + """ The unique identifier for the location""" + kind: Literal["gc", "pc"] + """ + Enum describing kind of location + + 'gc' The Location is a Guild Channel\n + 'pc' The Location is a Private Channel, such as a DM or GDM + """ + channel_id: Snowflake + guild_id: MissingOrNullable[Snowflake] = UNSET + + +class ApplicationEmojis(BaseModel): + """a list of emoji objects for the given application under the items key. + + see https://discord.com/developers/docs/resources/emoji#list-application-emojis""" + + items: list[Emoji] + + +class BulkBan(BaseModel): + """bulk ban response + + see https://discord.com/developers/docs/resources/guild#bulk-guild-ban-bulk-ban-response + """ + + banned_users: list[Snowflake] + """list of user ids, that were successfully banned""" + failed_users: list[Snowflake] + """list of user ids, that were not banned""" + + +class AnswerVoters(BaseModel): + """get answer voter response + + see https://discord.com/developers/docs/resources/poll#get-answer-voters-response-body + """ + + users: list[User] + """Users who voted for this answer""" + + +class SKU(BaseModel): + """https://discord.com/developers/docs/resources/sku#sku-object""" + + id: Snowflake + type: SKUType + application_id: Snowflake + name: str + slug: str + flags: SKUFlag + + +class Subscription(BaseModel): + """https://discord.com/developers/docs/resources/subscription#subscription-object""" + + id: Snowflake + user_id: Snowflake + sku_ids: list[Snowflake] + entitlement_ids: list[Snowflake] + current_period_start: datetime.datetime + current_period_end: datetime.datetime + status: SubscriptionStatus + canceled_at: Optional[datetime.datetime] = None + country: Missing[str] = UNSET + + for name, obj in inspect.getmembers(sys.modules[__name__]): if inspect.isclass(obj) and issubclass(obj, BaseModel) and obj is not BaseModel: if PYDANTIC_V2: @@ -4046,4 +4155,12 @@ class GuildScheduledEventRecurrenceRuleN_WeekdayStructure(BaseModel): "Entitlement", "RecurrenceRule", "GuildScheduledEventRecurrenceRuleN_WeekdayStructure", + "ModifyGuildOnboardingParams", + "ActivityInstance", + "ActivityLocation", + "ApplicationEmojis", + "BulkBan", + "AnswerVoters", + "SKU", + "Subscription", ] diff --git a/nonebot/adapters/discord/api/types.py b/nonebot/adapters/discord/api/types.py index aab84ec..9779210 100644 --- a/nonebot/adapters/discord/api/types.py +++ b/nonebot/adapters/discord/api/types.py @@ -1265,6 +1265,38 @@ class RoleFlag(IntFlag): """role can be selected by members in an onboarding prompt""" +class SKUFlag(IntFlag): + """SKUFlag + + see https://discord.com/developers/docs/resources/sku#sku-object-sku-flags + """ + + AVAILABLE = 1 << 2 + """SKU is available for purchase""" + GUILD_SUBSCRIPTION = 1 << 7 + """Recurring SKU that can be purchased by a user and applied + to a single server. Grants access to every user in that server.""" + USER_SUBSCRIPTION = 1 << 8 + """Recurring SKU purchased by a user for themselves. + Grants access to the purchasing user in every server.""" + + +class SKUType(IntEnum): + """SKU Type + + see https://discord.com/developers/docs/resources/sku#sku-object-sku-types + """ + + DURABLE = 2 + """Durable one-time purchase""" + CONSUMABLE = 3 + """Consumable one-time purchase""" + SUBSCRIPTION = 5 + """Represents a recurring subscription""" + SUBSCRIPTION_GROUP = 6 + """System-generated group for each SUBSCRIPTION SKU created""" + + class SortOrderTypes(IntEnum): """Sort order types. @@ -1313,6 +1345,20 @@ class StickerType(IntEnum): """a sticker uploaded to a guild for the guild's members""" +class SubscriptionStatus(IntEnum): + """Subscription Statuses + + see https://discord.com/developers/docs/resources/subscription#subscription-statuses + """ + + ACTIVE = 0 + """Subscription is active and scheduled to renew.""" + ENDING = 1 + """Subscription is active but will not renew.""" + INACTIVE = 2 + """Subscription is inactive and not being charged.""" + + class SystemChannelFlags(IntFlag): """System channel flags. @@ -1582,10 +1628,13 @@ class WebhookType(IntEnum): "PresenceStatus", "ReactionType", "RoleFlag", + "SKUFlag", + "SKUType", "SortOrderTypes", "StagePrivacyLevel", "StickerFormatType", "StickerType", + "SubscriptionStatus", "SystemChannelFlags", "TeamMemberRoleType", "TextInputStyle", From 7722598ff3bc2b2f90fba6d2bb6ef7cd058125b2 Mon Sep 17 00:00:00 2001 From: Autuamn_End Date: Wed, 11 Sep 2024 14:00:31 +0800 Subject: [PATCH 4/8] =?UTF-8?q?:sparkles:=20=E4=B8=BA=20Follow=20Announcem?= =?UTF-8?q?ent=20Channel=20=E6=B7=BB=E5=8A=A0=20Reason?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nonebot/adapters/discord/api/client.pyi | 8 ++++++-- nonebot/adapters/discord/api/handle.py | 2 ++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/nonebot/adapters/discord/api/client.pyi b/nonebot/adapters/discord/api/client.pyi index 4d66aea..c6d64fb 100644 --- a/nonebot/adapters/discord/api/client.pyi +++ b/nonebot/adapters/discord/api/client.pyi @@ -635,9 +635,13 @@ class ApiClient: ... async def follow_announcement_channel( - self, *, channel_id: SnowflakeType, webhook_channel_id: SnowflakeType = ... + self, + *, + channel_id: SnowflakeType, + webhook_channel_id: SnowflakeType = ..., + reason: str | None = ..., ) -> FollowedChannel: - """https://discord.com/developers/docs/resources/channel#follow-news-channel""" + """https://discord.com/developers/docs/resources/channel#follow-announcement-channel""" ... async def trigger_typing_indicator(self, *, channel_id: SnowflakeType) -> None: diff --git a/nonebot/adapters/discord/api/handle.py b/nonebot/adapters/discord/api/handle.py index ba3734e..64078e1 100644 --- a/nonebot/adapters/discord/api/handle.py +++ b/nonebot/adapters/discord/api/handle.py @@ -1212,6 +1212,8 @@ async def _follow_announcement_channel( ) -> FollowedChannel: """https://discord.com/developers/docs/resources/channel#follow-announcement-channel""" headers = {"Authorization": adapter.get_authorization(bot.bot_info)} + if data.get("reason"): + headers["X-Audit-Log-Reason"] = data.pop("reason") request = Request( headers=headers, method="POST", From 5daffc2929b4af7b1fa5b95036b06ba9c66184f8 Mon Sep 17 00:00:00 2001 From: Autuamn_End Date: Wed, 11 Sep 2024 15:33:51 +0800 Subject: [PATCH 5/8] =?UTF-8?q?:sparkles:=20=E6=89=A9=E5=85=85=20Event?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nonebot/adapters/discord/api/model.py | 87 +++++++++++++++++++ nonebot/adapters/discord/api/types.py | 13 +++ nonebot/adapters/discord/event.py | 120 ++++++++++++++++++++++++++ 3 files changed, 220 insertions(+) diff --git a/nonebot/adapters/discord/api/model.py b/nonebot/adapters/discord/api/model.py index 574fdd9..2b68065 100644 --- a/nonebot/adapters/discord/api/model.py +++ b/nonebot/adapters/discord/api/model.py @@ -3911,6 +3911,84 @@ class Subscription(BaseModel): country: Missing[str] = UNSET +class EntitlementCreate(Entitlement): + """Entitlement Create Event Fields + + see https://discord.com/developers/docs/topics/gateway-events#entitlement-create""" + + +class EntitlementUpdate(Entitlement): + """Entitlement Update Event Fields + + see https://discord.com/developers/docs/topics/gateway-events#entitlement-update""" + + +class EntitlementDelete(Entitlement): + """Entitlement Delete Event Fields + + see https://discord.com/developers/docs/topics/gateway-events#entitlement-delete""" + + +class SubscriptionCreate(Subscription): + """Subscription Create Event Fields + + see https://discord.com/developers/docs/topics/gateway-events#subscription-create""" + + +class SubscriptionUpdate(Subscription): + """Subscription Update Event Fields + + see https://discord.com/developers/docs/topics/gateway-events#subscription-update""" + + +class SubscriptionDelete(Subscription): + """Subscription Delete Event Fields + + see https://discord.com/developers/docs/topics/gateway-events#subscription-delete""" + + +class VoiceChannelEffectSend(BaseModel): + """Voice Channel Effect Send Event Fields + + see https://discord.com/developers/docs/topics/gateway-events#voice-channel-effect-send-voice-channel-effect-send-event-fields + """ + + channel_id: Snowflake + guild_id: Snowflake + user_id: Snowflake + emoji: MissingOrNullable[Emoji] = UNSET + animation_type: MissingOrNullable[AnimationType] = UNSET + animation_id: Missing[int] = UNSET + sound_id: Missing[Union[Snowflake, int]] = UNSET + sound_volume: Missing[float] = UNSET + + +class MessagePollVoteAdd(BaseModel): + """Message Poll Vote Add Fields + + see https://discord.com/developers/docs/topics/gateway-events#message-poll-vote-add-message-poll-vote-add-fields + """ + + user_id: Snowflake + channel_id: Snowflake + message_id: Snowflake + guild_id: Missing[Snowflake] = UNSET + answer_id: int + + +class MessagePollVoteRemove(BaseModel): + """Message Poll Vote Remove Fields + + see https://discord.com/developers/docs/topics/gateway-events#message-poll-vote-add-message-poll-vote-remove-fields + """ + + user_id: Snowflake + channel_id: Snowflake + message_id: Snowflake + guild_id: Missing[Snowflake] = UNSET + answer_id: int + + for name, obj in inspect.getmembers(sys.modules[__name__]): if inspect.isclass(obj) and issubclass(obj, BaseModel) and obj is not BaseModel: if PYDANTIC_V2: @@ -4163,4 +4241,13 @@ class Subscription(BaseModel): "AnswerVoters", "SKU", "Subscription", + "EntitlementCreate", + "EntitlementUpdate", + "EntitlementDelete", + "SubscriptionCreate", + "SubscriptionUpdate", + "SubscriptionDelete", + "VoiceChannelEffectSend", + "MessagePollVoteAdd", + "MessagePollVoteRemove", ] diff --git a/nonebot/adapters/discord/api/types.py b/nonebot/adapters/discord/api/types.py index 9779210..53b6474 100644 --- a/nonebot/adapters/discord/api/types.py +++ b/nonebot/adapters/discord/api/types.py @@ -124,6 +124,18 @@ class ActivityType(IntEnum): """ Competing in {name}""" +class AnimationType(IntEnum): + """Animation Type + + see https://discord.com/developers/docs/topics/gateway-events#voice-channel-effect-send-animation-types + """ + + PREMIUM = 0 + """A fun animation, sent by a Nitro subscriber""" + BASIC = 1 + """The standard animation""" + + class ApplicationCommandOptionType(IntEnum): """Application Command Option Type @@ -1576,6 +1588,7 @@ class WebhookType(IntEnum): "ActivityAssetImage", "ActivityFlags", "ActivityType", + "AnimationType", "ApplicationCommandOptionType", "ApplicationCommandPermissionsType", "ApplicationCommandType", diff --git a/nonebot/adapters/discord/event.py b/nonebot/adapters/discord/event.py index 5756bb3..a2f0495 100644 --- a/nonebot/adapters/discord/event.py +++ b/nonebot/adapters/discord/event.py @@ -49,6 +49,11 @@ class EventType(str, Enum): THREAD_MEMBER_UPDATE = "THREAD_MEMBER_UPDATE" THREAD_MEMBERS_UPDATE = "THREAD_MEMBERS_UPDATE" + # ENTITLEMENTS + ENTITLEMENT_CREATE = "ENTITLEMENT_CREATE" + ENTITLEMENT_UPDATE = "ENTITLEMENT_UPDATE" + ENTITLEMENT_DELETE = "ENTITLEMENT_DELETE" + # GUILDS GUILD_CREATE = "GUILD_CREATE" GUILD_UPDATE = "GUILD_UPDATE" @@ -108,6 +113,11 @@ class EventType(str, Enum): STAGE_INSTANCE_UPDATE = "STAGE_INSTANCE_UPDATE" STAGE_INSTANCE_DELETE = "STAGE_INSTANCE_DELETE" + # SUBSCRIPTION + SUBSCRIPTION_CREATE = "SUBSCRIPTION_CREATE" + SUBSCRIPTION_UPDATE = "SUBSCRIPTION_UPDATE" + SUBSCRIPTION_DELETE = "SUBSCRIPTION_DELETE" + # TYPING TYPING_START = "TYPING_START" @@ -115,12 +125,17 @@ class EventType(str, Enum): USER_UPDATE = "USER_UPDATE" # VOICE + VOICE_CHANNEL_EFFECT_SEND = "VOICE_CHANNEL_EFFECT_SEND" VOICE_STATE_UPDATE = "VOICE_STATE_UPDATE" VOICE_SERVER_UPDATE = "VOICE_SERVER_UPDATE" # WEBHOOKS WEBHOOKS_UPDATE = "WEBHOOKS_UPDATE" + # POLL + MESSAGE_POLL_VOTE_ADD = "MESSAGE_POLL_VOTE_ADD" + MESSAGE_POLL_VOTE_REMOVE = "MESSAGE_POLL_VOTE_REMOVE" + class Event(BaseEvent): """Event""" @@ -407,6 +422,36 @@ class ThreadMembersUpdateEvent(ThreadEvent, ThreadMembersUpdate): __type__ = EventType.THREAD_MEMBERS_UPDATE +class EntitlementEvent(NoticeEvent): + """Entitlement event + + see https://discord.com/developers/docs/topics/gateway-events#entitlements""" + + +class EntitlementCreateEvent(EntitlementEvent, EntitlementCreate): + """Entitlement create event + + see https://discord.com/developers/docs/topics/gateway-events#entitlement-create""" + + __type__ = EventType.ENTITLEMENT_CREATE + + +class EntitlementUpdateEvent(EntitlementEvent, EntitlementUpdate): + """Entitlement update event + + see https://discord.com/developers/docs/topics/gateway-events#entitlement-update""" + + __type__ = EventType.ENTITLEMENT_UPDATE + + +class EntitlementDeleteEvent(EntitlementEvent, EntitlementDelete): + """Entitlement delete event + + see https://discord.com/developers/docs/topics/gateway-events#entitlement-delete""" + + __type__ = EventType.ENTITLEMENT_DELETE + + class GuildEvent(NoticeEvent): """Guild event @@ -850,6 +895,36 @@ class StageInstanceDeleteEvent(GuildEvent, StageInstanceDelete): __type__ = EventType.STAGE_INSTANCE_DELETE +class SubscriptionEvent(NoticeEvent): + """Subscription event + + see https://discord.com/developers/docs/topics/gateway-events#subscriptions""" + + +class SubscriptionCreateEvent(SubscriptionEvent, SubscriptionCreate): + """Subscription create event + + see https://discord.com/developers/docs/topics/gateway-events#subscription-create""" + + __type__ = EventType.SUBSCRIPTION_CREATE + + +class SubscriptionUpdateEvent(SubscriptionEvent, SubscriptionUpdate): + """Subscription Update event + + see https://discord.com/developers/docs/topics/gateway-events#subscription-update""" + + __type__ = EventType.SUBSCRIPTION_UPDATE + + +class SubscriptionDeleteEvent(SubscriptionEvent, SubscriptionDelete): + """Subscription delete event + + see https://discord.com/developers/docs/topics/gateway-events#subscription-delete""" + + __type__ = EventType.SUBSCRIPTION_DELETE + + class TypingStartEvent(NoticeEvent, TypingStart): """Typing Start Event @@ -878,6 +953,15 @@ class UserUpdateEvent(NoticeEvent, UserUpdate): __type__ = EventType.USER_UPDATE +class VoiceChannelEffectSendEvent(NoticeEvent, VoiceChannelEffectSend): + """Voice Channel Effect Send Event + + see https://discord.com/developers/docs/topics/gateway-events#voice-channel-effect-send + """ + + __type__ = EventType.VOICE_CHANNEL_EFFECT_SEND + + class VoiceStateUpdateEvent(NoticeEvent, VoiceStateUpdate): """Voice State Update Event @@ -905,6 +989,24 @@ class WebhooksUpdateEvent(NoticeEvent, WebhooksUpdate): __type__ = EventType.WEBHOOKS_UPDATE +class MessagePollVoteAddEvent(NoticeEvent, MessagePollVoteAdd): + """Message Poll Vote Add Event + + see https://discord.com/developers/docs/topics/gateway-events#message-poll-vote-add + """ + + __type__ = EventType.MESSAGE_POLL_VOTE_ADD + + +class MessagePollVoteRemoveEvent(NoticeEvent, MessagePollVoteRemove): + """Message Poll Vote Remove Event + + see https://discord.com/developers/docs/topics/gateway-events#message-poll-vote-remove + """ + + __type__ = EventType.MESSAGE_POLL_VOTE_REMOVE + + event_classes: dict[str, type[Event]] = { EventType.HELLO.value: HelloEvent, EventType.READY.value: ReadyEvent, @@ -930,6 +1032,9 @@ class WebhooksUpdateEvent(NoticeEvent, WebhooksUpdate): EventType.THREAD_LIST_SYNC.value: ThreadListSyncEvent, EventType.THREAD_MEMBER_UPDATE.value: ThreadMemberUpdateEvent, EventType.THREAD_MEMBERS_UPDATE.value: ThreadMembersUpdateEvent, + EventType.ENTITLEMENT_CREATE.value: EntitlementCreateEvent, + EventType.ENTITLEMENT_UPDATE.value: EntitlementUpdateEvent, + EventType.ENTITLEMENT_DELETE.value: EntitlementDeleteEvent, EventType.GUILD_CREATE.value: GuildCreateEvent, EventType.GUILD_UPDATE.value: GuildUpdateEvent, EventType.GUILD_DELETE.value: GuildDeleteEvent, @@ -1004,13 +1109,19 @@ class WebhooksUpdateEvent(NoticeEvent, WebhooksUpdate): EventType.STAGE_INSTANCE_CREATE.value: StageInstanceCreateEvent, EventType.STAGE_INSTANCE_UPDATE.value: StageInstanceUpdateEvent, EventType.STAGE_INSTANCE_DELETE.value: StageInstanceDeleteEvent, + EventType.SUBSCRIPTION_CREATE.value: SubscriptionCreateEvent, + EventType.SUBSCRIPTION_UPDATE.value: SubscriptionUpdateEvent, + EventType.SUBSCRIPTION_DELETE.value: SubscriptionDeleteEvent, EventType.TYPING_START.value: Union[ GuildTypingStartEvent, DirectTypingStartEvent, TypingStartEvent ], EventType.USER_UPDATE.value: UserUpdateEvent, + EventType.VOICE_CHANNEL_EFFECT_SEND.value: VoiceChannelEffectSendEvent, EventType.VOICE_STATE_UPDATE.value: VoiceStateUpdateEvent, EventType.VOICE_SERVER_UPDATE.value: VoiceServerUpdateEvent, EventType.WEBHOOKS_UPDATE.value: WebhooksUpdateEvent, + EventType.MESSAGE_POLL_VOTE_ADD.value: MessagePollVoteAddEvent, + EventType.MESSAGE_POLL_VOTE_REMOVE.value: MessagePollVoteRemoveEvent, } # type: ignore __all__ = [ @@ -1043,6 +1154,9 @@ class WebhooksUpdateEvent(NoticeEvent, WebhooksUpdate): "ThreadListSyncEvent", "ThreadMemberUpdateEvent", "ThreadMembersUpdateEvent", + "EntitlementCreateEvent", + "EntitlementUpdateEvent", + "EntitlementDeleteEvent", "GuildEvent", "GuildCreateEvent", "GuildUpdateEvent", @@ -1105,12 +1219,18 @@ class WebhooksUpdateEvent(NoticeEvent, WebhooksUpdate): "StageInstanceCreateEvent", "StageInstanceUpdateEvent", "StageInstanceDeleteEvent", + "SubscriptionCreateEvent", + "SubscriptionUpdateEvent", + "SubscriptionDeleteEvent", "TypingStartEvent", "GuildTypingStartEvent", "DirectTypingStartEvent", "UserUpdateEvent", + "VoiceChannelEffectSendEvent", "VoiceStateUpdateEvent", "VoiceServerUpdateEvent", "WebhooksUpdateEvent", + "MessagePollVoteAddEvent", + "MessagePollVoteRemoveEvent", "event_classes", ] From 0bd0907352ecc5cd5bc4b8a756345fc2188844e2 Mon Sep 17 00:00:00 2001 From: Autuamn_End Date: Tue, 17 Sep 2024 11:51:01 +0800 Subject: [PATCH 6/8] =?UTF-8?q?:sparkles:=20=E6=B7=BB=E5=8A=A0=20Intents?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nonebot/adapters/discord/config.py | 4 ++++ nonebot/adapters/discord/event.py | 32 ++++++++++++++++++++++++++++-- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/nonebot/adapters/discord/config.py b/nonebot/adapters/discord/config.py index d267197..a9e9902 100644 --- a/nonebot/adapters/discord/config.py +++ b/nonebot/adapters/discord/config.py @@ -25,6 +25,8 @@ class Intents(BaseModel): guild_scheduled_events: bool = True auto_moderation_configuration: bool = True auto_moderation_execution: bool = True + guild_message_polls: bool = True + direct_message_polls: bool = True def to_int(self): return ( @@ -47,6 +49,8 @@ def to_int(self): | self.guild_scheduled_events << 16 | self.auto_moderation_configuration << 20 | self.auto_moderation_execution << 21 + | self.guild_message_polls << 24 + | self.direct_message_polls << 25 ) diff --git a/nonebot/adapters/discord/event.py b/nonebot/adapters/discord/event.py index a2f0495..fa8dc9b 100644 --- a/nonebot/adapters/discord/event.py +++ b/nonebot/adapters/discord/event.py @@ -998,6 +998,14 @@ class MessagePollVoteAddEvent(NoticeEvent, MessagePollVoteAdd): __type__ = EventType.MESSAGE_POLL_VOTE_ADD +class GuildMessagePollVoteAddEvent(MessagePollVoteAddEvent): + guild_id: Snowflake + + +class DirectMessagePollVoteAddEvent(MessagePollVoteAddEvent): + guild_id: Literal[UNSET] = Field(UNSET, exclude=True) + + class MessagePollVoteRemoveEvent(NoticeEvent, MessagePollVoteRemove): """Message Poll Vote Remove Event @@ -1007,6 +1015,14 @@ class MessagePollVoteRemoveEvent(NoticeEvent, MessagePollVoteRemove): __type__ = EventType.MESSAGE_POLL_VOTE_REMOVE +class GuildMessagePollVoteRemoveEvent(MessagePollVoteRemoveEvent): + guild_id: Snowflake + + +class DirectMessagePollVoteRemoveEvent(MessagePollVoteRemoveEvent): + guild_id: Literal[UNSET] = Field(UNSET, exclude=True) + + event_classes: dict[str, type[Event]] = { EventType.HELLO.value: HelloEvent, EventType.READY.value: ReadyEvent, @@ -1120,8 +1136,16 @@ class MessagePollVoteRemoveEvent(NoticeEvent, MessagePollVoteRemove): EventType.VOICE_STATE_UPDATE.value: VoiceStateUpdateEvent, EventType.VOICE_SERVER_UPDATE.value: VoiceServerUpdateEvent, EventType.WEBHOOKS_UPDATE.value: WebhooksUpdateEvent, - EventType.MESSAGE_POLL_VOTE_ADD.value: MessagePollVoteAddEvent, - EventType.MESSAGE_POLL_VOTE_REMOVE.value: MessagePollVoteRemoveEvent, + EventType.MESSAGE_POLL_VOTE_ADD.value: Union[ + GuildMessagePollVoteAddEvent, + DirectMessagePollVoteAddEvent, + MessagePollVoteAddEvent, + ], + EventType.MESSAGE_POLL_VOTE_REMOVE.value: Union[ + GuildMessagePollVoteRemoveEvent, + DirectMessagePollVoteRemoveEvent, + MessagePollVoteRemoveEvent, + ], } # type: ignore __all__ = [ @@ -1231,6 +1255,10 @@ class MessagePollVoteRemoveEvent(NoticeEvent, MessagePollVoteRemove): "VoiceServerUpdateEvent", "WebhooksUpdateEvent", "MessagePollVoteAddEvent", + "GuildMessagePollVoteAddEvent", + "DirectMessagePollVoteAddEvent", "MessagePollVoteRemoveEvent", + "GuildMessagePollVoteRemoveEvent", + "DirectMessagePollVoteRemoveEvent", "event_classes", ] From 58b1c870472cfa4e4d307b937b5a4671be1005cb Mon Sep 17 00:00:00 2001 From: Autuamn_End Date: Sat, 21 Sep 2024 17:09:40 +0800 Subject: [PATCH 7/8] =?UTF-8?q?:sparkles:=20=E5=AE=8C=E5=96=84=20`poll`=20?= =?UTF-8?q?=E7=9B=B8=E5=85=B3=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nonebot/adapters/discord/api/client.pyi | 8 ++++++++ nonebot/adapters/discord/api/model.py | 27 ++++++++++++++++++++++++- nonebot/adapters/discord/api/types.py | 3 +++ nonebot/adapters/discord/message.py | 26 ++++++++++++++++++++++++ 4 files changed, 63 insertions(+), 1 deletion(-) diff --git a/nonebot/adapters/discord/api/client.pyi b/nonebot/adapters/discord/api/client.pyi index c6d64fb..73ed33e 100644 --- a/nonebot/adapters/discord/api/client.pyi +++ b/nonebot/adapters/discord/api/client.pyi @@ -458,6 +458,7 @@ class ApiClient: files: list[File] | None = ..., attachments: list[AttachmentSend] | None = ..., flags: MessageFlag | None = ..., + poll: PollRequest | None = ..., ) -> MessageGet: """create message @@ -1827,6 +1828,8 @@ class ApiClient: attachments: list[AttachmentSend] | None = ..., flags: int | None = ..., thread_name: str | None = ..., + applied_tags: list[SnowflakeType] | None = ..., + poll: PollRequest | None = ..., **data, ) -> None: ... @overload @@ -1848,6 +1851,8 @@ class ApiClient: attachments: list[AttachmentSend] | None = ..., flags: int | None = ..., thread_name: str | None = ..., + applied_tags: list[SnowflakeType] | None = ..., + poll: PollRequest | None = ..., **data, ) -> MessageGet: ... async def execute_webhook( @@ -1868,6 +1873,8 @@ class ApiClient: attachments: list[AttachmentSend] | None = ..., flags: int | None = ..., thread_name: str | None = ..., + applied_tags: list[SnowflakeType] | None = ..., + poll: PollRequest | None = ..., **data, ) -> MessageGet | None: """https://discord.com/developers/docs/resources/webhook#execute-webhook""" @@ -1918,6 +1925,7 @@ class ApiClient: components: list[Component] | None = ..., files: list[File] | None = ..., attachments: list[AttachmentSend] | None = ..., + poll: PollRequest | None = ..., ) -> MessageGet: """https://discord.com/developers/docs/resources/webhook#edit-webhook-message""" ... diff --git a/nonebot/adapters/discord/api/model.py b/nonebot/adapters/discord/api/model.py index 2b68065..ce5760b 100644 --- a/nonebot/adapters/discord/api/model.py +++ b/nonebot/adapters/discord/api/model.py @@ -872,6 +872,8 @@ class InteractionCallbackMessage(BaseModel): attachments: Optional[list["AttachmentSend"]] = None """attachment objects with filename and description. See Uploading Files for details.""" + poll: Optional["PollRequest"] = None + """Details about the poll""" files: Optional[list["File"]] = None @@ -1757,6 +1759,7 @@ class MessageSend(BaseModel): files: Optional[list[File]] = None attachments: Optional[list[AttachmentSend]] = None flags: Optional[MessageFlag] = None + poll: Optional["PollRequest"] = None class ModifyChannelParams(BaseModel): @@ -3677,7 +3680,7 @@ class Poll(BaseModel): """The question of the poll. Only `text` is supported.""" answers: list["PollAnswer"] """Each of the answers available in the poll.""" - expiry: datetime.datetime + expiry: Optional[datetime.datetime] = None """The time when the poll ends.""" allow_multiselect: bool """Whether a user can select multiple answers""" @@ -3687,6 +3690,27 @@ class Poll(BaseModel): """The results of the poll""" +class PollRequest(BaseModel): + """This is the request object used when creating a poll across the + different endpoints. It is similar but not exactly identical to the + main poll object. The main difference is that the request has `duration` + which eventually becomes `expiry`. + + see https://discord.com/developers/docs/resources/poll#poll-create-request-object + """ + + question: "PollMedia" + """The question of the poll. Only `text` is supported.""" + answers: list["PollAnswer"] + """Each of the answers available in the poll, up to 10""" + duration: Missing[int] = UNSET + """Number of hours the poll should be open for, up to 32 days. Defaults to 24""" + allow_multiselect: Missing[bool] = UNSET + """Whether a user can select multiple answers. Defaults to false""" + layout_type: Missing[int] + """The layout type of the poll""" + + class PollAnswer(BaseModel): """answer_id: Only sent as part of responses from Discord's API/Gateway. @@ -4226,6 +4250,7 @@ class MessagePollVoteRemove(BaseModel): "TeamMemberUser", "AuthorizationResponse", "Poll", + "PollRequest", "PollAnswer", "PollMedia", "PollResults", diff --git a/nonebot/adapters/discord/api/types.py b/nonebot/adapters/discord/api/types.py index 53b6474..a8fd357 100644 --- a/nonebot/adapters/discord/api/types.py +++ b/nonebot/adapters/discord/api/types.py @@ -558,6 +558,8 @@ class EmbedTypes(StrEnum): """article embed""" link = "link" """link embed""" + poll_result = "poll_result" + """poll result embed""" class EntitlementType(IntEnum): @@ -1148,6 +1150,7 @@ class MessageType(IntEnum): GUILD_INCIDENT_REPORT_RAID = 38 GUILD_INCIDENT_REPORT_FALSE_ALARM = 39 PURCHASE_NOTIFICATION = 44 + POLL_RESULT = 46 class MembershipState(IntEnum): diff --git a/nonebot/adapters/discord/message.py b/nonebot/adapters/discord/message.py index 3afac43..58aad5f 100644 --- a/nonebot/adapters/discord/message.py +++ b/nonebot/adapters/discord/message.py @@ -29,6 +29,8 @@ File, MessageGet, MessageReference, + Poll, + PollRequest, SelectMenu, Snowflake, SnowflakeType, @@ -170,6 +172,10 @@ def reference( return ReferenceSegment("reference", {"reference": _reference}) + @staticmethod + def poll(poll: Union[Poll, PollRequest]) -> "PollSegment": + return PollSegment("poll", {"poll": poll}) + @override def is_text(self) -> bool: return self.type == "text" @@ -366,6 +372,21 @@ def __str__(self): return f"" +class PollData(TypedDict): + poll: Union[Poll, PollRequest] + + +@dataclass +class PollSegment(MessageSegment): + if TYPE_CHECKING: + type: Literal["poll"] + data: PollData + + @override + def __str__(self) -> str: + return f"" + + class Message(BaseMessage[MessageSegment]): @classmethod @override @@ -455,6 +476,8 @@ def from_guild_message(cls, message: MessageGet) -> "Message": msg.extend( MessageSegment.component(component) for component in message.components ) + if message.poll: + msg.append(MessageSegment.poll(message.poll)) return msg def extract_content(self) -> str: @@ -487,6 +510,8 @@ def parse_message(message: Union[Message, MessageSegment, str]) -> dict[str, Any components = [component.data["component"] for component in components] if sticker_ids := (message["sticker"] or None): sticker_ids = [sticker.data["id"] for sticker in sticker_ids] + if poll := (message["poll"] or None): + poll = poll[-1].data["poll"] attachments = None files = None @@ -507,6 +532,7 @@ def parse_message(message: Union[Message, MessageSegment, str]) -> dict[str, Any "message_reference": reference, "components": components, "sticker_ids": sticker_ids, + "poll": poll, "files": files, "attachments": attachments, }.items() From ffa908b996e8b9b716db7f81ece9b69d2874a2fc Mon Sep 17 00:00:00 2001 From: Autuamn_End Date: Sat, 21 Sep 2024 17:19:46 +0800 Subject: [PATCH 8/8] =?UTF-8?q?:bug:=20=E4=B8=BA=20`layout=5Ftype`=20?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E9=BB=98=E8=AE=A4=E5=80=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nonebot/adapters/discord/api/model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nonebot/adapters/discord/api/model.py b/nonebot/adapters/discord/api/model.py index ce5760b..9494b2a 100644 --- a/nonebot/adapters/discord/api/model.py +++ b/nonebot/adapters/discord/api/model.py @@ -3707,7 +3707,7 @@ class PollRequest(BaseModel): """Number of hours the poll should be open for, up to 32 days. Defaults to 24""" allow_multiselect: Missing[bool] = UNSET """Whether a user can select multiple answers. Defaults to false""" - layout_type: Missing[int] + layout_type: Missing[int] = UNSET """The layout type of the poll"""