[Feature] Premium subscriptions (#2781)

* what a big commit lel, add app sub enums

* work

* ah yup lol

* `?`

* events 1

* typo

* `list` => `get` | remaining events

* add `RespondWithPremiumRequiredAsync` to interaction module base
This commit is contained in:
Mihail Gribkov
2023-09-30 16:39:28 +03:00
committed by GitHub
parent 8baf913c9d
commit 7723f61072
28 changed files with 819 additions and 21 deletions

View File

@@ -237,5 +237,10 @@ namespace Discord
/// Returns the max amount of tags applied to an application.
/// </summary>
public const int MaxApplicationTagCount = 5;
/// <summary>
/// Returns the maximum number of entitlements that can be gotten per-batch.
/// </summary>
public const int MaxEntitlementsPerBatch = 100;
}
}

View File

@@ -0,0 +1,9 @@
namespace Discord;
public enum EntitlementType
{
/// <summary>
/// The entitlement was purchased as an app subscription.
/// </summary>
ApplicationSubscription = 8
}

View File

@@ -0,0 +1,61 @@
using System;
namespace Discord;
public interface IEntitlement : ISnowflakeEntity
{
/// <summary>
/// Gets the ID of the SKU this entitlement is for.
/// </summary>
ulong SkuId { get; }
/// <summary>
/// Gets the ID of the user that is granted access to the entitlement's SKU.
/// </summary>
/// <remarks>
/// <see langword="null"/> if the entitlement is for a guild.
/// </remarks>
ulong? UserId { get; }
/// <summary>
/// Gets the ID of the guild that is granted access to the entitlement's SKU.
/// </summary>
/// <remarks>
/// <see langword="null"/> if the entitlement is for a user.
/// </remarks>
ulong? GuildId { get; }
/// <summary>
/// Gets the ID of the parent application.
/// </summary>
ulong ApplicationId { get; }
/// <summary>
/// Gets the type of the entitlement.
/// </summary>
EntitlementType Type { get; }
/// <summary>
/// Gets whether this entitlement has been consumed.
/// </summary>
/// <remarks>
/// Not applicable for App Subscriptions.
/// </remarks>
bool IsConsumed { get; }
/// <summary>
/// Gets the start date at which the entitlement is valid.
/// </summary>
/// <remarks>
/// <see langword="null"/> when using test entitlements.
/// </remarks>
DateTimeOffset? StartsAt { get; }
/// <summary>
/// Gets the end date at which the entitlement is no longer valid.
/// </summary>
/// <remarks>
/// <see langword="null"/> when using test entitlements.
/// </remarks>
DateTimeOffset? EndsAt { get; }
}

View File

@@ -0,0 +1,41 @@
using System;
namespace Discord;
public struct SKU : ISnowflakeEntity
{
/// <inheritdoc />
public ulong Id { get; }
/// <inheritdoc />
public DateTimeOffset CreatedAt => SnowflakeUtils.FromSnowflake(Id);
/// <summary>
/// Gets the type of the SKU.
/// </summary>
public SKUType Type { get; }
/// <summary>
/// Gets the ID of the parent application.
/// </summary>
public ulong ApplicationId { get; }
/// <summary>
/// Gets the customer-facing name of your premium offering.
/// </summary>
public string Name { get; }
/// <summary>
/// Gets the system-generated URL slug based on the SKU's name.
/// </summary>
public string Slug { get; }
internal SKU(ulong id, SKUType type, ulong applicationId, string name, string slug)
{
Id = id;
Type = type;
ApplicationId = applicationId;
Name = name;
Slug = slug;
}
}

View File

@@ -0,0 +1,11 @@
using System;
namespace Discord;
[Flags]
public enum SKUFlags
{
GuildSubscription = 1 << 7,
UserSubscription = 1 << 8
}

View File

@@ -0,0 +1,14 @@
namespace Discord;
public enum SKUType
{
/// <summary>
/// Represents a recurring subscription.
/// </summary>
Subscription = 5,
/// <summary>
/// System-generated group for each <see cref="SKUType.Subscription"/> SKU created.
/// </summary>
SubscriptionGroup = 6,
}

View File

@@ -0,0 +1,14 @@
namespace Discord;
public enum SubscriptionOwnerType
{
/// <summary>
/// The owner of the application subscription is a guild.
/// </summary>
Guild = 1,
/// <summary>
/// The owner of the application subscription is a user.
/// </summary>
User = 2,
}

View File

@@ -91,6 +91,11 @@ namespace Discord
/// </summary>
ulong ApplicationId { get; }
/// <summary>
/// Gets entitlements for the invoking user.
/// </summary>
IReadOnlyCollection<IEntitlement> Entitlements { get; }
/// <summary>
/// Responds to an Interaction with type <see cref="InteractionResponseType.ChannelMessageWithSource"/>.
/// </summary>
@@ -368,5 +373,12 @@ namespace Discord
/// <param name="options">The request options for this <see langword="async"/> request.</param>
/// <returns>A task that represents the asynchronous operation of responding to the interaction.</returns>
Task RespondWithModalAsync(Modal modal, RequestOptions options = null);
/// <summary>
/// Responds to the interaction with an ephemeral message the invoking user,
/// instructing them that whatever they tried to do requires the premium benefits of your app.
/// </summary>
/// <returns>A task that represents the asynchronous operation of responding to the interaction.</returns>
Task RespondWithPremiumRequiredAsync(RequestOptions options = null);
}
}

View File

@@ -47,5 +47,10 @@ namespace Discord
/// Respond by showing the user a modal.
/// </summary>
Modal = 9,
/// <summary>
/// Respond to an interaction with an upgrade button, only available for apps with monetization enabled.
/// </summary>
PremiumRequired = 10
}
}

View File

@@ -327,5 +327,27 @@ namespace Discord
/// that represents the gateway information related to the bot.
/// </returns>
Task<BotGateway> GetBotGatewayAsync(RequestOptions options = null);
/// <summary>
/// Creates a test entitlement to a given SKU for a given guild or user.
/// </summary>
Task<IEntitlement> CreateTestEntitlementAsync(ulong skuId, ulong ownerId, SubscriptionOwnerType ownerType, RequestOptions options = null);
/// <summary>
/// Deletes a currently-active test entitlement.
/// </summary>
Task DeleteTestEntitlementAsync(ulong entitlementId, RequestOptions options = null);
/// <summary>
/// Returns all entitlements for a given app, active and expired.
/// </summary>
IAsyncEnumerable<IReadOnlyCollection<IEntitlement>> GetEntitlementsAsync(int? limit = 100,
ulong? afterId = null, ulong? beforeId = null, bool excludeEnded = false, ulong? guildId = null, ulong? userId = null,
ulong[] skuIds = null, RequestOptions options = null);
/// <summary>
/// Returns all SKUs for a given application.
/// </summary>
Task<IReadOnlyCollection<SKU>> GetSKUsAsync(RequestOptions options = null);
}
}