Browse Source

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.

pull/1717/head
quin lynch 4 years ago
parent
commit
ead960961b
4 changed files with 45 additions and 16 deletions
  1. +12
    -4
      src/Discord.Net.Core/Entities/Interactions/InteractionResponseType.cs
  2. +4
    -0
      src/Discord.Net.Rest/API/Common/InteractionApplicationCommandCallbackData.cs
  3. +8
    -0
      src/Discord.Net.Rest/API/Rest/CreateWebhookMessageParams.cs
  4. +21
    -12
      src/Discord.Net.WebSocket/Entities/Interaction/SocketInteraction.cs

+ 12
- 4
src/Discord.Net.Core/Entities/Interactions/InteractionResponseType.cs View File

@@ -9,6 +9,12 @@ namespace Discord
/// <summary> /// <summary>
/// The response type for an <see cref="IDiscordInteraction"/>. /// The response type for an <see cref="IDiscordInteraction"/>.
/// </summary> /// </summary>
/// <remarks>
/// After receiving an interaction, you must respond to acknowledge it. You can choose to respond with a message immediately using <see cref="ChannelMessageWithSource"/>
/// or you can choose to send a deferred response with <see cref="ACKWithSource"/>. 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 <see href="https://discord.com/developers/docs/interactions/slash-commands#interaction-response">Here</see>
/// </remarks>
public enum InteractionResponseType : byte public enum InteractionResponseType : byte
{ {
/// <summary> /// <summary>
@@ -16,24 +22,26 @@ namespace Discord
/// </summary> /// </summary>
Pong = 1, Pong = 1,


[Obsolete("This response type has been depricated by discord. Either use ChannelMessageWithSource or ACKWithSource", true)]
/// <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,


[Obsolete("This response type has been depricated by discord. Either use ChannelMessageWithSource or ACKWithSource", true)]
/// <summary> /// <summary>
/// Respond with a message, eating the user's input.
/// Respond with a message, showing the user's input.
/// </summary> /// </summary>
ChannelMessage = 3, ChannelMessage = 3,


/// <summary> /// <summary>
/// Respond with a message, showing the user's input.
/// Respond to an interaction with a message.
/// </summary> /// </summary>
ChannelMessageWithSource = 4, ChannelMessageWithSource = 4,


/// <summary> /// <summary>
/// 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.
/// </summary> /// </summary>
ACKWithSource = 5
DeferredChannelMessageWithSource = 5
} }
} }

+ 4
- 0
src/Discord.Net.Rest/API/Common/InteractionApplicationCommandCallbackData.cs View File

@@ -21,6 +21,10 @@ namespace Discord.API
[JsonProperty("allowed_mentions")] [JsonProperty("allowed_mentions")]
public Optional<AllowedMentions> AllowedMentions { get; set; } public Optional<AllowedMentions> 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<int> Flags { get; set; }

