twilight_model/oauth/
application.rs

1use super::{
2    ApplicationFlags, InstallParams,
3    application_integration_type::{ApplicationIntegrationMap, ApplicationIntegrationTypeConfig},
4    team::Team,
5};
6use crate::{
7    guild::Guild,
8    id::{
9        Id,
10        marker::{ApplicationMarker, GuildMarker, OauthSkuMarker},
11    },
12    user::User,
13    util::image_hash::ImageHash,
14};
15use serde::{Deserialize, Serialize};
16
17#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
18pub struct Application {
19    /// Approximate count of guilds this app has been added to.
20    #[serde(skip_serializing_if = "Option::is_none")]
21    pub approximate_guild_count: Option<u64>,
22    /// Approximate count of users that have installed the app.
23    #[serde(skip_serializing_if = "Option::is_none")]
24    pub approximate_user_install_count: Option<u64>,
25    /// Partial user object for the bot user associated with the app.
26    #[serde(skip_serializing_if = "Option::is_none")]
27    pub bot: Option<User>,
28    /// When `false`, only the app owner can add the app to guilds
29    pub bot_public: bool,
30    /// When `true`, the app's bot will only join upon completion of the
31    /// full OAuth2 code grant flow
32    pub bot_require_code_grant: bool,
33    /// Default rich presence invite cover image.
34    #[serde(skip_serializing_if = "Option::is_none")]
35    pub cover_image: Option<ImageHash>,
36    /// Application's default custom authorization link, if enabled.
37    #[serde(skip_serializing_if = "Option::is_none")]
38    pub custom_install_url: Option<String>,
39    /// Description of the application.
40    pub description: String,
41    /// Public flags of the application.
42    pub flags: Option<ApplicationFlags>,
43    /// Partial object of the associated guild.
44    #[serde(skip_serializing_if = "Option::is_none")]
45    pub guild: Option<Guild>,
46    /// Guild associated with the app. For example, a developer support server.
47    #[serde(skip_serializing_if = "Option::is_none")]
48    pub guild_id: Option<Id<GuildMarker>>,
49    /// Icon of the application.
50    pub icon: Option<ImageHash>,
51    /// ID of the application.
52    pub id: Id<ApplicationMarker>,
53    /// Settings for the application's default in-app authorization, if enabled.
54    #[serde(skip_serializing_if = "Option::is_none")]
55    pub install_params: Option<InstallParams>,
56    #[serde(skip_serializing_if = "Option::is_none")]
57    pub integration_types_config:
58        Option<ApplicationIntegrationMap<ApplicationIntegrationTypeConfig>>,
59    /// Interactions endpoint URL for the app.
60    #[serde(skip_serializing_if = "Option::is_none")]
61    pub interactions_endpoint_url: Option<String>,
62    /// Name of the application.
63    pub name: String,
64    /// Partial user object for the owner of the app.
65    #[serde(skip_serializing_if = "Option::is_none")]
66    pub owner: Option<User>,
67    /// If this app is a game sold on Discord, this field will be the
68    /// id of the "Game SKU" that is created, if exists.
69    #[serde(skip_serializing_if = "Option::is_none")]
70    pub primary_sku_id: Option<Id<OauthSkuMarker>>,
71    /// URL of the application's privacy policy.
72    #[serde(skip_serializing_if = "Option::is_none")]
73    pub privacy_policy_url: Option<String>,
74    /// Redirect URIs for the application.
75    #[serde(skip_serializing_if = "Option::is_none")]
76    pub redirect_uris: Option<Vec<String>>,
77    /// Role connection verification URL for the app.
78    #[serde(skip_serializing_if = "Option::is_none")]
79    pub role_connections_verification_url: Option<String>,
80    #[serde(default)]
81    pub rpc_origins: Vec<String>,
82    /// If this app is a game sold on Discord, this field will be the
83    /// URL slug that links to the store page.
84    #[serde(skip_serializing_if = "Option::is_none")]
85    pub slug: Option<String>,
86    /// Tags describing the content and functionality of the application.
87    #[serde(skip_serializing_if = "Option::is_none")]
88    pub tags: Option<Vec<String>>,
89    /// If the app belongs to a team, this will be a list of the
90    /// members of that team.
91    pub team: Option<Team>,
92    /// URL of the application's terms of service.
93    #[serde(skip_serializing_if = "Option::is_none")]
94    pub terms_of_service_url: Option<String>,
95    pub verify_key: String,
96}
97
98#[cfg(test)]
99mod tests {
100    use super::{Application, ApplicationFlags, Team, User};
101    use crate::{id::Id, test::image_hash};
102    use serde::{Deserialize, Serialize};
103    use serde_test::Token;
104    use static_assertions::{assert_fields, assert_impl_all};
105    use std::{fmt::Debug, hash::Hash};
106
107    assert_fields!(
108        Application: bot_public,
109        bot_require_code_grant,
110        cover_image,
111        custom_install_url,
112        description,
113        guild_id,
114        flags,
115        icon,
116        id,
117        install_params,
118        name,
119        owner,
120        primary_sku_id,
121        privacy_policy_url,
122        rpc_origins,
123        slug,
124        tags,
125        team,
126        terms_of_service_url,
127        verify_key
128    );
129
130    assert_impl_all!(
131        Application: Clone,
132        Debug,
133        Deserialize<'static>,
134        Eq,
135        Hash,
136        PartialEq,
137        Serialize
138    );
139
140    #[allow(clippy::too_many_lines)]
141    #[test]
142    fn current_application_info() {
143        let value = Application {
144            approximate_guild_count: Some(2),
145            approximate_user_install_count: Some(5),
146            bot: None,
147            bot_public: true,
148            bot_require_code_grant: false,
149            cover_image: Some(image_hash::COVER),
150            custom_install_url: None,
151            description: "a pretty cool application".to_owned(),
152            flags: Some(ApplicationFlags::EMBEDDED),
153            guild: None,
154            guild_id: Some(Id::new(1)),
155            icon: Some(image_hash::ICON),
156            id: Id::new(2),
157            install_params: None,
158            integration_types_config: None,
159            interactions_endpoint_url: Some("https://interactions".into()),
160            name: "cool application".to_owned(),
161            owner: Some(User {
162                accent_color: None,
163                avatar: None,
164                avatar_decoration: None,
165                avatar_decoration_data: None,
166                banner: None,
167                bot: false,
168                discriminator: 1,
169                email: None,
170                flags: None,
171                global_name: Some("test".to_owned()),
172                id: Id::new(3),
173                locale: None,
174                mfa_enabled: None,
175                name: "app dev".to_owned(),
176                premium_type: None,
177                primary_guild: None,
178                public_flags: None,
179                system: None,
180                verified: None,
181            }),
182            primary_sku_id: Some(Id::new(4)),
183            privacy_policy_url: Some("https://privacypolicy".into()),
184            redirect_uris: None,
185            role_connections_verification_url: Some("https://roleconnections".into()),
186            rpc_origins: vec!["one".to_owned()],
187            slug: Some("app slug".to_owned()),
188            tags: Some(Vec::from([
189                "ponies".to_owned(),
190                "horses".to_owned(),
191                "friendship".to_owned(),
192                "magic".to_owned(),
193            ])),
194            team: Some(Team {
195                icon: None,
196                id: Id::new(5),
197                members: Vec::new(),
198                name: "team name".into(),
199                owner_user_id: Id::new(6),
200            }),
201            terms_of_service_url: Some("https://termsofservice".into()),
202            verify_key: "key".to_owned(),
203        };
204
205        serde_test::assert_tokens(
206            &value,
207            &[
208                Token::Struct {
209                    name: "Application",
210                    len: 22,
211                },
212                Token::Str("approximate_guild_count"),
213                Token::Some,
214                Token::U64(2),
215                Token::Str("approximate_user_install_count"),
216                Token::Some,
217                Token::U64(5),
218                Token::Str("bot_public"),
219                Token::Bool(true),
220                Token::Str("bot_require_code_grant"),
221                Token::Bool(false),
222                Token::Str("cover_image"),
223                Token::Some,
224                Token::Str(image_hash::COVER_INPUT),
225                Token::Str("description"),
226                Token::Str("a pretty cool application"),
227                Token::Str("flags"),
228                Token::Some,
229                Token::U64(131_072),
230                Token::Str("guild_id"),
231                Token::Some,
232                Token::NewtypeStruct { name: "Id" },
233                Token::Str("1"),
234                Token::Str("icon"),
235                Token::Some,
236                Token::Str(image_hash::ICON_INPUT),
237                Token::Str("id"),
238                Token::NewtypeStruct { name: "Id" },
239                Token::Str("2"),
240                Token::Str("interactions_endpoint_url"),
241                Token::Some,
242                Token::Str("https://interactions"),
243                Token::Str("name"),
244                Token::Str("cool application"),
245                Token::Str("owner"),
246                Token::Some,
247                Token::Struct {
248                    name: "User",
249                    len: 10,
250                },
251                Token::Str("accent_color"),
252                Token::None,
253                Token::Str("avatar"),
254                Token::None,
255                Token::Str("avatar_decoration"),
256                Token::None,
257                Token::Str("avatar_decoration_data"),
258                Token::None,
259                Token::Str("banner"),
260                Token::None,
261                Token::Str("bot"),
262                Token::Bool(false),
263                Token::Str("discriminator"),
264                Token::Str("0001"),
265                Token::Str("global_name"),
266                Token::Some,
267                Token::Str("test"),
268                Token::Str("id"),
269                Token::NewtypeStruct { name: "Id" },
270                Token::Str("3"),
271                Token::Str("username"),
272                Token::Str("app dev"),
273                Token::StructEnd,
274                Token::Str("primary_sku_id"),
275                Token::Some,
276                Token::NewtypeStruct { name: "Id" },
277                Token::Str("4"),
278                Token::Str("privacy_policy_url"),
279                Token::Some,
280                Token::Str("https://privacypolicy"),
281                Token::Str("role_connections_verification_url"),
282                Token::Some,
283                Token::Str("https://roleconnections"),
284                Token::Str("rpc_origins"),
285                Token::Seq { len: Some(1) },
286                Token::Str("one"),
287                Token::SeqEnd,
288                Token::Str("slug"),
289                Token::Some,
290                Token::Str("app slug"),
291                Token::Str("tags"),
292                Token::Some,
293                Token::Seq { len: Some(4) },
294                Token::Str("ponies"),
295                Token::Str("horses"),
296                Token::Str("friendship"),
297                Token::Str("magic"),
298                Token::SeqEnd,
299                Token::Str("team"),
300                Token::Some,
301                Token::Struct {
302                    name: "Team",
303                    len: 5,
304                },
305                Token::Str("icon"),
306                Token::None,
307                Token::Str("id"),
308                Token::NewtypeStruct { name: "Id" },
309                Token::Str("5"),
310                Token::Str("members"),
311                Token::Seq { len: Some(0) },
312                Token::SeqEnd,
313                Token::Str("name"),
314                Token::Str("team name"),
315                Token::Str("owner_user_id"),
316                Token::NewtypeStruct { name: "Id" },
317                Token::Str("6"),
318                Token::StructEnd,
319                Token::Str("terms_of_service_url"),
320                Token::Some,
321                Token::Str("https://termsofservice"),
322                Token::Str("verify_key"),
323                Token::Str("key"),
324                Token::StructEnd,
325            ],
326        );
327    }
328}