From ead960961be070172c76c3ca5fc912f5eb884a6f Mon Sep 17 00:00:00 2001 From: quin lynch Date: Wed, 14 Apr 2021 15:30:20 -0300 Subject: [PATCH] Added flags to interaction response and webhook message. see https://discord.com/developers/docs/interactions/slash-commands#interaction-response-interactionapplicationcommandcallbackdata. Interaction response types 2 and 3 have been deprecated. --- .../Interactions/InteractionResponseType.cs | 16 ++++++--- ...teractionApplicationCommandCallbackData.cs | 4 +++ .../API/Rest/CreateWebhookMessageParams.cs | 8 +++++ .../Entities/Interaction/SocketInteraction.cs | 33 ++++++++++++------- 4 files changed, 45 insertions(+), 16 deletions(-) diff --git a/src/Discord.Net.Core/Entities/Interactions/InteractionResponseType.cs b/src/Discord.Net.Core/Entities/Interactions/InteractionResponseType.cs index 99a228358..7160be976 100644 --- a/src/Discord.Net.Core/Entities/Interactions/InteractionResponseType.cs +++ b/src/Discord.Net.Core/Entities/Interactions/InteractionResponseType.cs @@ -9,6 +9,12 @@ namespace Discord /// /// The response type for an . /// + /// + /// After receiving an interaction, you must respond to acknowledge it. You can choose to respond with a message immediately using + /// or you can choose to send a deferred response with . If choosing a deferred response, the user will see a loading state for the interaction, + /// and you'll have up to 15 minutes to edit the original deferred response using Edit Original Interaction Response. + /// You can read more about Response types Here + /// public enum InteractionResponseType : byte { /// @@ -16,24 +22,26 @@ namespace Discord /// Pong = 1, + [Obsolete("This response type has been depricated by discord. Either use ChannelMessageWithSource or ACKWithSource", true)] /// /// ACK a command without sending a message, eating the user's input. /// Acknowledge = 2, + [Obsolete("This response type has been depricated by discord. Either use ChannelMessageWithSource or ACKWithSource", true)] /// - /// Respond with a message, eating the user's input. + /// Respond with a message, showing the user's input. /// ChannelMessage = 3, /// - /// Respond with a message, showing the user's input. + /// Respond to an interaction with a message. /// ChannelMessageWithSource = 4, /// - /// ACK a command without sending a message, showing the user's input. + /// ACK an interaction and edit a response later, the user sees a loading state. /// - ACKWithSource = 5 + DeferredChannelMessageWithSource = 5 } } diff --git a/src/Discord.Net.Rest/API/Common/InteractionApplicationCommandCallbackData.cs b/src/Discord.Net.Rest/API/Common/InteractionApplicationCommandCallbackData.cs index 6637c176c..24da5bf7e 100644 --- a/src/Discord.Net.Rest/API/Common/InteractionApplicationCommandCallbackData.cs +++ b/src/Discord.Net.Rest/API/Common/InteractionApplicationCommandCallbackData.cs @@ -21,6 +21,10 @@ namespace Discord.API [JsonProperty("allowed_mentions")] public Optional AllowedMentions { get; set; } + // New flags prop. this make the response "ephemeral". see https://discord.com/developers/docs/interactions/slash-commands#interaction-response-interactionapplicationcommandcallbackdata + [JsonProperty("flags")] + public Optional Flags { get; set; } + public InteractionApplicationCommandCallbackData() { } public InteractionApplicationCommandCallbackData(string text) { diff --git a/src/Discord.Net.Rest/API/Rest/CreateWebhookMessageParams.cs b/src/Discord.Net.Rest/API/Rest/CreateWebhookMessageParams.cs index 0a4f80a3c..3e201d8eb 100644 --- a/src/Discord.Net.Rest/API/Rest/CreateWebhookMessageParams.cs +++ b/src/Discord.Net.Rest/API/Rest/CreateWebhookMessageParams.cs @@ -11,17 +11,25 @@ namespace Discord.API.Rest [JsonProperty("nonce")] public Optional Nonce { get; set; } + [JsonProperty("tts")] public Optional IsTTS { get; set; } + [JsonProperty("embeds")] public Optional Embeds { get; set; } + [JsonProperty("username")] public Optional Username { get; set; } + [JsonProperty("avatar_url")] public Optional AvatarUrl { get; set; } + [JsonProperty("allowed_mentions")] public Optional AllowedMentions { get; set; } + [JsonProperty("flags")] + public Optional Flags { get; set; } + public CreateWebhookMessageParams(string content) { Content = content; diff --git a/src/Discord.Net.WebSocket/Entities/Interaction/SocketInteraction.cs b/src/Discord.Net.WebSocket/Entities/Interaction/SocketInteraction.cs index eebb590fe..6e7efaf66 100644 --- a/src/Discord.Net.WebSocket/Entities/Interaction/SocketInteraction.cs +++ b/src/Discord.Net.WebSocket/Entities/Interaction/SocketInteraction.cs @@ -104,7 +104,8 @@ namespace Discord.WebSocket /// The text of the message to be sent. /// if the message should be read out by a text-to-speech reader, otherwise . /// A to send with this response. - /// The type of response to this Interaction. + /// The type of response to this Interaction. + /// if the response should be hidden to everyone besides the invoker of the command, otherwise . /// The allowed mentions for this response. /// The request options for this response. /// @@ -113,16 +114,17 @@ namespace Discord.WebSocket /// Message content is too long, length must be less or equal to . /// The parameters provided were invalid or the token was invalid. - public async Task RespondAsync(string text = null, bool isTTS = false, Embed embed = null, InteractionResponseType Type = InteractionResponseType.ChannelMessageWithSource, AllowedMentions allowedMentions = null, RequestOptions options = null) + public async Task RespondAsync(string text = null, bool isTTS = false, Embed embed = null, InteractionResponseType type = InteractionResponseType.ChannelMessageWithSource, + bool ephemeral = false, AllowedMentions allowedMentions = null, RequestOptions options = null) { - if (Type == InteractionResponseType.Pong) + if (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(); + return await FollowupAsync(text, isTTS, embed, ephemeral, type, allowedMentions, options); // The arguments should be passed? What was i thinking... 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."); @@ -146,17 +148,20 @@ namespace Discord.WebSocket var response = new API.InteractionResponse() { - Type = Type, + Type = type, Data = new API.InteractionApplicationCommandCallbackData(text) { AllowedMentions = allowedMentions?.ToModel(), Embeds = embed != null ? new API.Embed[] { embed.ToModel() } : Optional.Unspecified, - TTS = isTTS + TTS = isTTS, } }; + if (ephemeral) + response.Data.Value.Flags = 64; + await Discord.Rest.ApiClient.CreateInteractionResponse(response, this.Id, Token, options); return null; } @@ -168,15 +173,17 @@ namespace Discord.WebSocket /// if the message should be read out by a text-to-speech reader, otherwise . /// A to send with this response. /// The type of response to this Interaction. + /// /// if the response should be hidden to everyone besides the invoker of the command, otherwise . /// The allowed mentions for this response. /// The request options for this response. /// /// The sent message. /// - public async Task FollowupAsync(string text = null, bool isTTS = false, Embed embed = null, InteractionResponseType Type = InteractionResponseType.ChannelMessageWithSource, + public async Task FollowupAsync(string text = null, bool isTTS = false, Embed embed = null, bool ephemeral = false, + InteractionResponseType Type = InteractionResponseType.ChannelMessageWithSource, AllowedMentions allowedMentions = null, RequestOptions options = null) { - if (Type == InteractionResponseType.ACKWithSource || Type == InteractionResponseType.ACKWithSource || Type == InteractionResponseType.Pong) + if (Type == InteractionResponseType.DeferredChannelMessageWithSource || Type == InteractionResponseType.DeferredChannelMessageWithSource || Type == InteractionResponseType.Pong) throw new InvalidOperationException($"Cannot use {Type} on a send message function"); if (!IsValidToken) @@ -189,13 +196,15 @@ namespace Discord.WebSocket ? new API.Embed[] { embed.ToModel() } : Optional.Unspecified, }; - + + if (ephemeral) + args.Flags = 64; + return await InteractionHelper.SendFollowupAsync(Discord.Rest, args, Token, Channel, options); - } /// - /// Acknowledges this interaction with the . + /// Acknowledges this interaction with the . /// /// /// A task that represents the asynchronous operation of acknowledging the interaction. @@ -204,7 +213,7 @@ namespace Discord.WebSocket { var response = new API.InteractionResponse() { - Type = InteractionResponseType.ACKWithSource, + Type = InteractionResponseType.DeferredChannelMessageWithSource, }; await Discord.Rest.ApiClient.CreateInteractionResponse(response, this.Id, Token, options).ConfigureAwait(false);