public InteractionApplicationCommandCallbackData() { } public InteractionApplicationCommandCallbackData() { }
public InteractionApplicationCommandCallbackData(string text) public InteractionApplicationCommandCallbackData(string text)
{ {


+ 8
- 0
src/Discord.Net.Rest/API/Rest/CreateWebhookMessageParams.cs View File

@@ -11,17 +11,25 @@ namespace Discord.API.Rest


[JsonProperty("nonce")] [JsonProperty("nonce")]
public Optional<string> Nonce { get; set; } public Optional<string> Nonce { get; set; }

[JsonProperty("tts")] [JsonProperty("tts")]
public Optional<bool> IsTTS { get; set; } public Optional<bool> IsTTS { get; set; }

[JsonProperty("embeds")] [JsonProperty("embeds")]
public Optional<Embed[]> Embeds { get; set; } public Optional<Embed[]> Embeds { get; set; }

[JsonProperty("username")] [JsonProperty("username")]
public Optional<string> Username { get; set; } public Optional<string> Username { get; set; }

[JsonProperty("avatar_url")] [JsonProperty("avatar_url")]
public Optional<string> AvatarUrl { get; set; } public Optional<string> AvatarUrl { get; set; }

[JsonProperty("allowed_mentions")] [JsonProperty("allowed_mentions")]
public Optional<AllowedMentions> AllowedMentions { get; set; } public Optional<AllowedMentions> AllowedMentions { get; set; }


[JsonProperty("flags")]
public Optional<int> Flags { get; set; }

public CreateWebhookMessageParams(string content) public CreateWebhookMessageParams(string content)
{ {
Content = content; Content = content;


+ 21
- 12
src/Discord.Net.WebSocket/Entities/Interaction/SocketInteraction.cs View File

@@ -104,7 +104,8 @@ namespace Discord.WebSocket
/// <param name="text">The text of the message to be sent.</param> /// <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="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="embed">A <see cref="Embed"/> to send with this response.</param>
/// <param name="Type">The type of response to this Interaction.</param>
/// <param name="type">The type of response to this Interaction.</param>
/// <param name="ephemeral"><see langword="true"/> if the response should be hidden to everyone besides the invoker of the command, otherwise <see langword="false"/>.</param>
/// <param name="allowedMentions">The allowed mentions for this response.</param> /// <param name="allowedMentions">The allowed mentions for this response.</param>
/// <param name="options">The request options for this response.</param> /// <param name="options">The request options for this response.</param>
/// <returns> /// <returns>
@@ -113,16 +114,17 @@ namespace Discord.WebSocket
/// <exception cref="ArgumentOutOfRangeException">Message content is too long, length must be less or equal to <see cref="DiscordConfig.MaxMessageSize"/>.</exception> /// <exception cref="ArgumentOutOfRangeException">Message content is too long, length must be less or equal to <see cref="DiscordConfig.MaxMessageSize"/>.</exception>
/// <exception cref="InvalidOperationException">The parameters provided were invalid or the token was invalid.</exception> /// <exception cref="InvalidOperationException">The parameters provided were invalid or the token was invalid.</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)
public async Task<IMessage> 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"); throw new InvalidOperationException($"Cannot use {Type} on a send message function");


if (!IsValidToken) if (!IsValidToken)
throw new InvalidOperationException("Interaction token is no longer valid"); throw new InvalidOperationException("Interaction token is no longer valid");


if (Discord.AlwaysAcknowledgeInteractions) 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?.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."); 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() var response = new API.InteractionResponse()
{ {
Type = Type,
Type = type,
Data = new API.InteractionApplicationCommandCallbackData(text) Data = new API.InteractionApplicationCommandCallbackData(text)
{ {
AllowedMentions = allowedMentions?.ToModel(), AllowedMentions = allowedMentions?.ToModel(),
Embeds = embed != null Embeds = embed != null
? new API.Embed[] { embed.ToModel() } ? new API.Embed[] { embed.ToModel() }
: Optional<API.Embed[]>.Unspecified, : Optional<API.Embed[]>.Unspecified,
TTS = isTTS
TTS = isTTS,
} }
}; };


if (ephemeral)
response.Data.Value.Flags = 64;

await Discord.Rest.ApiClient.CreateInteractionResponse(response, this.Id, Token, options); await Discord.Rest.ApiClient.CreateInteractionResponse(response, this.Id, Token, options);
return null; return null;
} }
@@ -168,15 +173,17 @@ namespace Discord.WebSocket
/// <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="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="embed">A <see cref="Embed"/> to send with this response.</param>
/// <param name="Type">The type of response to this Interaction.</param> /// <param name="Type">The type of response to this Interaction.</param>
/// /// <param name="ephemeral"><see langword="true"/> if the response should be hidden to everyone besides the invoker of the command, otherwise <see langword="false"/>.</param>
/// <param name="allowedMentions">The allowed mentions for this response.</param> /// <param name="allowedMentions">The allowed mentions for this response.</param>
/// <param name="options">The request options for this response.</param> /// <param name="options">The request options for this response.</param>
/// <returns> /// <returns>
/// The sent message. /// The sent message.
/// </returns> /// </returns>
public async Task<IMessage> FollowupAsync(string text = null, bool isTTS = false, Embed embed = null, InteractionResponseType Type = InteractionResponseType.ChannelMessageWithSource,
public async Task<IMessage> FollowupAsync(string text = null, bool isTTS = false, Embed embed = null, bool ephemeral = false,
InteractionResponseType Type = InteractionResponseType.ChannelMessageWithSource,
AllowedMentions allowedMentions = null, RequestOptions options = null) 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"); throw new InvalidOperationException($"Cannot use {Type} on a send message function");


if (!IsValidToken) if (!IsValidToken)
@@ -189,13 +196,15 @@ namespace Discord.WebSocket
? new API.Embed[] { embed.ToModel() } ? new API.Embed[] { embed.ToModel() }
: Optional<API.Embed[]>.Unspecified, : Optional<API.Embed[]>.Unspecified,
}; };

if (ephemeral)
args.Flags = 64;

return await InteractionHelper.SendFollowupAsync(Discord.Rest, args, Token, Channel, options); return await InteractionHelper.SendFollowupAsync(Discord.Rest, args, Token, Channel, options);
} }


/// <summary> /// <summary>
/// Acknowledges this interaction with the <see cref="InteractionResponseType.ACKWithSource"/>.
/// Acknowledges this interaction with the <see cref="InteractionResponseType.DeferredChannelMessageWithSource"/>.
/// </summary> /// </summary>
/// <returns> /// <returns>
/// A task that represents the asynchronous operation of acknowledging the interaction. /// A task that represents the asynchronous operation of acknowledging the interaction.
@@ -204,7 +213,7 @@ namespace Discord.WebSocket
{ {
var response = new API.InteractionResponse() var response = new API.InteractionResponse()
{ {
Type = InteractionResponseType.ACKWithSource,
Type = InteractionResponseType.DeferredChannelMessageWithSource,
}; };


await Discord.Rest.ApiClient.CreateInteractionResponse(response, this.Id, Token, options).ConfigureAwait(false); await Discord.Rest.ApiClient.CreateInteractionResponse(response, this.Id, Token, options).ConfigureAwait(false);


Loading…
Cancel
Save