| @@ -7,47 +7,47 @@ using System.Threading.Tasks; | |||||
| namespace Discord | namespace Discord | ||||
| { | { | ||||
| /// <summary> | /// <summary> | ||||
| /// The option type of the Slash command parameter, See <see href="https://discord.com/developers/docs/interactions/slash-commands#applicationcommandoptiontype"/> | |||||
| /// The option type of the Slash command parameter, See <see href="https://discord.com/developers/docs/interactions/slash-commands#applicationcommandoptiontype">the discord docs</see>. | |||||
| /// </summary> | /// </summary> | ||||
| public enum ApplicationCommandOptionType : byte | public enum ApplicationCommandOptionType : byte | ||||
| { | { | ||||
| /// <summary> | /// <summary> | ||||
| /// A sub command | |||||
| /// A sub command. | |||||
| /// </summary> | /// </summary> | ||||
| SubCommand = 1, | SubCommand = 1, | ||||
| /// <summary> | /// <summary> | ||||
| /// A group of sub commands | |||||
| /// A group of sub commands. | |||||
| /// </summary> | /// </summary> | ||||
| SubCommandGroup = 2, | SubCommandGroup = 2, | ||||
| /// <summary> | /// <summary> | ||||
| /// A <see langword="string"/> of text | |||||
| /// A <see langword="string"/> of text. | |||||
| /// </summary> | /// </summary> | ||||
| String = 3, | String = 3, | ||||
| /// <summary> | /// <summary> | ||||
| /// An <see langword="int"/> | |||||
| /// An <see langword="int"/>. | |||||
| /// </summary> | /// </summary> | ||||
| Integer = 4, | Integer = 4, | ||||
| /// <summary> | /// <summary> | ||||
| /// A <see langword="bool"/> | |||||
| /// A <see langword="bool"/>. | |||||
| /// </summary> | /// </summary> | ||||
| Boolean = 5, | Boolean = 5, | ||||
| /// <summary> | /// <summary> | ||||
| /// A <see cref="IGuildUser"/> | |||||
| /// A <see cref="IGuildUser"/>. | |||||
| /// </summary> | /// </summary> | ||||
| User = 6, | User = 6, | ||||
| /// <summary> | /// <summary> | ||||
| /// A <see cref="IGuildChannel"/> | |||||
| /// A <see cref="IGuildChannel"/>. | |||||
| /// </summary> | /// </summary> | ||||
| Channel = 7, | Channel = 7, | ||||
| /// <summary> | /// <summary> | ||||
| /// A <see cref="IRole"/> | |||||
| /// A <see cref="IRole"/>. | |||||
| /// </summary> | /// </summary> | ||||
| Role = 8 | Role = 8 | ||||
| } | } | ||||
| @@ -9,11 +9,21 @@ namespace Discord | |||||
| /// <summary> | /// <summary> | ||||
| /// Provides properties that are used to modify a <see cref="IApplicationCommand" /> with the specified changes. | /// Provides properties that are used to modify a <see cref="IApplicationCommand" /> with the specified changes. | ||||
| /// </summary> | /// </summary> | ||||
| /// <see cref="Ia"/> | |||||
| public class ApplicationCommandProperties | public class ApplicationCommandProperties | ||||
| { | { | ||||
| /// <summary> | |||||
| /// Gets or sets the name of this command. | |||||
| /// </summary> | |||||
| public string Name { get; set; } | public string Name { get; set; } | ||||
| /// <summary> | |||||
| /// Gets or sets the discription of this command. | |||||
| /// </summary> | |||||
| public string Description { get; set; } | public string Description { get; set; } | ||||
| /// <summary> | |||||
| /// Gets or sets the options for this command. | |||||
| /// </summary> | |||||
| public Optional<IEnumerable<IApplicationCommandOption>> Options { get; set; } | public Optional<IEnumerable<IApplicationCommandOption>> Options { get; set; } | ||||
| } | } | ||||
| } | } | ||||
| @@ -7,32 +7,37 @@ using System.Threading.Tasks; | |||||
| namespace Discord | namespace Discord | ||||
| { | { | ||||
| /// <summary> | /// <summary> | ||||
| /// The base command model that belongs to an application. see <see href="https://discord.com/developers/docs/interactions/slash-commands#applicationcommand"/> | |||||
| /// The base command model that belongs to an application. see <see href="https://discord.com/developers/docs/interactions/slash-commands#applicationcommand"/> | |||||
| /// </summary> | /// </summary> | ||||
| public interface IApplicationCommand : ISnowflakeEntity | public interface IApplicationCommand : ISnowflakeEntity | ||||
| { | { | ||||
| /// <summary> | /// <summary> | ||||
| /// Gets the unique id of the command | |||||
| /// Gets the unique id of the command. | |||||
| /// </summary> | /// </summary> | ||||
| ulong Id { get; } | ulong Id { get; } | ||||
| /// <summary> | /// <summary> | ||||
| /// Gets the unique id of the parent application | |||||
| /// Gets the unique id of the parent application. | |||||
| /// </summary> | /// </summary> | ||||
| ulong ApplicationId { get; } | ulong ApplicationId { get; } | ||||
| /// <summary> | /// <summary> | ||||
| /// The name of the command | |||||
| /// The name of the command. | |||||
| /// </summary> | /// </summary> | ||||
| string Name { get; } | string Name { get; } | ||||
| /// <summary> | /// <summary> | ||||
| /// The description of the command | |||||
| /// The description of the command. | |||||
| /// </summary> | /// </summary> | ||||
| string Description { get; } | string Description { get; } | ||||
| /// <summary> | /// <summary> | ||||
| /// Modifies this command | |||||
| /// If the option is a subcommand or subcommand group type, this nested options will be the parameters. | |||||
| /// </summary> | |||||
| IEnumerable<IApplicationCommandOption>? Options { get; } | |||||
| /// <summary> | |||||
| /// Modifies this command. | |||||
| /// </summary> | /// </summary> | ||||
| /// <param name="func">The delegate containing the properties to modify the command with.</param> | /// <param name="func">The delegate containing the properties to modify the command with.</param> | ||||
| /// <param name="options">The options to be used when sending the request.</param> | /// <param name="options">The options to be used when sending the request.</param> | ||||
| @@ -40,7 +45,5 @@ namespace Discord | |||||
| /// A task that represents the asynchronous modification operation. | /// A task that represents the asynchronous modification operation. | ||||
| /// </returns> | /// </returns> | ||||
| Task ModifyAsync(Action<ApplicationCommandProperties> func, RequestOptions options = null); | Task ModifyAsync(Action<ApplicationCommandProperties> func, RequestOptions options = null); | ||||
| IEnumerable<IApplicationCommandOption>? Options { get; } | |||||
| } | } | ||||
| } | } | ||||
| @@ -7,22 +7,22 @@ using System.Threading.Tasks; | |||||
| namespace Discord | namespace Discord | ||||
| { | { | ||||
| /// <summary> | /// <summary> | ||||
| /// Represents data of an Interaction Command, see <see href="https://discord.com/developers/docs/interactions/slash-commands#interaction-applicationcommandinteractiondata"/> | |||||
| /// Represents data of an Interaction Command, see <see href="https://discord.com/developers/docs/interactions/slash-commands#interaction-applicationcommandinteractiondata"/> | |||||
| /// </summary> | /// </summary> | ||||
| public interface IApplicationCommandInteractionData | public interface IApplicationCommandInteractionData | ||||
| { | { | ||||
| /// <summary> | /// <summary> | ||||
| /// The snowflake id of this command | |||||
| /// The snowflake id of this command | |||||
| /// </summary> | /// </summary> | ||||
| ulong Id { get; } | ulong Id { get; } | ||||
| /// <summary> | /// <summary> | ||||
| /// The name of this command | |||||
| /// The name of this command | |||||
| /// </summary> | /// </summary> | ||||
| string Name { get; } | string Name { get; } | ||||
| /// <summary> | /// <summary> | ||||
| /// The params + values from the user | |||||
| /// The params + values from the user | |||||
| /// </summary> | /// </summary> | ||||
| IReadOnlyCollection<IApplicationCommandInteractionDataOption> Options { get; } | IReadOnlyCollection<IApplicationCommandInteractionDataOption> Options { get; } | ||||
| } | } | ||||
| @@ -7,22 +7,25 @@ using System.Threading.Tasks; | |||||
| namespace Discord | namespace Discord | ||||
| { | { | ||||
| /// <summary> | /// <summary> | ||||
| /// Represents a option group for a command, see <see href="https://discord.com/developers/docs/interactions/slash-commands#interaction-applicationcommandinteractiondataoption"/> | |||||
| /// Represents a option group for a command, see <see href="https://discord.com/developers/docs/interactions/slash-commands#interaction-applicationcommandinteractiondataoption"/> | |||||
| /// </summary> | /// </summary> | ||||
| public interface IApplicationCommandInteractionDataOption | public interface IApplicationCommandInteractionDataOption | ||||
| { | { | ||||
| /// <summary> | /// <summary> | ||||
| /// The name of the parameter | |||||
| /// The name of the parameter. | |||||
| /// </summary> | /// </summary> | ||||
| string Name { get; } | string Name { get; } | ||||
| /// <summary> | /// <summary> | ||||
| /// The value of the pair | |||||
| /// The value of the pair. | |||||
| /// <note> | |||||
| /// This objects type can be any one of the option types in <see cref="ApplicationCommandOptionType"/> | |||||
| /// </note> | |||||
| /// </summary> | /// </summary> | ||||
| ApplicationCommandOptionType? Value { get; } | |||||
| object? Value { get; } | |||||
| /// <summary> | /// <summary> | ||||
| /// Present if this option is a group or subcommand | |||||
| /// Present if this option is a group or subcommand. | |||||
| /// </summary> | /// </summary> | ||||
| IReadOnlyCollection<IApplicationCommandInteractionDataOption> Options { get; } | IReadOnlyCollection<IApplicationCommandInteractionDataOption> Options { get; } | ||||
| @@ -7,42 +7,42 @@ using System.Threading.Tasks; | |||||
| namespace Discord | namespace Discord | ||||
| { | { | ||||
| /// <summary> | /// <summary> | ||||
| /// Options for the <see cref="IApplicationCommand"/>, see <see href="https://discord.com/developers/docs/interactions/slash-commands#applicationcommandoption"/> | |||||
| /// Options for the <see cref="IApplicationCommand"/>, see <see href="https://discord.com/developers/docs/interactions/slash-commands#applicationcommandoption"/>The docs</see>. | |||||
| /// </summary> | /// </summary> | ||||
| public interface IApplicationCommandOption | public interface IApplicationCommandOption | ||||
| { | { | ||||
| /// <summary> | /// <summary> | ||||
| /// The type of this <see cref="IApplicationCommandOption"/> | |||||
| /// The type of this <see cref="IApplicationCommandOption"/>. | |||||
| /// </summary> | /// </summary> | ||||
| ApplicationCommandOptionType Type { get; } | ApplicationCommandOptionType Type { get; } | ||||
| /// <summary> | /// <summary> | ||||
| /// The name of this command option, 1-32 character name. | |||||
| /// The name of this command option, 1-32 character name. | |||||
| /// </summary> | /// </summary> | ||||
| string Name { get; } | string Name { get; } | ||||
| /// <summary> | /// <summary> | ||||
| /// The discription of this command option, 1-100 character description | |||||
| /// The discription of this command option, 1-100 character description. | |||||
| /// </summary> | /// </summary> | ||||
| string Description { get; } | string Description { get; } | ||||
| /// <summary> | /// <summary> | ||||
| /// the first required option for the user to complete--only one option can be default | |||||
| /// The first required option for the user to complete--only one option can be default. | |||||
| /// </summary> | /// </summary> | ||||
| bool? Default { get; } | bool? Default { get; } | ||||
| /// <summary> | /// <summary> | ||||
| /// if the parameter is required or optional--default <see langword="false"/> | |||||
| /// If the parameter is required or optional, default is <see langword="false"/>. | |||||
| /// </summary> | /// </summary> | ||||
| bool? Required { get; } | bool? Required { get; } | ||||
| /// <summary> | /// <summary> | ||||
| /// choices for string and int types for the user to pick from | |||||
| /// Choices for string and int types for the user to pick from. | |||||
| /// </summary> | /// </summary> | ||||
| IEnumerable<IApplicationCommandOptionChoice>? Choices { get; } | IEnumerable<IApplicationCommandOptionChoice>? Choices { get; } | ||||
| /// <summary> | /// <summary> | ||||
| /// if the option is a subcommand or subcommand group type, this nested options will be the parameters | |||||
| /// if the option is a subcommand or subcommand group type, this nested options will be the parameters. | |||||
| /// </summary> | /// </summary> | ||||
| IEnumerable<IApplicationCommandOption>? Options { get; } | IEnumerable<IApplicationCommandOption>? Options { get; } | ||||
| } | } | ||||
| @@ -7,17 +7,17 @@ using System.Threading.Tasks; | |||||
| namespace Discord | namespace Discord | ||||
| { | { | ||||
| /// <summary> | /// <summary> | ||||
| /// Specifies choices for command group | |||||
| /// Specifies choices for command group. | |||||
| /// </summary> | /// </summary> | ||||
| public interface IApplicationCommandOptionChoice | public interface IApplicationCommandOptionChoice | ||||
| { | { | ||||
| /// <summary> | /// <summary> | ||||
| /// 1-100 character choice name | |||||
| /// 1-100 character choice name. | |||||
| /// </summary> | /// </summary> | ||||
| string Name { get; } | string Name { get; } | ||||
| /// <summary> | /// <summary> | ||||
| /// value of the choice | |||||
| /// value of the choice. | |||||
| /// </summary> | /// </summary> | ||||
| string Value { get; } | string Value { get; } | ||||
| @@ -7,48 +7,36 @@ using System.Threading.Tasks; | |||||
| namespace Discord | namespace Discord | ||||
| { | { | ||||
| /// <summary> | /// <summary> | ||||
| /// An interaction is the base "thing" that is sent when a user invokes a command, and is the same for Slash Commands and other future interaction types. | |||||
| /// see <see href="https://discord.com/developers/docs/interactions/slash-commands#interaction"/> | |||||
| /// Represents a discord interaction | |||||
| /// <para> | |||||
| /// An interaction is the base "thing" that is sent when a user invokes a command, and is the same for Slash Commands | |||||
| /// and other future interaction types. see <see href="https://discord.com/developers/docs/interactions/slash-commands#interaction"/>. | |||||
| /// </para> | |||||
| /// </summary> | /// </summary> | ||||
| public interface IDiscordInteraction : ISnowflakeEntity | public interface IDiscordInteraction : ISnowflakeEntity | ||||
| { | { | ||||
| /// <summary> | /// <summary> | ||||
| /// id of the interaction | |||||
| /// The id of the interaction. | |||||
| /// </summary> | /// </summary> | ||||
| ulong Id { get; } | ulong Id { get; } | ||||
| /// <summary> | /// <summary> | ||||
| /// The type of this <see cref="IDiscordInteraction"/> | |||||
| /// The type of this <see cref="IDiscordInteraction"/>. | |||||
| /// </summary> | /// </summary> | ||||
| InteractionType Type { get; } | InteractionType Type { get; } | ||||
| /// <summary> | /// <summary> | ||||
| /// The command data payload | |||||
| /// The command data payload. | |||||
| /// </summary> | /// </summary> | ||||
| IApplicationCommandInteractionData? Data { get; } | IApplicationCommandInteractionData? Data { get; } | ||||
| /// <summary> | /// <summary> | ||||
| /// The guild it was sent from | |||||
| /// </summary> | |||||
| ulong GuildId { get; } | |||||
| /// <summary> | |||||
| /// The channel it was sent from | |||||
| /// </summary> | |||||
| ulong ChannelId { get; } | |||||
| /// <summary> | |||||
| /// Guild member id for the invoking user | |||||
| /// </summary> | |||||
| ulong MemberId { get; } | |||||
| /// <summary> | |||||
| /// A continuation token for responding to the interaction | |||||
| /// A continuation token for responding to the interaction. | |||||
| /// </summary> | /// </summary> | ||||
| string Token { get; } | string Token { get; } | ||||
| /// <summary> | /// <summary> | ||||
| /// read-only property, always 1 | |||||
| /// read-only property, always 1. | |||||
| /// </summary> | /// </summary> | ||||
| int Version { get; } | int Version { get; } | ||||
| } | } | ||||
| @@ -7,32 +7,32 @@ using System.Threading.Tasks; | |||||
| namespace Discord | namespace Discord | ||||
| { | { | ||||
| /// <summary> | /// <summary> | ||||
| /// The response type for an <see cref="IDiscordInteraction"/> | |||||
| /// The response type for an <see cref="IDiscordInteraction"/>. | |||||
| /// </summary> | /// </summary> | ||||
| public enum InteractionResponseType : byte | public enum InteractionResponseType : byte | ||||
| { | { | ||||
| /// <summary> | /// <summary> | ||||
| /// ACK a Ping | |||||
| /// ACK a Ping. | |||||
| /// </summary> | /// </summary> | ||||
| Pong = 1, | Pong = 1, | ||||
| /// <summary> | /// <summary> | ||||
| /// ACK a command without sending a message, eating the user's input | |||||
| /// ACK a command without sending a message, eating the user's input. | |||||
| /// </summary> | /// </summary> | ||||
| Acknowledge = 2, | Acknowledge = 2, | ||||
| /// <summary> | /// <summary> | ||||
| /// Respond with a message, eating the user's input | |||||
| /// Respond with a message, eating the user's input. | |||||
| /// </summary> | /// </summary> | ||||
| ChannelMessage = 3, | ChannelMessage = 3, | ||||
| /// <summary> | /// <summary> | ||||
| /// respond with a message, showing the user's input | |||||
| /// Respond with a message, showing the user's input. | |||||
| /// </summary> | /// </summary> | ||||
| ChannelMessageWithSource = 4, | ChannelMessageWithSource = 4, | ||||
| /// <summary> | /// <summary> | ||||
| /// ACK a command without sending a message, showing the user's input | |||||
| /// ACK a command without sending a message, showing the user's input. | |||||
| /// </summary> | /// </summary> | ||||
| ACKWithSource = 5 | ACKWithSource = 5 | ||||
| } | } | ||||
| @@ -7,17 +7,17 @@ using System.Threading.Tasks; | |||||
| namespace Discord | namespace Discord | ||||
| { | { | ||||
| /// <summary> | /// <summary> | ||||
| /// Represents a type of Interaction from discord. | |||||
| /// Represents a type of Interaction from discord. | |||||
| /// </summary> | /// </summary> | ||||
| public enum InteractionType : byte | public enum InteractionType : byte | ||||
| { | { | ||||
| /// <summary> | /// <summary> | ||||
| /// A ping from discord | |||||
| /// A ping from discord. | |||||
| /// </summary> | /// </summary> | ||||
| Ping = 1, | Ping = 1, | ||||
| /// <summary> | /// <summary> | ||||
| /// An <see cref="IApplicationCommand"/> sent from discord | |||||
| /// An <see cref="IApplicationCommand"/> sent from discord. | |||||
| /// </summary> | /// </summary> | ||||
| ApplicationCommand = 2 | ApplicationCommand = 2 | ||||
| } | } | ||||
| @@ -64,5 +64,12 @@ namespace Discord | |||||
| /// Only available in API v8. | /// Only available in API v8. | ||||
| /// </remarks> | /// </remarks> | ||||
| Reply = 19, | Reply = 19, | ||||
| /// <summary> | |||||
| /// The message is an Application Command | |||||
| /// </summary> | |||||
| /// <remarks> | |||||
| /// Only available in API v8 | |||||
| /// </remarks> | |||||
| ApplicationCommand = 20 | |||||
| } | } | ||||
| } | } | ||||
| @@ -13,7 +13,7 @@ namespace Discord.API | |||||
| public string Name { get; set; } | public string Name { get; set; } | ||||
| [JsonProperty("value")] | [JsonProperty("value")] | ||||
| public Optional<ApplicationCommandOptionType> Value { get; set; } | |||||
| public Optional<object> Value { get; set; } | |||||
| [JsonProperty("options")] | [JsonProperty("options")] | ||||
| public Optional<IEnumerable<ApplicationCommandInteractionDataOption>> Options { get; set; } | public Optional<IEnumerable<ApplicationCommandInteractionDataOption>> Options { get; set; } | ||||
| @@ -13,12 +13,19 @@ namespace Discord.API | |||||
| public Optional<bool> TTS { get; set; } | public Optional<bool> TTS { get; set; } | ||||
| [JsonProperty("content")] | [JsonProperty("content")] | ||||
| public string Content { get; set; } | |||||
| public Optional<string> Content { get; set; } | |||||
| [JsonProperty("embeds")] | [JsonProperty("embeds")] | ||||
| public Optional<Embed[]> Embeds { get; set; } | public Optional<Embed[]> Embeds { get; set; } | ||||
| [JsonProperty("allowed_mentions")] | [JsonProperty("allowed_mentions")] | ||||
| public Optional<AllowedMentions> AllowedMentions { get; set; } | public Optional<AllowedMentions> AllowedMentions { get; set; } | ||||
| public InteractionApplicationCommandCallbackData() { } | |||||
| public InteractionApplicationCommandCallbackData(string text) | |||||
| { | |||||
| this.Content = text; | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| @@ -787,13 +787,7 @@ namespace Discord.API | |||||
| //Interactions | //Interactions | ||||
| public async Task<ApplicationCommand[]> GetGlobalApplicationCommandsAsync(RequestOptions options = null) | public async Task<ApplicationCommand[]> GetGlobalApplicationCommandsAsync(RequestOptions options = null) | ||||
| { | |||||
| try | |||||
| { | |||||
| return await SendAsync<ApplicationCommand[]>("GET", $"applications/{this.CurrentUserId}/commands", options: options).ConfigureAwait(false); | |||||
| } | |||||
| catch (HttpException ex) { return null; } | |||||
| } | |||||
| => await SendAsync<ApplicationCommand[]>("GET", $"applications/{this.CurrentUserId}/commands", options: options).ConfigureAwait(false); | |||||
| public async Task<ApplicationCommand> CreateGlobalApplicationCommandAsync(ApplicationCommandParams command, RequestOptions options = null) | public async Task<ApplicationCommand> CreateGlobalApplicationCommandAsync(ApplicationCommandParams command, RequestOptions options = null) | ||||
| { | { | ||||
| @@ -844,21 +838,53 @@ namespace Discord.API | |||||
| => await SendAsync<ApplicationCommand>("DELETE", $"applications/{this.CurrentUserId}/guilds/{guildId}/commands/{commandId}", options: options).ConfigureAwait(false); | => await SendAsync<ApplicationCommand>("DELETE", $"applications/{this.CurrentUserId}/guilds/{guildId}/commands/{commandId}", options: options).ConfigureAwait(false); | ||||
| //Interaction Responses | //Interaction Responses | ||||
| public async Task CreateInteractionResponse(InteractionResponse response, string interactionId, string interactionToken, RequestOptions options = null) | |||||
| public async Task CreateInteractionResponse(InteractionResponse response, ulong interactionId, string interactionToken, RequestOptions options = null) | |||||
| { | { | ||||
| if(response.Data.IsSpecified) | |||||
| Preconditions.AtMost(response.Data.Value.Content.Length, 2000, nameof(response.Data.Value.Content)); | |||||
| await SendJsonAsync("POST", $"/interactions/{interactionId}/{interactionToken}/callback", response, options: options); | |||||
| if(response.Data.IsSpecified && response.Data.Value.Content.IsSpecified) | |||||
| Preconditions.AtMost(response.Data.Value.Content.Value.Length, 2000, nameof(response.Data.Value.Content)); | |||||
| options = RequestOptions.CreateOrClone(options); | |||||
| await SendJsonAsync("POST", () => $"interactions/{interactionId}/{interactionToken}/callback", response, new BucketIds(), options: options); | |||||
| } | } | ||||
| public async Task ModifyInteractionResponse(ModifyInteractionResponseParams args, string interactionToken, RequestOptions options = null) | public async Task ModifyInteractionResponse(ModifyInteractionResponseParams args, string interactionToken, RequestOptions options = null) | ||||
| => await SendJsonAsync("POST", $"/webhooks/{this.CurrentUserId}/{interactionToken}/messages/@original", args, options: options); | |||||
| => await SendJsonAsync("POST", $"webhooks/{this.CurrentUserId}/{interactionToken}/messages/@original", args, options: options); | |||||
| public async Task DeleteInteractionResponse(string interactionToken, RequestOptions options = null) | public async Task DeleteInteractionResponse(string interactionToken, RequestOptions options = null) | ||||
| => await SendAsync("DELETE", $"/webhooks/{this.CurrentUserId}/{interactionToken}/messages/@original", options: options); | |||||
| => await SendAsync("DELETE", $"webhooks/{this.CurrentUserId}/{interactionToken}/messages/@original", options: options); | |||||
| public async Task CreateInteractionFollowupMessage() | |||||
| public async Task<Message> CreateInteractionFollowupMessage(CreateWebhookMessageParams args, string token, RequestOptions options = null) | |||||
| { | { | ||||
| if (!args.Embeds.IsSpecified || args.Embeds.Value == null || args.Embeds.Value.Length == 0) | |||||
| Preconditions.NotNullOrEmpty(args.Content, nameof(args.Content)); | |||||
| if (args.Content?.Length > DiscordConfig.MaxMessageSize) | |||||
| throw new ArgumentException(message: $"Message content is too long, length must be less or equal to {DiscordConfig.MaxMessageSize}.", paramName: nameof(args.Content)); | |||||
| options = RequestOptions.CreateOrClone(options); | |||||
| return await SendJsonAsync<Message>("POST", $"webhooks/{CurrentUserId}/{token}?wait=true", args, options: options).ConfigureAwait(false); | |||||
| } | |||||
| public async Task<Message> ModifyInteractionFollowupMessage(CreateWebhookMessageParams args, ulong id, string token, RequestOptions options = null) | |||||
| { | |||||
| Preconditions.NotNull(args, nameof(args)); | |||||
| Preconditions.NotEqual(id, 0, nameof(id)); | |||||
| if (args.Content?.Length > DiscordConfig.MaxMessageSize) | |||||
| throw new ArgumentException(message: $"Message content is too long, length must be less or equal to {DiscordConfig.MaxMessageSize}.", paramName: nameof(args.Content)); | |||||
| options = RequestOptions.CreateOrClone(options); | |||||
| return await SendJsonAsync<Message>("PATCH", $"webhooks/{CurrentUserId}/{token}/messages/{id}", args, options: options).ConfigureAwait(false); | |||||
| } | |||||
| public async Task DeleteInteractionFollowupMessage(ulong id, string token, RequestOptions options = null) | |||||
| { | |||||
| Preconditions.NotEqual(id, 0, nameof(id)); | |||||
| options = RequestOptions.CreateOrClone(options); | |||||
| await SendAsync("DELETE", $"webhooks/{CurrentUserId}/{token}/messages/{id}", options: options).ConfigureAwait(false); | |||||
| } | } | ||||
| //Guilds | //Guilds | ||||
| @@ -1,33 +0,0 @@ | |||||
| using System; | |||||
| using System.Collections.Generic; | |||||
| using System.Linq; | |||||
| using System.Text; | |||||
| using System.Threading.Tasks; | |||||
| using Model = Discord.API.ApplicationCommand; | |||||
| namespace Discord.Rest | |||||
| { | |||||
| internal static class ApplicationCommandHelper | |||||
| { | |||||
| public static async Task<Model> ModifyAsync(IApplicationCommand command, BaseDiscordClient client, | |||||
| Action<ApplicationCommandProperties> func, RequestOptions options) | |||||
| { | |||||
| if (func == null) | |||||
| throw new ArgumentNullException(nameof(func)); | |||||
| var args = new ApplicationCommandProperties(); | |||||
| func(args); | |||||
| var apiArgs = new Discord.API.Rest.ApplicationCommandParams() | |||||
| { | |||||
| Description = args.Description, | |||||
| Name = args.Name, | |||||
| Options = args.Options.IsSpecified | |||||
| ? args.Options.Value.Select(x => new API.ApplicationCommandOption(x)).ToArray() | |||||
| : Optional<API.ApplicationCommandOption[]>.Unspecified, | |||||
| }; | |||||
| return await client.ApiClient.ModifyGlobalApplicationCommandAsync(apiArgs, command.Id, options); | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,21 @@ | |||||
| using Discord.API; | |||||
| using System; | |||||
| using System.Collections.Generic; | |||||
| using System.Linq; | |||||
| using System.Text; | |||||
| using System.Threading.Tasks; | |||||
| namespace Discord.Rest | |||||
| { | |||||
| internal static class InteractionHelper | |||||
| { | |||||
| internal static async Task<RestUserMessage> SendFollowupAsync(BaseDiscordClient client, API.Rest.CreateWebhookMessageParams args, | |||||
| string token, IMessageChannel channel, RequestOptions options = null) | |||||
| { | |||||
| var model = await client.ApiClient.CreateInteractionFollowupMessage(args, token, options); | |||||
| var entity = RestUserMessage.Create(client, channel, client.CurrentUser, model); | |||||
| return entity; | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -23,7 +23,7 @@ namespace Discord.WebSocket | |||||
| /// <code language="cs" region="ChannelCreated" | /// <code language="cs" region="ChannelCreated" | ||||
| /// source="..\Discord.Net.Examples\WebSocket\BaseSocketClient.Events.Examples.cs"/> | /// source="..\Discord.Net.Examples\WebSocket\BaseSocketClient.Events.Examples.cs"/> | ||||
| /// </example> | /// </example> | ||||
| public event Func<SocketChannel, Task> ChannelCreated | |||||
| public event Func<SocketChannel, Task> ChannelCreated | |||||
| { | { | ||||
| add { _channelCreatedEvent.Add(value); } | add { _channelCreatedEvent.Add(value); } | ||||
| remove { _channelCreatedEvent.Remove(value); } | remove { _channelCreatedEvent.Remove(value); } | ||||
| @@ -70,7 +70,7 @@ namespace Discord.WebSocket | |||||
| public event Func<SocketChannel, SocketChannel, Task> ChannelUpdated { | public event Func<SocketChannel, SocketChannel, Task> ChannelUpdated { | ||||
| add { _channelUpdatedEvent.Add(value); } | add { _channelUpdatedEvent.Add(value); } | ||||
| remove { _channelUpdatedEvent.Remove(value); } | remove { _channelUpdatedEvent.Remove(value); } | ||||
| } | |||||
| } | |||||
| internal readonly AsyncEvent<Func<SocketChannel, SocketChannel, Task>> _channelUpdatedEvent = new AsyncEvent<Func<SocketChannel, SocketChannel, Task>>(); | internal readonly AsyncEvent<Func<SocketChannel, SocketChannel, Task>> _channelUpdatedEvent = new AsyncEvent<Func<SocketChannel, SocketChannel, Task>>(); | ||||
| //Messages | //Messages | ||||
| @@ -351,7 +351,7 @@ namespace Discord.WebSocket | |||||
| add { _guildMemberUpdatedEvent.Add(value); } | add { _guildMemberUpdatedEvent.Add(value); } | ||||
| remove { _guildMemberUpdatedEvent.Remove(value); } | remove { _guildMemberUpdatedEvent.Remove(value); } | ||||
| } | } | ||||
| internal readonly AsyncEvent<Func<SocketGuildUser, SocketGuildUser, Task>> _guildMemberUpdatedEvent = new AsyncEvent<Func<SocketGuildUser, SocketGuildUser, Task>>(); | |||||
| internal readonly AsyncEvent<Func<SocketGuildUser, SocketGuildUser, Task>> _guildMemberUpdatedEvent = new AsyncEvent<Func<SocketGuildUser, SocketGuildUser, Task>>(); | |||||
| /// <summary> Fired when a user joins, leaves, or moves voice channels. </summary> | /// <summary> Fired when a user joins, leaves, or moves voice channels. </summary> | ||||
| public event Func<SocketUser, SocketVoiceState, SocketVoiceState, Task> UserVoiceStateUpdated { | public event Func<SocketUser, SocketVoiceState, SocketVoiceState, Task> UserVoiceStateUpdated { | ||||
| add { _userVoiceStateUpdatedEvent.Add(value); } | add { _userVoiceStateUpdatedEvent.Add(value); } | ||||
| @@ -361,7 +361,7 @@ namespace Discord.WebSocket | |||||
| /// <summary> Fired when the bot connects to a Discord voice server. </summary> | /// <summary> Fired when the bot connects to a Discord voice server. </summary> | ||||
| public event Func<SocketVoiceServer, Task> VoiceServerUpdated | public event Func<SocketVoiceServer, Task> VoiceServerUpdated | ||||
| { | { | ||||
| add { _voiceServerUpdatedEvent.Add(value); } | |||||
| add { _voiceServerUpdatedEvent.Add(value); } | |||||
| remove { _voiceServerUpdatedEvent.Remove(value); } | remove { _voiceServerUpdatedEvent.Remove(value); } | ||||
| } | } | ||||
| internal readonly AsyncEvent<Func<SocketVoiceServer, Task>> _voiceServerUpdatedEvent = new AsyncEvent<Func<SocketVoiceServer, Task>>(); | internal readonly AsyncEvent<Func<SocketVoiceServer, Task>> _voiceServerUpdatedEvent = new AsyncEvent<Func<SocketVoiceServer, Task>>(); | ||||
| @@ -431,5 +431,26 @@ namespace Discord.WebSocket | |||||
| remove { _inviteDeletedEvent.Remove(value); } | remove { _inviteDeletedEvent.Remove(value); } | ||||
| } | } | ||||
| internal readonly AsyncEvent<Func<SocketGuildChannel, string, Task>> _inviteDeletedEvent = new AsyncEvent<Func<SocketGuildChannel, string, Task>>(); | internal readonly AsyncEvent<Func<SocketGuildChannel, string, Task>> _inviteDeletedEvent = new AsyncEvent<Func<SocketGuildChannel, string, Task>>(); | ||||
| //Interactions | |||||
| /// <summary> | |||||
| /// Fired when an Interaction is created. | |||||
| /// </summary> | |||||
| /// <remarks> | |||||
| /// <para> | |||||
| /// This event is fired when an interaction is created. The event handler must return a | |||||
| /// <see cref="Task"/> and accept a <see cref="SocketInteraction"/> as its parameter. | |||||
| /// </para> | |||||
| /// <para> | |||||
| /// The interaction created will be passed into the <see cref="SocketInteraction"/> parameter. | |||||
| /// </para> | |||||
| /// </remarks> | |||||
| public event Func<SocketInteraction, Task> InteractionCreated | |||||
| { | |||||
| add { _interactionCreatedEvent.Add(value); } | |||||
| remove { _interactionCreatedEvent.Remove(value); } | |||||
| } | |||||
| internal readonly AsyncEvent<Func<SocketInteraction, Task>> _interactionCreatedEvent = new AsyncEvent<Func<SocketInteraction, Task>>(); | |||||
| } | } | ||||
| } | } | ||||
| @@ -378,6 +378,8 @@ namespace Discord.WebSocket | |||||
| client.InviteCreated += (invite) => _inviteCreatedEvent.InvokeAsync(invite); | client.InviteCreated += (invite) => _inviteCreatedEvent.InvokeAsync(invite); | ||||
| client.InviteDeleted += (channel, invite) => _inviteDeletedEvent.InvokeAsync(channel, invite); | client.InviteDeleted += (channel, invite) => _inviteDeletedEvent.InvokeAsync(channel, invite); | ||||
| client.InteractionCreated += (interaction) => _interactionCreatedEvent.InvokeAsync(interaction); | |||||
| } | } | ||||
| //IDiscordClient | //IDiscordClient | ||||
| @@ -73,6 +73,7 @@ namespace Discord.WebSocket | |||||
| internal bool AlwaysDownloadUsers { get; private set; } | internal bool AlwaysDownloadUsers { get; private set; } | ||||
| internal int? HandlerTimeout { get; private set; } | internal int? HandlerTimeout { get; private set; } | ||||
| internal bool? ExclusiveBulkDelete { get; private set; } | internal bool? ExclusiveBulkDelete { get; private set; } | ||||
| internal bool AlwaysAcknowledgeInteractions { get; private set; } | |||||
| internal new DiscordSocketApiClient ApiClient => base.ApiClient as DiscordSocketApiClient; | internal new DiscordSocketApiClient ApiClient => base.ApiClient as DiscordSocketApiClient; | ||||
| /// <inheritdoc /> | /// <inheritdoc /> | ||||
| @@ -134,6 +135,7 @@ namespace Discord.WebSocket | |||||
| UdpSocketProvider = config.UdpSocketProvider; | UdpSocketProvider = config.UdpSocketProvider; | ||||
| WebSocketProvider = config.WebSocketProvider; | WebSocketProvider = config.WebSocketProvider; | ||||
| AlwaysDownloadUsers = config.AlwaysDownloadUsers; | AlwaysDownloadUsers = config.AlwaysDownloadUsers; | ||||
| AlwaysAcknowledgeInteractions = config.AlwaysAcknowledgeInteractions; | |||||
| HandlerTimeout = config.HandlerTimeout; | HandlerTimeout = config.HandlerTimeout; | ||||
| ExclusiveBulkDelete = config.ExclusiveBulkDelete; | ExclusiveBulkDelete = config.ExclusiveBulkDelete; | ||||
| State = new ClientState(0, 0); | State = new ClientState(0, 0); | ||||
| @@ -1792,11 +1794,12 @@ namespace Discord.WebSocket | |||||
| return; | return; | ||||
| } | } | ||||
| if(data.Type == InteractionType.ApplicationCommand) | |||||
| { | |||||
| // TODO: call command | |||||
| } | |||||
| var interaction = SocketInteraction.Create(this, data); | |||||
| if (this.AlwaysAcknowledgeInteractions) | |||||
| await interaction.AcknowledgeAsync().ConfigureAwait(false); | |||||
| await TimedInvokeAsync(_interactionCreatedEvent, nameof(InteractionCreated), interaction).ConfigureAwait(false); | |||||
| } | } | ||||
| else | else | ||||
| { | { | ||||
| @@ -105,6 +105,29 @@ namespace Discord.WebSocket | |||||
| /// </remarks> | /// </remarks> | ||||
| public bool AlwaysDownloadUsers { get; set; } = false; | public bool AlwaysDownloadUsers { get; set; } = false; | ||||
| /// <summary> | |||||
| /// Gets or sets whether or not interactions are acknowledge with source. | |||||
| /// </summary> | |||||
| /// <remarks> | |||||
| /// <para> | |||||
| /// Discord interactions will not go thru in chat until the client responds to them. With this option set to | |||||
| /// <see langword="true"/> the client will automatically acknowledge the interaction with <see cref="InteractionResponseType.ACKWithSource"/>. | |||||
| /// see <see href="https://discord.com/developers/docs/interactions/slash-commands#interaction-interactionresponsetype">the docs</see> on | |||||
| /// responding to interactions for more info | |||||
| /// </para> | |||||
| /// <para> | |||||
| /// With this option set to <see langword="false"/> you will have to acknowledge the interaction with | |||||
| /// <see cref="SocketInteraction.RespondAsync(string, bool, Embed, InteractionResponseType, AllowedMentions, RequestOptions)"/>, | |||||
| /// only after the interaction is captured the origional slash command message will be visible. | |||||
| /// </para> | |||||
| /// <note> | |||||
| /// Please note that manually acknowledging the interaction with a message reply will not provide any return data. | |||||
| /// By autmatically acknowledging the interaction without sending the message will allow for follow up responses to | |||||
| /// be used, follow up responses return the message data sent. | |||||
| /// </note> | |||||
| /// </remarks> | |||||
| public bool AlwaysAcknowledgeInteractions { get; set; } = true; | |||||
| /// <summary> | /// <summary> | ||||
| /// Gets or sets the timeout for event handlers, in milliseconds, after which a warning will be logged. | /// Gets or sets the timeout for event handlers, in milliseconds, after which a warning will be logged. | ||||
| /// Setting this property to <c>null</c>disables this check. | /// Setting this property to <c>null</c>disables this check. | ||||
| @@ -1,3 +1,4 @@ | |||||
| using Discord.Rest; | |||||
| using System; | using System; | ||||
| using System.Collections.Generic; | using System.Collections.Generic; | ||||
| using System.Linq; | using System.Linq; | ||||
| @@ -5,28 +6,63 @@ using System.Text; | |||||
| using System.Threading.Tasks; | using System.Threading.Tasks; | ||||
| using Model = Discord.API.Gateway.InteractionCreated; | using Model = Discord.API.Gateway.InteractionCreated; | ||||
| namespace Discord.WebSocket.Entities.Interaction | |||||
| namespace Discord.WebSocket | |||||
| { | { | ||||
| /// <summary> | |||||
| /// Represents an Interaction recieved over the gateway | |||||
| /// </summary> | |||||
| public class SocketInteraction : SocketEntity<ulong>, IDiscordInteraction | public class SocketInteraction : SocketEntity<ulong>, IDiscordInteraction | ||||
| { | { | ||||
| /// <summary> | |||||
| /// The <see cref="SocketGuild"/> this interaction was used in | |||||
| /// </summary> | |||||
| public SocketGuild Guild | public SocketGuild Guild | ||||
| => Discord.GetGuild(GuildId); | => Discord.GetGuild(GuildId); | ||||
| /// <summary> | |||||
| /// The <see cref="SocketTextChannel"/> this interaction was used in | |||||
| /// </summary> | |||||
| public SocketTextChannel Channel | public SocketTextChannel Channel | ||||
| => Guild.GetTextChannel(ChannelId); | => Guild.GetTextChannel(ChannelId); | ||||
| /// <summary> | |||||
| /// The <see cref="SocketGuildUser"/> who triggered this interaction | |||||
| /// </summary> | |||||
| public SocketGuildUser Member | public SocketGuildUser Member | ||||
| => Guild.GetUser(MemberId); | => Guild.GetUser(MemberId); | ||||
| /// <summary> | |||||
| /// The type of this interaction | |||||
| /// </summary> | |||||
| public InteractionType Type { get; private set; } | public InteractionType Type { get; private set; } | ||||
| /// <summary> | |||||
| /// The data associated with this interaction | |||||
| /// </summary> | |||||
| public IApplicationCommandInteractionData Data { get; private set; } | public IApplicationCommandInteractionData Data { get; private set; } | ||||
| /// <summary> | |||||
| /// The token used to respond to this interaction | |||||
| /// </summary> | |||||
| public string Token { get; private set; } | public string Token { get; private set; } | ||||
| /// <summary> | |||||
| /// The version of this interaction | |||||
| /// </summary> | |||||
| public int Version { get; private set; } | public int Version { get; private set; } | ||||
| public DateTimeOffset CreatedAt { get; } | public DateTimeOffset CreatedAt { get; } | ||||
| public ulong GuildId { get; private set; } | |||||
| public ulong ChannelId { get; private set; } | |||||
| public ulong MemberId { get; private set; } | |||||
| /// <summary> | |||||
| /// <see langword="true"/> if the token is valid for replying to, otherwise <see langword="false"/> | |||||
| /// </summary> | |||||
| public bool IsValidToken | |||||
| => CheckToken(); | |||||
| private ulong GuildId { get; set; } | |||||
| private ulong ChannelId { get; set; } | |||||
| private ulong MemberId { get; set; } | |||||
| internal SocketInteraction(DiscordSocketClient client, ulong id) | internal SocketInteraction(DiscordSocketClient client, ulong id) | ||||
| : base(client, id) | : base(client, id) | ||||
| { | { | ||||
| @@ -52,6 +88,125 @@ namespace Discord.WebSocket.Entities.Interaction | |||||
| this.MemberId = model.Member.User.Id; | this.MemberId = model.Member.User.Id; | ||||
| this.Type = model.Type; | this.Type = model.Type; | ||||
| } | } | ||||
| private bool CheckToken() | |||||
| { | |||||
| // Tokens last for 15 minutes according to https://discord.com/developers/docs/interactions/slash-commands#responding-to-an-interaction | |||||
| return (DateTime.UtcNow - this.CreatedAt.UtcDateTime).TotalMinutes >= 15d; | |||||
| } | |||||
| /// <summary> | |||||
| /// Responds to an Interaction, eating its input | |||||
| /// <para> | |||||
| /// If you have <see cref="DiscordSocketConfig.AlwaysAcknowledgeInteractions"/> set to <see langword="true"/>, this method | |||||
| /// will be obsolete and will use <see cref="FollowupAsync(string, bool, Embed, InteractionResponseType, AllowedMentions, RequestOptions)"/> | |||||
| /// </para> | |||||
| /// </summary> | |||||
| /// <param name="text">The text of the message to be sent</param> | |||||
| /// <param name="isTTS"><see langword="true"/> if the message should be read out by a text-to-speech reader, otherwise <see langword="false"/></param> | |||||
| /// <param name="embed">A <see cref="Embed"/> to send with this response</param> | |||||
| /// <param name="Type">The type of response to this Interaction</param> | |||||
| /// <param name="allowedMentions">The allowed mentions for this response</param> | |||||
| /// <param name="options">The request options for this response</param> | |||||
| /// <returns> | |||||
| /// The <see cref="IMessage"/> sent as the response. If this is the first acknowledgement, it will return null; | |||||
| /// </returns> | |||||
| /// <exception cref="ArgumentOutOfRangeException">Message content is too long, length must be less or equal to <see cref="DiscordConfig.MaxMessageSize"/>.</exception> | |||||
| public async Task<IMessage> RespondAsync(string text = null, bool isTTS = false, Embed embed = null, InteractionResponseType Type = InteractionResponseType.ChannelMessageWithSource, AllowedMentions allowedMentions = null, RequestOptions options = null) | |||||
| { | |||||
| if (Type == InteractionResponseType.ACKWithSource || Type == InteractionResponseType.ACKWithSource || Type == InteractionResponseType.Pong) | |||||
| throw new InvalidOperationException($"Cannot use {Type} on a send message function"); | |||||
| if (!IsValidToken) | |||||
| throw new InvalidOperationException("Interaction token is no longer valid"); | |||||
| if (Discord.AlwaysAcknowledgeInteractions) | |||||
| return await FollowupAsync(); | |||||
| Preconditions.AtMost(allowedMentions?.RoleIds?.Count ?? 0, 100, nameof(allowedMentions.RoleIds), "A max of 100 role Ids are allowed."); | |||||
| Preconditions.AtMost(allowedMentions?.UserIds?.Count ?? 0, 100, nameof(allowedMentions.UserIds), "A max of 100 user Ids are allowed."); | |||||
| // check that user flag and user Id list are exclusive, same with role flag and role Id list | |||||
| if (allowedMentions != null && allowedMentions.AllowedTypes.HasValue) | |||||
| { | |||||
| if (allowedMentions.AllowedTypes.Value.HasFlag(AllowedMentionTypes.Users) && | |||||
| allowedMentions.UserIds != null && allowedMentions.UserIds.Count > 0) | |||||
| { | |||||
| throw new ArgumentException("The Users flag is mutually exclusive with the list of User Ids.", nameof(allowedMentions)); | |||||
| } | |||||
| if (allowedMentions.AllowedTypes.Value.HasFlag(AllowedMentionTypes.Roles) && | |||||
| allowedMentions.RoleIds != null && allowedMentions.RoleIds.Count > 0) | |||||
| { | |||||
| throw new ArgumentException("The Roles flag is mutually exclusive with the list of Role Ids.", nameof(allowedMentions)); | |||||
| } | |||||
| } | |||||
| var response = new API.InteractionResponse() | |||||
| { | |||||
| Type = Type, | |||||
| Data = new API.InteractionApplicationCommandCallbackData(text) | |||||
| { | |||||
| AllowedMentions = allowedMentions?.ToModel(), | |||||
| Embeds = embed != null | |||||
| ? new API.Embed[] { embed.ToModel() } | |||||
| : Optional<API.Embed[]>.Unspecified, | |||||
| TTS = isTTS | |||||
| } | |||||
| }; | |||||
| await Discord.Rest.ApiClient.CreateInteractionResponse(response, this.Id, Token, options); | |||||
| return null; | |||||
| } | |||||
| /// <summary> | |||||
| /// Sends a followup message for this interaction | |||||
| /// </summary> | |||||
| /// <param name="text">The text of the message to be sent</param> | |||||
| /// <param name="isTTS"><see langword="true"/> if the message should be read out by a text-to-speech reader, otherwise <see langword="false"/></param> | |||||
| /// <param name="embed">A <see cref="Embed"/> to send with this response</param> | |||||
| /// <param name="Type">The type of response to this Interaction</param> | |||||
| /// <param name="allowedMentions">The allowed mentions for this response</param> | |||||
| /// <param name="options">The request options for this response</param> | |||||
| /// <returns> | |||||
| /// The sent message | |||||
| /// </returns> | |||||
| public async Task<IMessage> FollowupAsync(string text = null, bool isTTS = false, Embed embed = null, InteractionResponseType Type = InteractionResponseType.ChannelMessageWithSource, | |||||
| AllowedMentions allowedMentions = null, RequestOptions options = null) | |||||
| { | |||||
| if (Type == InteractionResponseType.ACKWithSource || Type == InteractionResponseType.ACKWithSource || Type == InteractionResponseType.Pong) | |||||
| throw new InvalidOperationException($"Cannot use {Type} on a send message function"); | |||||
| if (!IsValidToken) | |||||
| throw new InvalidOperationException("Interaction token is no longer valid"); | |||||
| var args = new API.Rest.CreateWebhookMessageParams(text) | |||||
| { | |||||
| IsTTS = isTTS, | |||||
| Embeds = embed != null | |||||
| ? new API.Embed[] { embed.ToModel() } | |||||
| : Optional<API.Embed[]>.Unspecified, | |||||
| }; | |||||
| return await InteractionHelper.SendFollowupAsync(Discord.Rest, args, Token, Channel, options); | |||||
| } | |||||
| /// <summary> | |||||
| /// Acknowledges this interaction with the <see cref="InteractionResponseType.ACKWithSource"/> | |||||
| /// </summary> | |||||
| /// <returns> | |||||
| /// A task that represents the asynchronous operation of acknowledging the interaction | |||||
| /// </returns> | |||||
| public async Task AcknowledgeAsync(RequestOptions options = null) | |||||
| { | |||||
| var response = new API.InteractionResponse() | |||||
| { | |||||
| Type = InteractionResponseType.ACKWithSource, | |||||
| }; | |||||
| await Discord.Rest.ApiClient.CreateInteractionResponse(response, this.Id, Token, options).ConfigureAwait(false); | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| @@ -6,7 +6,7 @@ using System.Text; | |||||
| using System.Threading.Tasks; | using System.Threading.Tasks; | ||||
| using Model = Discord.API.ApplicationCommandInteractionData; | using Model = Discord.API.ApplicationCommandInteractionData; | ||||
| namespace Discord.WebSocket.Entities.Interaction | |||||
| namespace Discord.WebSocket | |||||
| { | { | ||||
| public class SocketInteractionData : SocketEntity<ulong>, IApplicationCommandInteractionData | public class SocketInteractionData : SocketEntity<ulong>, IApplicationCommandInteractionData | ||||
| { | { | ||||
| @@ -6,12 +6,12 @@ using System.Text; | |||||
| using System.Threading.Tasks; | using System.Threading.Tasks; | ||||
| using Model = Discord.API.ApplicationCommandInteractionDataOption; | using Model = Discord.API.ApplicationCommandInteractionDataOption; | ||||
| namespace Discord.WebSocket.Entities.Interaction | |||||
| namespace Discord.WebSocket | |||||
| { | { | ||||
| public class SocketInteractionDataOption : IApplicationCommandInteractionDataOption | public class SocketInteractionDataOption : IApplicationCommandInteractionDataOption | ||||
| { | { | ||||
| public string Name { get; private set; } | public string Name { get; private set; } | ||||
| public ApplicationCommandOptionType? Value { get; private set; } | |||||
| public object? Value { get; private set; } | |||||
| public IReadOnlyCollection<IApplicationCommandInteractionDataOption> Options { get; private set; } | public IReadOnlyCollection<IApplicationCommandInteractionDataOption> Options { get; private set; } | ||||