Skip to content

Commit 17172da

Browse files
authored
Stablise User Apps (#3018)
1 parent 57f66f7 commit 17172da

File tree

8 files changed

+124
-64
lines changed

8 files changed

+124
-64
lines changed

src/builder/create_command.rs

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -313,10 +313,8 @@ pub struct CreateCommand {
313313
#[serde(skip_serializing_if = "Option::is_none")]
314314
#[serde(rename = "type")]
315315
kind: Option<CommandType>,
316-
#[cfg(feature = "unstable_discord_api")]
317316
#[serde(skip_serializing_if = "Option::is_none")]
318317
integration_types: Option<Vec<InstallationContext>>,
319-
#[cfg(feature = "unstable_discord_api")]
320318
#[serde(skip_serializing_if = "Option::is_none")]
321319
contexts: Option<Vec<InteractionContext>>,
322320
nsfw: bool,
@@ -335,9 +333,7 @@ impl CreateCommand {
335333
default_member_permissions: None,
336334
dm_permission: None,
337335

338-
#[cfg(feature = "unstable_discord_api")]
339336
integration_types: None,
340-
#[cfg(feature = "unstable_discord_api")]
341337
contexts: None,
342338

343339
options: Vec::new(),
@@ -430,28 +426,24 @@ impl CreateCommand {
430426
self
431427
}
432428

433-
#[cfg(feature = "unstable_discord_api")]
434429
/// Adds an installation context that this application command can be used in.
435430
pub fn add_integration_type(mut self, integration_type: InstallationContext) -> Self {
436431
self.integration_types.get_or_insert_with(Vec::default).push(integration_type);
437432
self
438433
}
439434

440-
#[cfg(feature = "unstable_discord_api")]
441435
/// Sets the installation contexts that this application command can be used in.
442436
pub fn integration_types(mut self, integration_types: Vec<InstallationContext>) -> Self {
443437
self.integration_types = Some(integration_types);
444438
self
445439
}
446440

447-
#[cfg(feature = "unstable_discord_api")]
448441
/// Adds an interaction context that this application command can be used in.
449442
pub fn add_context(mut self, context: InteractionContext) -> Self {
450443
self.contexts.get_or_insert_with(Vec::default).push(context);
451444
self
452445
}
453446

454-
#[cfg(feature = "unstable_discord_api")]
455447
/// Sets the interaction contexts that this application command can be used in.
456448
pub fn contexts(mut self, contexts: Vec<InteractionContext>) -> Self {
457449
self.contexts = Some(contexts);

src/model/application/command.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ use std::collections::HashMap;
22

33
use serde::Serialize;
44

5-
#[cfg(feature = "unstable_discord_api")]
65
use super::{InstallationContext, InteractionContext};
76
#[cfg(feature = "model")]
87
use crate::builder::{Builder, CreateCommand};
@@ -86,14 +85,12 @@ pub struct Command {
8685
pub nsfw: bool,
8786
/// Installation context(s) where the command is available, only for globally-scoped commands.
8887
///
89-
/// Defaults to [`InstallationContext::Guild`]
90-
#[cfg(feature = "unstable_discord_api")]
88+
/// Defaults to [`InstallationContext::Guild`] and [`InstallationContext::User`].
9189
#[serde(default)]
9290
pub integration_types: Vec<InstallationContext>,
9391
/// Interaction context(s) where the command can be used, only for globally-scoped commands.
9492
///
9593
/// By default, all interaction context types are included.
96-
#[cfg(feature = "unstable_discord_api")]
9794
pub contexts: Option<Vec<InteractionContext>>,
9895
/// An autoincremented version identifier updated during substantial record changes.
9996
pub version: CommandVersionId,

src/model/application/command_interaction.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ use serde::de::{Deserializer, Error as DeError};
44
use serde::ser::{Error as _, Serializer};
55
use serde::{Deserialize, Serialize};
66

7-
#[cfg(feature = "unstable_discord_api")]
87
use super::{AuthorizingIntegrationOwners, InteractionContext};
98
#[cfg(feature = "model")]
109
use crate::builder::{
@@ -86,10 +85,8 @@ pub struct CommandInteraction {
8685
pub entitlements: Vec<Entitlement>,
8786
/// The owners of the applications that authorized the interaction, such as a guild or user.
8887
#[serde(default)]
89-
#[cfg(feature = "unstable_discord_api")]
9088
pub authorizing_integration_owners: AuthorizingIntegrationOwners,
9189
/// The context where the interaction was triggered from.
92-
#[cfg(feature = "unstable_discord_api")]
9390
pub context: Option<InteractionContext>,
9491
}
9592

src/model/application/component_interaction.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,8 @@ pub struct ComponentInteraction {
6464
pub entitlements: Vec<Entitlement>,
6565
/// The owners of the applications that authorized the interaction, such as a guild or user.
6666
#[serde(default)]
67-
#[cfg(feature = "unstable_discord_api")]
6867
pub authorizing_integration_owners: AuthorizingIntegrationOwners,
6968
/// The context where the interaction was triggered from.
70-
#[cfg(feature = "unstable_discord_api")]
7169
pub context: Option<InteractionContext>,
7270
}
7371

src/model/application/interaction.rs

Lines changed: 118 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,20 @@
11
use serde::de::{Deserialize, Deserializer, Error as DeError};
22
use serde::ser::{Serialize, Serializer};
33

4-
#[cfg(feature = "unstable_discord_api")]
5-
use super::InstallationContext;
6-
use super::{CommandInteraction, ComponentInteraction, ModalInteraction, PingInteraction};
4+
use super::{
5+
CommandInteraction,
6+
ComponentInteraction,
7+
InstallationContext,
8+
ModalInteraction,
9+
PingInteraction,
10+
};
711
use crate::internal::prelude::*;
812
use crate::json::from_value;
913
use crate::model::guild::PartialMember;
10-
use crate::model::id::{ApplicationId, InteractionId};
11-
#[cfg(feature = "unstable_discord_api")]
12-
use crate::model::id::{GuildId, MessageId, UserId};
14+
use crate::model::id::{ApplicationId, GuildId, InteractionId, MessageId, UserId};
1315
use crate::model::monetization::Entitlement;
1416
use crate::model::user::User;
15-
use crate::model::utils::deserialize_val;
16-
#[cfg(feature = "unstable_discord_api")]
17-
use crate::model::utils::StrOrInt;
17+
use crate::model::utils::{deserialize_val, remove_from_map, StrOrInt};
1818
use crate::model::Permissions;
1919

2020
/// [Discord docs](https://discord.com/developers/docs/interactions/receiving-and-responding#interaction-object)
@@ -299,7 +299,6 @@ bitflags! {
299299
///
300300
/// [Discord Docs](https://discord.com/developers/docs/interactions/receiving-and-responding#interaction-object-authorizing-integration-owners-object)
301301
#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
302-
#[cfg(feature = "unstable_discord_api")]
303302
#[derive(Clone, Debug)]
304303
#[non_exhaustive]
305304
pub enum AuthorizingIntegrationOwner {
@@ -315,12 +314,10 @@ pub enum AuthorizingIntegrationOwner {
315314
}
316315

317316
#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
318-
#[cfg(feature = "unstable_discord_api")]
319317
#[derive(Clone, Debug, Default)]
320318
#[repr(transparent)]
321319
pub struct AuthorizingIntegrationOwners(pub Vec<AuthorizingIntegrationOwner>);
322320

323-
#[cfg(feature = "unstable_discord_api")]
324321
impl<'de> serde::Deserialize<'de> for AuthorizingIntegrationOwners {
325322
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> StdResult<Self, D::Error> {
326323
struct Visitor;
@@ -366,7 +363,6 @@ impl<'de> serde::Deserialize<'de> for AuthorizingIntegrationOwners {
366363
}
367364
}
368365

369-
#[cfg(feature = "unstable_discord_api")]
370366
impl serde::Serialize for AuthorizingIntegrationOwners {
371367
fn serialize<S: Serializer>(&self, serializer: S) -> StdResult<S::Ok, S::Error> {
372368
use serde::ser::SerializeMap;
@@ -419,28 +415,121 @@ pub struct MessageInteraction {
419415
pub member: Option<PartialMember>,
420416
}
421417

422-
/// Metadata about the interaction, including the source of the interaction relevant server and
423-
/// user IDs.
424418
#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
425-
#[derive(Clone, Debug, Deserialize, Serialize)]
426-
#[cfg(feature = "unstable_discord_api")]
427-
pub struct MessageInteractionMetadata {
419+
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
420+
#[non_exhaustive]
421+
pub struct MessageCommandInteractionMetadata {
428422
/// The ID of the interaction
429423
pub id: InteractionId,
430-
/// The type of interaction
431-
#[serde(rename = "type")]
432-
pub kind: InteractionType,
433-
/// The ID of the user who triggered the interaction
424+
/// The user who triggered the interaction
425+
pub user: User,
426+
/// The IDs for installation context(s) related to an interaction.
427+
pub authorizing_integration_owners: AuthorizingIntegrationOwners,
428+
/// The ID of the original response message, present only on follow-up messages.
429+
pub original_response_message_id: Option<MessageId>,
430+
/// The user the command was run on, present only on user command interactions
431+
pub target_user: Option<User>,
432+
/// The ID of the message the command was run on, present only on message command
433+
/// interactions.
434+
pub target_message_id: Option<MessageId>,
435+
}
436+
437+
#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
438+
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
439+
#[non_exhaustive]
440+
pub struct MessageComponentInteractionMetadata {
441+
/// The ID of the interaction
442+
pub id: InteractionId,
443+
/// The user who triggered the interaction
444+
pub user: User,
445+
/// The IDs for installation context(s) related to an interaction.
446+
pub authorizing_integration_owners: AuthorizingIntegrationOwners,
447+
/// The ID of the original response message, present only on follow-up messages.
448+
pub original_response_message_id: Option<MessageId>,
449+
/// The ID of the message that contained the interactive component
450+
pub interacted_message_id: MessageId,
451+
}
452+
453+
#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
454+
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
455+
#[non_exhaustive]
456+
pub struct MessageModalSubmitInteractionMetadata {
457+
/// The ID of the interaction
458+
pub id: InteractionId,
459+
/// The user who triggered the interaction
434460
pub user: User,
435461
/// The IDs for installation context(s) related to an interaction.
436-
#[serde(default)]
437462
pub authorizing_integration_owners: AuthorizingIntegrationOwners,
438463
/// The ID of the original response message, present only on follow-up messages.
439464
pub original_response_message_id: Option<MessageId>,
440-
/// ID of the message that contained interactive component, present only on messages created
441-
/// from component interactions.
442-
pub interacted_message_id: Option<MessageId>,
443-
/// Metadata for the interaction that was used to open the modal, present only on modal submit
444-
/// interactions
445-
pub triggering_interaction_metadata: Option<Box<MessageInteractionMetadata>>,
465+
/// Metadata for the interaction that was used to open the modal
466+
pub triggering_interaction_metadata: Box<MessageInteractionMetadata>,
467+
}
468+
469+
/// Metadata about the interaction, including the source of the interaction relevant server and
470+
/// user IDs.
471+
#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
472+
#[derive(Clone, Debug)]
473+
#[non_exhaustive]
474+
pub enum MessageInteractionMetadata {
475+
Command(MessageCommandInteractionMetadata),
476+
Component(MessageComponentInteractionMetadata),
477+
ModalSubmit(MessageModalSubmitInteractionMetadata),
478+
Unknown(InteractionType),
479+
}
480+
481+
impl<'de> serde::Deserialize<'de> for MessageInteractionMetadata {
482+
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> StdResult<Self, D::Error> {
483+
let mut data = JsonMap::deserialize(deserializer)?;
484+
let kind: InteractionType = remove_from_map(&mut data, "type")?;
485+
486+
match kind {
487+
InteractionType::Command => deserialize_val(Value::from(data)).map(Self::Command),
488+
InteractionType::Component => deserialize_val(Value::from(data)).map(Self::Component),
489+
InteractionType::Modal => deserialize_val(Value::from(data)).map(Self::ModalSubmit),
490+
491+
unknown => Ok(Self::Unknown(unknown)),
492+
}
493+
}
494+
}
495+
496+
impl serde::Serialize for MessageInteractionMetadata {
497+
fn serialize<S: Serializer>(&self, serializer: S) -> StdResult<S::Ok, S::Error> {
498+
#[derive(serde::Serialize)]
499+
struct WithType<T> {
500+
#[serde(rename = "type")]
501+
kind: InteractionType,
502+
#[serde(flatten)]
503+
val: T,
504+
}
505+
506+
fn serialize_with_type<S: Serializer, T: serde::Serialize>(
507+
serializer: S,
508+
val: T,
509+
kind: InteractionType,
510+
) -> StdResult<S::Ok, S::Error> {
511+
let wrapper = WithType {
512+
kind,
513+
val,
514+
};
515+
516+
wrapper.serialize(serializer)
517+
}
518+
519+
match self {
520+
MessageInteractionMetadata::Command(val) => {
521+
serialize_with_type(serializer, val, InteractionType::Command)
522+
},
523+
MessageInteractionMetadata::Component(val) => {
524+
serialize_with_type(serializer, val, InteractionType::Component)
525+
},
526+
MessageInteractionMetadata::ModalSubmit(val) => {
527+
serialize_with_type(serializer, val, InteractionType::Modal)
528+
},
529+
&MessageInteractionMetadata::Unknown(kind) => {
530+
tracing::warn!("Tried to serialize MessageInteractionMetadata::Unknown({}), serialising null instead", u8::from(kind));
531+
serializer.serialize_none()
532+
},
533+
}
534+
}
446535
}

src/model/application/mod.rs

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
//! Models about OAuth2 applications.
22
3+
use std::collections::HashMap;
4+
35
mod command;
46
pub use command::*;
57
mod command_interaction;
@@ -77,10 +79,8 @@ pub struct CurrentApplicationInfo {
7779
/// The application's role connection verification entry point, which when configured will
7880
/// render the app as a verification method in the guild role verification configuration.
7981
pub role_connections_verification_url: Option<String>,
80-
#[cfg(feature = "unstable_discord_api")]
8182
#[serde(default)]
82-
pub integration_types_config:
83-
std::collections::HashMap<InstallationContext, InstallationContextConfig>,
83+
pub integration_types_config: HashMap<InstallationContext, InstallationContextConfig>,
8484
pub approximate_guild_count: Option<u32>,
8585
pub approximate_user_install_count: Option<u32>,
8686
pub guild: Option<PartialGuild>,
@@ -99,7 +99,6 @@ impl CurrentApplicationInfo {
9999
}
100100
}
101101

102-
#[cfg(feature = "unstable_discord_api")]
103102
enum_number! {
104103
/// An enum representing the [installation contexts].
105104
///
@@ -115,7 +114,6 @@ enum_number! {
115114
}
116115
}
117116

118-
#[cfg(feature = "unstable_discord_api")]
119117
enum_number! {
120118
/// An enum representing the different [interaction contexts].
121119
///
@@ -138,7 +136,6 @@ enum_number! {
138136
/// Information about how the [`CurrentApplicationInfo`] is installed.
139137
///
140138
/// [Discord docs](https://discord.com/developers/docs/resources/application#application-object-application-integration-types).
141-
#[cfg(feature = "unstable_discord_api")]
142139
#[derive(Clone, Debug, Deserialize, Serialize)]
143140
pub struct InstallationContextConfig {
144141
pub oauth2_install_params: Option<InstallParams>,

src/model/channel/message.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -106,15 +106,11 @@ pub struct Message {
106106
pub flags: Option<MessageFlags>,
107107
/// The message that was replied to using this message.
108108
pub referenced_message: Option<Box<Message>>, // Boxed to avoid recursion
109-
#[cfg_attr(
110-
all(not(ignore_serenity_deprecated), feature = "unstable_discord_api"),
111-
deprecated = "Use interaction_metadata"
112-
)]
109+
#[cfg_attr(not(ignore_serenity_deprecated), deprecated = "Use interaction_metadata")]
113110
pub interaction: Option<Box<MessageInteraction>>,
114111
/// Sent if the message is a response to an [`Interaction`].
115112
///
116113
/// [`Interaction`]: crate::model::application::Interaction
117-
#[cfg(feature = "unstable_discord_api")]
118114
pub interaction_metadata: Option<Box<MessageInteractionMetadata>>,
119115
/// The thread that was started from this message, includes thread member object.
120116
pub thread: Option<GuildChannel>,

src/model/event.rs

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -525,13 +525,9 @@ pub struct MessageUpdateEvent {
525525
pub flags: Option<Option<MessageFlags>>,
526526
#[serde(default, deserialize_with = "deserialize_some")]
527527
pub referenced_message: Option<Option<Box<Message>>>,
528-
#[cfg_attr(
529-
all(not(ignore_serenity_deprecated), feature = "unstable_discord_api"),
530-
deprecated = "Use interaction_metadata"
531-
)]
528+
#[cfg_attr(not(ignore_serenity_deprecated), deprecated = "Use interaction_metadata")]
532529
#[serde(default, deserialize_with = "deserialize_some")]
533530
pub interaction: Option<Option<Box<MessageInteraction>>>,
534-
#[cfg(feature = "unstable_discord_api")]
535531
pub interaction_metadata: Option<Option<Box<MessageInteractionMetadata>>>,
536532
#[serde(default, deserialize_with = "deserialize_some")]
537533
pub thread: Option<Option<GuildChannel>>,
@@ -576,7 +572,6 @@ impl MessageUpdateEvent {
576572
flags,
577573
referenced_message,
578574
interaction,
579-
#[cfg(feature = "unstable_discord_api")]
580575
interaction_metadata,
581576
thread,
582577
components,
@@ -615,7 +610,6 @@ impl MessageUpdateEvent {
615610
if let Some(x) = flags { message.flags.clone_from(x) }
616611
if let Some(x) = referenced_message { message.referenced_message.clone_from(x) }
617612
if let Some(x) = interaction { message.interaction.clone_from(x) }
618-
#[cfg(feature = "unstable_discord_api")]
619613
if let Some(x) = interaction_metadata { message.interaction_metadata.clone_from(x) }
620614
if let Some(x) = thread { message.thread.clone_from(x) }
621615
if let Some(x) = components { message.components.clone_from(x) }

0 commit comments

Comments
 (0)