feature: Add missing interaction properties (#2325)

This commit is contained in:
d4n
2022-05-25 04:12:03 -05:00
committed by GitHub
parent 2c428600b0
commit d3a693ab67
3 changed files with 94 additions and 67 deletions

View File

@@ -52,6 +52,9 @@ namespace Discord
/// <summary> /// <summary>
/// Gets the preferred locale of the invoking User. /// Gets the preferred locale of the invoking User.
/// </summary> /// </summary>
/// <remarks>
/// This property returns <see langword="null"/> if the interaction is a REST ping interaction.
/// </remarks>
string UserLocale { get; } string UserLocale { get; }
/// <summary> /// <summary>
@@ -67,6 +70,27 @@ namespace Discord
/// </summary> /// </summary>
bool IsDMInteraction { get; } bool IsDMInteraction { get; }
/// <summary>
/// Gets the ID of the channel this interaction was executed in.
/// </summary>
/// <remarks>
/// This property returns <see langword="null"/> if the interaction is a REST ping interaction.
/// </remarks>
ulong? ChannelId { get; }
/// <summary>
/// Gets the ID of the guild this interaction was executed in.
/// </summary>
/// <remarks>
/// This property returns <see langword="null"/> if the interaction was not executed in a guild.
/// </remarks>
ulong? GuildId { get; }
/// <summary>
/// Gets the ID of the application this interaction is for.
/// </summary>
ulong ApplicationId { get; }
/// <summary> /// <summary>
/// Responds to an Interaction with type <see cref="InteractionResponseType.ChannelMessageWithSource"/>. /// Responds to an Interaction with type <see cref="InteractionResponseType.ChannelMessageWithSource"/>.
/// </summary> /// </summary>

View File

@@ -1,7 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Model = Discord.API.Interaction; using Model = Discord.API.Interaction;
@@ -17,8 +16,8 @@ namespace Discord.Rest
public abstract class RestInteraction : RestEntity<ulong>, IDiscordInteraction public abstract class RestInteraction : RestEntity<ulong>, IDiscordInteraction
{ {
// Added so channel & guild methods don't need a client reference // Added so channel & guild methods don't need a client reference
private Func<RequestOptions, ulong, Task<IRestMessageChannel>> _getChannel = null; private Func<RequestOptions, ulong, Task<IRestMessageChannel>> _getChannel;
private Func<RequestOptions, ulong, Task<RestGuild>> _getGuild = null; private Func<RequestOptions, ulong, Task<RestGuild>> _getGuild;
/// <inheritdoc/> /// <inheritdoc/>
public InteractionType Type { get; private set; } public InteractionType Type { get; private set; }
@@ -56,30 +55,17 @@ namespace Discord.Rest
public bool IsValidToken public bool IsValidToken
=> InteractionHelper.CanRespondOrFollowup(this); => InteractionHelper.CanRespondOrFollowup(this);
/// <summary>
/// Gets the ID of the channel this interaction was executed in.
/// </summary>
/// <remarks>
/// <see langword="null"/> if the interaction was not executed in a guild.
/// </remarks>
public ulong? ChannelId { get; private set; } = null;
/// <summary> /// <summary>
/// Gets the channel that this interaction was executed in. /// Gets the channel that this interaction was executed in.
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// <see langword="null"/> if <see cref="DiscordRestConfig.APIOnRestInteractionCreation"/> is set to false. /// This property will be <see langword="null"/> if <see cref="DiscordRestConfig.APIOnRestInteractionCreation"/> is set to false.
/// Call <see cref="GetChannelAsync"/> to set this property and get the interaction channel. /// Call <see cref="GetChannelAsync"/> to set this property and get the interaction channel.
/// </remarks> /// </remarks>
public IRestMessageChannel Channel { get; private set; } public IRestMessageChannel Channel { get; private set; }
/// <summary> /// <inheritdoc/>
/// Gets the ID of the guild this interaction was executed in if applicable. public ulong? ChannelId { get; private set; }
/// </summary>
/// <remarks>
/// <see langword="null"/> if the interaction was not executed in a guild.
/// </remarks>
public ulong? GuildId { get; private set; } = null;
/// <summary> /// <summary>
/// Gets the guild this interaction was executed in if applicable. /// Gets the guild this interaction was executed in if applicable.
@@ -90,12 +76,18 @@ namespace Discord.Rest
/// </remarks> /// </remarks>
public RestGuild Guild { get; private set; } public RestGuild Guild { get; private set; }
/// <inheritdoc/>
public ulong? GuildId { get; private set; }
/// <inheritdoc/> /// <inheritdoc/>
public bool HasResponded { get; protected set; } public bool HasResponded { get; protected set; }
/// <inheritdoc/> /// <inheritdoc/>
public bool IsDMInteraction { get; private set; } public bool IsDMInteraction { get; private set; }
/// <inheritdoc/>
public ulong ApplicationId { get; private set; }
internal RestInteraction(BaseDiscordClient discord, ulong id) internal RestInteraction(BaseDiscordClient discord, ulong id)
: base(discord, id) : base(discord, id)
{ {
@@ -143,32 +135,41 @@ namespace Discord.Rest
internal virtual async Task UpdateAsync(DiscordRestClient discord, Model model, bool doApiCall) internal virtual async Task UpdateAsync(DiscordRestClient discord, Model model, bool doApiCall)
{ {
IsDMInteraction = !model.GuildId.IsSpecified; ChannelId = model.ChannelId.IsSpecified
? model.ChannelId.Value
: null;
GuildId = model.GuildId.IsSpecified
? model.GuildId.Value
: null;
IsDMInteraction = GuildId is null;
Data = model.Data.IsSpecified Data = model.Data.IsSpecified
? model.Data.Value ? model.Data.Value
: null; : null;
Token = model.Token; Token = model.Token;
Version = model.Version; Version = model.Version;
Type = model.Type; Type = model.Type;
ApplicationId = model.ApplicationId;
if (Guild == null && model.GuildId.IsSpecified) if (Guild is null && GuildId is not null)
{ {
GuildId = model.GuildId.Value;
if (doApiCall) if (doApiCall)
Guild = await discord.GetGuildAsync(model.GuildId.Value); Guild = await discord.GetGuildAsync(GuildId.Value);
else else
{ {
Guild = null; Guild = null;
_getGuild = new(async (opt, ul) => await discord.GetGuildAsync(ul, opt)); _getGuild = async (opt, ul) => await discord.GetGuildAsync(ul, opt);
} }
} }
if (User == null) if (User is null)
{ {
if (model.Member.IsSpecified && model.GuildId.IsSpecified) if (model.Member.IsSpecified && GuildId is not null)
{ {
User = RestGuildUser.Create(Discord, Guild, model.Member.Value, (Guild is null) ? model.GuildId.Value : null); User = RestGuildUser.Create(Discord, Guild, model.Member.Value, GuildId);
} }
else else
{ {
@@ -176,24 +177,25 @@ namespace Discord.Rest
} }
} }
if (Channel == null && model.ChannelId.IsSpecified)
if (Channel is null && ChannelId is not null)
{ {
try try
{ {
ChannelId = model.ChannelId.Value;
if (doApiCall) if (doApiCall)
Channel = (IRestMessageChannel)await discord.GetChannelAsync(model.ChannelId.Value); Channel = (IRestMessageChannel)await discord.GetChannelAsync(ChannelId.Value);
else else
{ {
_getChannel = new(async (opt, ul) => Channel = null;
_getChannel = async (opt, ul) =>
{ {
if (Guild is null) if (Guild is null)
return (IRestMessageChannel)await discord.GetChannelAsync(ul, opt); return (IRestMessageChannel)await discord.GetChannelAsync(ul, opt);
else // get a guild channel if the guild is set.
return (IRestMessageChannel)await Guild.GetChannelAsync(ul, opt);
});
Channel = null; // get a guild channel if the guild is set.
return (IRestMessageChannel)await Guild.GetChannelAsync(ul, opt);
};
} }
} }
catch (HttpException x) when (x.DiscordCode == DiscordErrorCode.MissingPermissions) { } // ignore catch (HttpException x) when (x.DiscordCode == DiscordErrorCode.MissingPermissions) { } // ignore
@@ -222,7 +224,7 @@ namespace Discord.Rest
/// Gets the channel this interaction was executed in. Will be a DM channel if the interaction was executed in DM. /// Gets the channel this interaction was executed in. Will be a DM channel if the interaction was executed in DM.
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// Calling this method succesfully will populate the <see cref="Channel"/> property. /// Calling this method successfully will populate the <see cref="Channel"/> property.
/// After this, further calls to this method will no longer call the API, and depend on the value set in <see cref="Channel"/>. /// After this, further calls to this method will no longer call the API, and depend on the value set in <see cref="Channel"/>.
/// </remarks> /// </remarks>
/// <param name="options">The request options for this <see langword="async"/> request.</param> /// <param name="options">The request options for this <see langword="async"/> request.</param>
@@ -230,20 +232,16 @@ namespace Discord.Rest
/// <exception cref="InvalidOperationException">Thrown if no channel can be received.</exception> /// <exception cref="InvalidOperationException">Thrown if no channel can be received.</exception>
public async Task<IRestMessageChannel> GetChannelAsync(RequestOptions options = null) public async Task<IRestMessageChannel> GetChannelAsync(RequestOptions options = null)
{ {
if (IsDMInteraction && Channel is null) if (Channel is not null)
return Channel;
if (IsDMInteraction)
{ {
var channel = await User.CreateDMChannelAsync(options); Channel = await User.CreateDMChannelAsync(options);
Channel = channel;
} }
else if (ChannelId is not null)
else if (Channel is null)
{ {
var channel = await _getChannel(options, ChannelId.Value); Channel = await _getChannel(options, ChannelId.Value) ?? throw new InvalidOperationException("The interaction channel was not able to be retrieved.");
if (channel is null)
throw new InvalidOperationException("The interaction channel was not able to be retrieved.");
Channel = channel;
_getChannel = null; // get rid of it, we don't need it anymore. _getChannel = null; // get rid of it, we don't need it anymore.
} }
@@ -254,20 +252,19 @@ namespace Discord.Rest
/// Gets the guild this interaction was executed in if applicable. /// Gets the guild this interaction was executed in if applicable.
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// Calling this method succesfully will populate the <see cref="Guild"/> property. /// Calling this method successfully will populate the <see cref="Guild"/> property.
/// After this, further calls to this method will no longer call the API, and depend on the value set in <see cref="Guild"/>. /// After this, further calls to this method will no longer call the API, and depend on the value set in <see cref="Guild"/>.
/// </remarks> /// </remarks>
/// <param name="options">The request options for this <see langword="async"/> request.</param> /// <param name="options">The request options for this <see langword="async"/> request.</param>
/// <returns>The guild this interaction was executed in. <see langword="null"/> if the interaction was executed inside DM.</returns> /// <returns>The guild this interaction was executed in. <see langword="null"/> if the interaction was executed inside DM.</returns>
public async Task<RestGuild> GetGuildAsync(RequestOptions options) public async Task<RestGuild> GetGuildAsync(RequestOptions options)
{ {
if (IsDMInteraction) if (GuildId is null)
return null; return null;
if (Guild is null) Guild ??= await _getGuild(options, GuildId.Value);
Guild = await _getGuild(options, GuildId.Value);
_getGuild = null; // get rid of it, we don't need it anymore. _getGuild = null; // get rid of it, we don't need it anymore.
return Guild; return Guild;
} }

View File

@@ -24,20 +24,11 @@ namespace Discord.WebSocket
/// </remarks> /// </remarks>
public ISocketMessageChannel Channel { get; private set; } public ISocketMessageChannel Channel { get; private set; }
/// <summary> /// <inheritdoc/>
/// Gets the ID of the channel this interaction was used in.
/// </summary>
/// <remarks>
/// This property is exposed in cases where the bot scope is not provided, so the channel entity cannot be retrieved.
/// <br />
/// To get the channel, you can call <see cref="GetChannelAsync(RequestOptions)"/>
/// as this method makes a request for a <see cref="RestChannel"/> if nothing was found in cache.
/// </remarks>
public ulong? ChannelId { get; private set; } public ulong? ChannelId { get; private set; }
/// <summary> /// <summary>
/// Gets the <see cref="SocketUser"/> who triggered this interaction. /// Gets the <see cref="SocketUser"/> who triggered this interaction.
/// This property will be <see langword="null"/> if the bot scope isn't used.
/// </summary> /// </summary>
public SocketUser User { get; private set; } public SocketUser User { get; private set; }
@@ -74,6 +65,12 @@ namespace Discord.WebSocket
/// <inheritdoc/> /// <inheritdoc/>
public bool IsDMInteraction { get; private set; } public bool IsDMInteraction { get; private set; }
/// <inheritdoc/>
public ulong? GuildId { get; private set; }
/// <inheritdoc/>
public ulong ApplicationId { get; private set; }
internal SocketInteraction(DiscordSocketClient client, ulong id, ISocketMessageChannel channel, SocketUser user) internal SocketInteraction(DiscordSocketClient client, ulong id, ISocketMessageChannel channel, SocketUser user)
: base(client, id) : base(client, id)
{ {
@@ -119,13 +116,21 @@ namespace Discord.WebSocket
internal virtual void Update(Model model) internal virtual void Update(Model model)
{ {
IsDMInteraction = !model.GuildId.IsSpecified; ChannelId = model.ChannelId.IsSpecified
? model.ChannelId.Value
: null;
ChannelId = model.ChannelId.ToNullable(); GuildId = model.GuildId.IsSpecified
? model.GuildId.Value
: null;
IsDMInteraction = GuildId is null;
ApplicationId = model.ApplicationId;
Data = model.Data.IsSpecified Data = model.Data.IsSpecified
? model.Data.Value ? model.Data.Value
: null; : null;
Token = model.Token; Token = model.Token;
Version = model.Version; Version = model.Version;
Type = model.Type; Type = model.Type;
@@ -133,6 +138,7 @@ namespace Discord.WebSocket
UserLocale = model.UserLocale.IsSpecified UserLocale = model.UserLocale.IsSpecified
? model.UserLocale.Value ? model.UserLocale.Value
: null; : null;
GuildLocale = model.GuildLocale.IsSpecified GuildLocale = model.GuildLocale.IsSpecified
? model.GuildLocale.Value ? model.GuildLocale.Value
: null; : null;