serenity/model/monetization.rs
1#[cfg(feature = "model")]
2use crate::builder::{Builder as _, GetEntitlements};
3#[cfg(feature = "model")]
4use crate::http::{CacheHttp, Http};
5use crate::model::prelude::*;
6
7/// A premium offering that can be made available to an application's users and guilds.
8///
9/// [Discord docs](https://discord.com/developers/docs/monetization/skus#sku-object).
10#[derive(Clone, Debug, Serialize, Deserialize)]
11pub struct Sku {
12 /// The unique ID of the SKU.
13 pub id: SkuId,
14 /// The class of the SKU.
15 #[serde(rename = "type")]
16 pub kind: SkuKind,
17 /// Id of the SKU's parent application.
18 pub application_id: ApplicationId,
19 /// The customer-facing name of the premium offering.
20 pub name: String,
21 /// A system-generated URL slug based on the SKU.
22 pub slug: String,
23 /// Flags indicating the type of subscription the SKU represents.
24 pub flags: SkuFlags,
25}
26
27impl Sku {
28 /// Returns the store url for this SKU. If included in a message, will render as a rich embed.
29 /// See the [Discord docs] for details.
30 ///
31 /// [Discord docs]: https://discord.com/developers/docs/monetization/skus#linking-to-your-skus
32 #[must_use]
33 pub fn url(&self) -> String {
34 format!(
35 "https://discord.com/application-directory/{}/store/{}",
36 self.application_id, self.id
37 )
38 }
39}
40
41enum_number! {
42 /// Differentiates between SKU classes.
43 ///
44 /// [Discord docs](https://discord.com/developers/docs/monetization/skus#sku-object-sku-types).
45 #[derive(Clone, Debug, Serialize, Deserialize)]
46 #[serde(from = "u8", into = "u8")]
47 #[non_exhaustive]
48 pub enum SkuKind {
49 /// A durable one-time purchase.
50 Durable = 2,
51 /// A consumable one-time purchase.
52 Consumable = 3,
53 /// Represents a recurring subscription.
54 Subscription = 5,
55 /// A system-generated group for each SKU created of type [`SkuKind::Subscription`].
56 SubscriptionGroup = 6,
57 _ => Unknown(u8),
58 }
59}
60
61bitflags! {
62 /// Differentates between user and server subscriptions.
63 ///
64 /// [Discord docs](https://discord.com/developers/docs/monetization/skus#sku-object-sku-flags).
65 #[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
66 pub struct SkuFlags: u64 {
67 /// SKU is available for purchase.
68 const AVAILABLE = 1 << 2;
69 /// Recurring SKU that can be purchased by a user and applied to a single server. Grants
70 /// access to every user in that server.
71 const GUILD_SUBSCRIPTION = 1 << 7;
72 /// Recurring SKU purchased by a user for themselves. Grants access to the purchasing user
73 /// in every server.
74 const USER_SUBSCRIPTION = 1 << 8;
75 }
76}
77
78/// Represents that a user or guild has access to a premium offering in the application.
79///
80/// [Discord docs](https://discord.com/developers/docs/monetization/entitlements#entitlement-object-entitlement-structure).
81#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
82#[derive(Clone, Debug, Serialize, Deserialize)]
83pub struct Entitlement {
84 /// The ID of the entitlement.
85 pub id: EntitlementId,
86 /// The ID of the corresponding SKU.
87 pub sku_id: SkuId,
88 /// The ID of the parent application.
89 pub application_id: ApplicationId,
90 /// The ID of the user that is granted access to the SKU.
91 pub user_id: Option<UserId>,
92 /// The type of the entitlement.
93 #[serde(rename = "type")]
94 pub kind: EntitlementKind,
95 /// Whether the entitlement has been deleted or not. Entitlements are not deleted when they
96 /// expire.
97 pub deleted: bool,
98 /// Start date after which the entitlement is valid. Not present when using test entitlements.
99 pub starts_at: Option<Timestamp>,
100 /// End date after which the entitlement is no longer valid. Not present when using test
101 /// entitlements.
102 pub ends_at: Option<Timestamp>,
103 /// The ID of the guild that is granted access to the SKU.
104 pub guild_id: Option<GuildId>,
105 /// For consumable items, whether or not the entitlement has been consumed.
106 pub consumed: Option<bool>,
107}
108
109impl Entitlement {
110 /// Returns a link to the SKU corresponding to this entitlement. See [`Sku::url`] for details.
111 #[must_use]
112 pub fn sku_url(&self) -> String {
113 format!(
114 "https://discord.com/application-directory/{}/store/{}",
115 self.application_id, self.sku_id
116 )
117 }
118
119 /// For a one-time purchase consumable SKU (of kind [`Consumable`]), marks the entitlement as
120 /// consumed. On success, the [`consumed`] field will be set to `Some(true)`.
121 ///
122 /// # Errors
123 ///
124 /// Will fail if the corresponding SKU is not of kind [`Consumable`].
125 ///
126 /// [`Consumable`]: SkuKind::Consumable
127 /// [`consumed`]: Entitlement::consumed
128 #[cfg(feature = "model")]
129 pub async fn consume(&mut self, http: &Http) -> Result<()> {
130 http.consume_entitlement(self.id).await?;
131 self.consumed = Some(true);
132 Ok(())
133 }
134
135 /// Returns all entitlements for the current application, active and expired.
136 ///
137 /// # Errors
138 ///
139 /// May error due to an invalid response from discord, or network error.
140 #[cfg(feature = "model")]
141 pub async fn list(
142 cache_http: impl CacheHttp,
143 builder: GetEntitlements,
144 ) -> Result<Vec<Entitlement>> {
145 builder.execute(cache_http, ()).await
146 }
147}
148
149enum_number! {
150 /// Differentiates between Entitlement types.
151 ///
152 /// [Discord docs](https://discord.com/developers/docs/monetization/entitlements#entitlement-object-entitlement-types).
153 #[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
154 #[derive(Clone, Debug, Serialize, Deserialize)]
155 #[serde(from = "u8", into = "u8")]
156 #[non_exhaustive]
157 pub enum EntitlementKind {
158 /// Entitlement was purchased by a user.
159 Purchase = 1,
160 /// Entitlement for a Discord Nitro subscription.
161 PremiumSubscription = 2,
162 /// Entitlement was gifted by an app developer.
163 DeveloperGift = 3,
164 /// Entitlement was purchased by a developer in application test mode.
165 TestModePurchase = 4,
166 /// Entitlement was granted when the corresponding SKU was free.
167 FreePurchase = 5,
168 /// Entitlement was gifted by another user.
169 UserGift = 6,
170 /// Entitlement was claimed by user for free as a Nitro Subscriber.
171 PremiumPurchase = 7,
172 /// Entitlement was purchased as an app subscription.
173 ApplicationSubscription = 8,
174 _ => Unknown(u8),
175 }
176}
177
178pub enum EntitlementOwner {
179 Guild(GuildId),
180 User(UserId),
181}