From a24dde4b19adf7a8615f59b9ab9713e5bbb08833 Mon Sep 17 00:00:00 2001
From: Armano den Boef <68127614+Rozen4334@users.noreply.github.com>
Date: Wed, 18 May 2022 09:56:57 +0200
Subject: [PATCH] feature: optional API calling to RestInteraction (#2281)
* Take 2
* Expose channel & guild Id for manual calling
* Make api calling optional at runtime
* Resolve build errors
* Bind runtime option to interaction type
* Expose methods to get channel & guild from API
* Patch out NRE's, test on all int types
---
src/Discord.Net.Rest/DiscordRestClient.cs | 22 ++-
src/Discord.Net.Rest/DiscordRestConfig.cs | 2 +
.../CommandBase/RestCommandBase.cs | 8 +-
.../CommandBase/RestCommandBaseData.cs | 8 +-
.../CommandBase/RestResolvableData.cs | 26 +++-
.../MessageCommands/RestMessageCommand.cs | 10 +-
.../MessageCommands/RestMessageCommandData.cs | 6 +-
.../UserCommands/RestUserCommand.cs | 10 +-
.../UserCommands/RestUserCommandData.cs | 4 +-
.../MessageComponents/RestMessageComponent.cs | 8 +-
.../Entities/Interactions/Modals/RestModal.cs | 4 +-
.../Entities/Interactions/RestInteraction.cs | 143 +++++++++++++++---
.../Interactions/RestPingInteraction.cs | 4 +-
.../RestAutocompleteInteraction.cs | 4 +-
.../SlashCommands/RestSlashCommand.cs | 10 +-
.../SlashCommands/RestSlashCommandData.cs | 8 +-
.../Entities/Users/RestGuildUser.cs | 14 +-
17 files changed, 212 insertions(+), 79 deletions(-)
diff --git a/src/Discord.Net.Rest/DiscordRestClient.cs b/src/Discord.Net.Rest/DiscordRestClient.cs
index b1948f80a..7cb15bed1 100644
--- a/src/Discord.Net.Rest/DiscordRestClient.cs
+++ b/src/Discord.Net.Rest/DiscordRestClient.cs
@@ -32,9 +32,15 @@ namespace Discord.Rest
/// Initializes a new with the provided configuration.
///
/// The configuration to be used with the client.
- public DiscordRestClient(DiscordRestConfig config) : base(config, CreateApiClient(config)) { }
+ public DiscordRestClient(DiscordRestConfig config) : base(config, CreateApiClient(config))
+ {
+ _apiOnCreation = config.APIOnRestInteractionCreation;
+ }
// used for socket client rest access
- internal DiscordRestClient(DiscordRestConfig config, API.DiscordRestApiClient api) : base(config, api) { }
+ internal DiscordRestClient(DiscordRestConfig config, API.DiscordRestApiClient api) : base(config, api)
+ {
+ _apiOnCreation = config.APIOnRestInteractionCreation;
+ }
private static API.DiscordRestApiClient CreateApiClient(DiscordRestConfig config)
=> new API.DiscordRestApiClient(config.RestClientProvider, DiscordRestConfig.UserAgent, serializer: Serializer, useSystemClock: config.UseSystemClock, defaultRatelimitCallback: config.DefaultRatelimitCallback);
@@ -82,6 +88,8 @@ namespace Discord.Rest
#region Rest interactions
+ private readonly bool _apiOnCreation;
+
public bool IsValidHttpInteraction(string publicKey, string signature, string timestamp, string body)
=> IsValidHttpInteraction(publicKey, signature, timestamp, Encoding.UTF8.GetBytes(body));
public bool IsValidHttpInteraction(string publicKey, string signature, string timestamp, byte[] body)
@@ -113,8 +121,8 @@ namespace Discord.Rest
/// A that represents the incoming http interaction.
///
/// Thrown when the signature doesn't match the public key.
- public Task ParseHttpInteractionAsync(string publicKey, string signature, string timestamp, string body)
- => ParseHttpInteractionAsync(publicKey, signature, timestamp, Encoding.UTF8.GetBytes(body));
+ public Task ParseHttpInteractionAsync(string publicKey, string signature, string timestamp, string body, Func doApiCallOnCreation = null)
+ => ParseHttpInteractionAsync(publicKey, signature, timestamp, Encoding.UTF8.GetBytes(body), doApiCallOnCreation);
///
/// Creates a from a http message.
@@ -127,7 +135,7 @@ namespace Discord.Rest
/// A that represents the incoming http interaction.
///
/// Thrown when the signature doesn't match the public key.
- public async Task ParseHttpInteractionAsync(string publicKey, string signature, string timestamp, byte[] body)
+ public async Task ParseHttpInteractionAsync(string publicKey, string signature, string timestamp, byte[] body, Func doApiCallOnCreation = null)
{
if (!IsValidHttpInteraction(publicKey, signature, timestamp, body))
{
@@ -138,12 +146,12 @@ namespace Discord.Rest
using (var jsonReader = new JsonTextReader(textReader))
{
var model = Serializer.Deserialize(jsonReader);
- return await RestInteraction.CreateAsync(this, model);
+ return await RestInteraction.CreateAsync(this, model, doApiCallOnCreation != null ? doApiCallOnCreation(model.Type) : _apiOnCreation);
}
}
#endregion
-
+
public async Task GetApplicationInfoAsync(RequestOptions options = null)
{
return _applicationInfo ??= await ClientHelper.GetApplicationInfoAsync(this, options).ConfigureAwait(false);
diff --git a/src/Discord.Net.Rest/DiscordRestConfig.cs b/src/Discord.Net.Rest/DiscordRestConfig.cs
index 7bf7440ce..a09d9ee98 100644
--- a/src/Discord.Net.Rest/DiscordRestConfig.cs
+++ b/src/Discord.Net.Rest/DiscordRestConfig.cs
@@ -9,5 +9,7 @@ namespace Discord.Rest
{
/// Gets or sets the provider used to generate new REST connections.
public RestClientProvider RestClientProvider { get; set; } = DefaultRestClientProvider.Instance;
+
+ public bool APIOnRestInteractionCreation { get; set; } = true;
}
}
diff --git a/src/Discord.Net.Rest/Entities/Interactions/CommandBase/RestCommandBase.cs b/src/Discord.Net.Rest/Entities/Interactions/CommandBase/RestCommandBase.cs
index 196416f0e..22e56a733 100644
--- a/src/Discord.Net.Rest/Entities/Interactions/CommandBase/RestCommandBase.cs
+++ b/src/Discord.Net.Rest/Entities/Interactions/CommandBase/RestCommandBase.cs
@@ -39,16 +39,16 @@ namespace Discord.Rest
{
}
- internal new static async Task CreateAsync(DiscordRestClient client, Model model)
+ internal new static async Task CreateAsync(DiscordRestClient client, Model model, bool doApiCall)
{
var entity = new RestCommandBase(client, model);
- await entity.UpdateAsync(client, model).ConfigureAwait(false);
+ await entity.UpdateAsync(client, model, doApiCall).ConfigureAwait(false);
return entity;
}
- internal override async Task UpdateAsync(DiscordRestClient client, Model model)
+ internal override async Task UpdateAsync(DiscordRestClient client, Model model, bool doApiCall)
{
- await base.UpdateAsync(client, model).ConfigureAwait(false);
+ await base.UpdateAsync(client, model, doApiCall).ConfigureAwait(false);
}
///
diff --git a/src/Discord.Net.Rest/Entities/Interactions/CommandBase/RestCommandBaseData.cs b/src/Discord.Net.Rest/Entities/Interactions/CommandBase/RestCommandBaseData.cs
index 4227c802a..828299d22 100644
--- a/src/Discord.Net.Rest/Entities/Interactions/CommandBase/RestCommandBaseData.cs
+++ b/src/Discord.Net.Rest/Entities/Interactions/CommandBase/RestCommandBaseData.cs
@@ -27,20 +27,20 @@ namespace Discord.Rest
{
}
- internal static async Task CreateAsync(DiscordRestClient client, Model model, RestGuild guild, IRestMessageChannel channel)
+ internal static async Task CreateAsync(DiscordRestClient client, Model model, RestGuild guild, IRestMessageChannel channel, bool doApiCall)
{
var entity = new RestCommandBaseData(client, model);
- await entity.UpdateAsync(client, model, guild, channel).ConfigureAwait(false);
+ await entity.UpdateAsync(client, model, guild, channel, doApiCall).ConfigureAwait(false);
return entity;
}
- internal virtual async Task UpdateAsync(DiscordRestClient client, Model model, RestGuild guild, IRestMessageChannel channel)
+ internal virtual async Task UpdateAsync(DiscordRestClient client, Model model, RestGuild guild, IRestMessageChannel channel, bool doApiCall)
{
Name = model.Name;
if (model.Resolved.IsSpecified && ResolvableData == null)
{
ResolvableData = new RestResolvableData();
- await ResolvableData.PopulateAsync(client, guild, channel, model).ConfigureAwait(false);
+ await ResolvableData.PopulateAsync(client, guild, channel, model, doApiCall).ConfigureAwait(false);
}
}
diff --git a/src/Discord.Net.Rest/Entities/Interactions/CommandBase/RestResolvableData.cs b/src/Discord.Net.Rest/Entities/Interactions/CommandBase/RestResolvableData.cs
index 9353a8530..72b894729 100644
--- a/src/Discord.Net.Rest/Entities/Interactions/CommandBase/RestResolvableData.cs
+++ b/src/Discord.Net.Rest/Entities/Interactions/CommandBase/RestResolvableData.cs
@@ -22,7 +22,7 @@ namespace Discord.Rest
internal readonly Dictionary Attachments
= new Dictionary();
- internal async Task PopulateAsync(DiscordRestClient discord, RestGuild guild, IRestMessageChannel channel, T model)
+ internal async Task PopulateAsync(DiscordRestClient discord, RestGuild guild, IRestMessageChannel channel, T model, bool doApiCall)
{
var resolved = model.Resolved.Value;
@@ -38,15 +38,26 @@ namespace Discord.Rest
if (resolved.Channels.IsSpecified)
{
- var channels = await guild.GetChannelsAsync().ConfigureAwait(false);
+ var channels = doApiCall ? await guild.GetChannelsAsync().ConfigureAwait(false) : null;
foreach (var channelModel in resolved.Channels.Value)
{
- var restChannel = channels.FirstOrDefault(x => x.Id == channelModel.Value.Id);
+ if (channels != null)
+ {
+ var guildChannel = channels.FirstOrDefault(x => x.Id == channelModel.Value.Id);
- restChannel.Update(channelModel.Value);
+ guildChannel.Update(channelModel.Value);
- Channels.Add(ulong.Parse(channelModel.Key), restChannel);
+ Channels.Add(ulong.Parse(channelModel.Key), guildChannel);
+ }
+ else
+ {
+ var restChannel = RestChannel.Create(discord, channelModel.Value);
+
+ restChannel.Update(channelModel.Value);
+
+ Channels.Add(ulong.Parse(channelModel.Key), restChannel);
+ }
}
}
@@ -76,7 +87,10 @@ namespace Discord.Rest
{
foreach (var msg in resolved.Messages.Value)
{
- channel ??= (IRestMessageChannel)(Channels.FirstOrDefault(x => x.Key == msg.Value.ChannelId).Value ?? await discord.GetChannelAsync(msg.Value.ChannelId).ConfigureAwait(false));
+ channel ??= (IRestMessageChannel)(Channels.FirstOrDefault(x => x.Key == msg.Value.ChannelId).Value
+ ?? (doApiCall
+ ? await discord.GetChannelAsync(msg.Value.ChannelId).ConfigureAwait(false)
+ : null));
RestUser author;
diff --git a/src/Discord.Net.Rest/Entities/Interactions/ContextMenuCommands/MessageCommands/RestMessageCommand.cs b/src/Discord.Net.Rest/Entities/Interactions/ContextMenuCommands/MessageCommands/RestMessageCommand.cs
index 609fe0829..34c664b09 100644
--- a/src/Discord.Net.Rest/Entities/Interactions/ContextMenuCommands/MessageCommands/RestMessageCommand.cs
+++ b/src/Discord.Net.Rest/Entities/Interactions/ContextMenuCommands/MessageCommands/RestMessageCommand.cs
@@ -20,22 +20,22 @@ namespace Discord.Rest
}
- internal new static async Task CreateAsync(DiscordRestClient client, Model model)
+ internal new static async Task CreateAsync(DiscordRestClient client, Model model, bool doApiCall)
{
var entity = new RestMessageCommand(client, model);
- await entity.UpdateAsync(client, model).ConfigureAwait(false);
+ await entity.UpdateAsync(client, model, doApiCall).ConfigureAwait(false);
return entity;
}
- internal override async Task UpdateAsync(DiscordRestClient client, Model model)
+ internal override async Task UpdateAsync(DiscordRestClient client, Model model, bool doApiCall)
{
- await base.UpdateAsync(client, model).ConfigureAwait(false);
+ await base.UpdateAsync(client, model, doApiCall).ConfigureAwait(false);
var dataModel = model.Data.IsSpecified
? (DataModel)model.Data.Value
: null;
- Data = await RestMessageCommandData.CreateAsync(client, dataModel, Guild, Channel).ConfigureAwait(false);
+ Data = await RestMessageCommandData.CreateAsync(client, dataModel, Guild, Channel, doApiCall).ConfigureAwait(false);
}
//IMessageCommandInteraction
diff --git a/src/Discord.Net.Rest/Entities/Interactions/ContextMenuCommands/MessageCommands/RestMessageCommandData.cs b/src/Discord.Net.Rest/Entities/Interactions/ContextMenuCommands/MessageCommands/RestMessageCommandData.cs
index 127d539d9..d2968a38a 100644
--- a/src/Discord.Net.Rest/Entities/Interactions/ContextMenuCommands/MessageCommands/RestMessageCommandData.cs
+++ b/src/Discord.Net.Rest/Entities/Interactions/ContextMenuCommands/MessageCommands/RestMessageCommandData.cs
@@ -23,15 +23,15 @@ namespace Discord.Rest
/// Note Not implemented for
///
public override IReadOnlyCollection Options
- => throw new System.NotImplementedException();
+ => throw new NotImplementedException();
internal RestMessageCommandData(DiscordRestClient client, Model model)
: base(client, model) { }
- internal new static async Task CreateAsync(DiscordRestClient client, Model model, RestGuild guild, IRestMessageChannel channel)
+ internal new static async Task CreateAsync(DiscordRestClient client, Model model, RestGuild guild, IRestMessageChannel channel, bool doApiCall)
{
var entity = new RestMessageCommandData(client, model);
- await entity.UpdateAsync(client, model, guild, channel).ConfigureAwait(false);
+ await entity.UpdateAsync(client, model, guild, channel, doApiCall).ConfigureAwait(false);
return entity;
}
diff --git a/src/Discord.Net.Rest/Entities/Interactions/ContextMenuCommands/UserCommands/RestUserCommand.cs b/src/Discord.Net.Rest/Entities/Interactions/ContextMenuCommands/UserCommands/RestUserCommand.cs
index 7f55fd61b..91319a649 100644
--- a/src/Discord.Net.Rest/Entities/Interactions/ContextMenuCommands/UserCommands/RestUserCommand.cs
+++ b/src/Discord.Net.Rest/Entities/Interactions/ContextMenuCommands/UserCommands/RestUserCommand.cs
@@ -23,22 +23,22 @@ namespace Discord.Rest
{
}
- internal new static async Task CreateAsync(DiscordRestClient client, Model model)
+ internal new static async Task CreateAsync(DiscordRestClient client, Model model, bool doApiCall)
{
var entity = new RestUserCommand(client, model);
- await entity.UpdateAsync(client, model).ConfigureAwait(false);
+ await entity.UpdateAsync(client, model, doApiCall).ConfigureAwait(false);
return entity;
}
- internal override async Task UpdateAsync(DiscordRestClient client, Model model)
+ internal override async Task UpdateAsync(DiscordRestClient client, Model model, bool doApiCall)
{
- await base.UpdateAsync(client, model).ConfigureAwait(false);
+ await base.UpdateAsync(client, model, doApiCall).ConfigureAwait(false);
var dataModel = model.Data.IsSpecified
? (DataModel)model.Data.Value
: null;
- Data = await RestUserCommandData.CreateAsync(client, dataModel, Guild, Channel).ConfigureAwait(false);
+ Data = await RestUserCommandData.CreateAsync(client, dataModel, Guild, Channel, doApiCall).ConfigureAwait(false);
}
//IUserCommandInteractionData
diff --git a/src/Discord.Net.Rest/Entities/Interactions/ContextMenuCommands/UserCommands/RestUserCommandData.cs b/src/Discord.Net.Rest/Entities/Interactions/ContextMenuCommands/UserCommands/RestUserCommandData.cs
index e18499d42..61b291f7c 100644
--- a/src/Discord.Net.Rest/Entities/Interactions/ContextMenuCommands/UserCommands/RestUserCommandData.cs
+++ b/src/Discord.Net.Rest/Entities/Interactions/ContextMenuCommands/UserCommands/RestUserCommandData.cs
@@ -26,10 +26,10 @@ namespace Discord.Rest
internal RestUserCommandData(DiscordRestClient client, Model model)
: base(client, model) { }
- internal new static async Task CreateAsync(DiscordRestClient client, Model model, RestGuild guild, IRestMessageChannel channel)
+ internal new static async Task CreateAsync(DiscordRestClient client, Model model, RestGuild guild, IRestMessageChannel channel, bool doApiCall)
{
var entity = new RestUserCommandData(client, model);
- await entity.UpdateAsync(client, model, guild, channel).ConfigureAwait(false);
+ await entity.UpdateAsync(client, model, guild, channel, doApiCall).ConfigureAwait(false);
return entity;
}
diff --git a/src/Discord.Net.Rest/Entities/Interactions/MessageComponents/RestMessageComponent.cs b/src/Discord.Net.Rest/Entities/Interactions/MessageComponents/RestMessageComponent.cs
index 002510eac..e0eab6051 100644
--- a/src/Discord.Net.Rest/Entities/Interactions/MessageComponents/RestMessageComponent.cs
+++ b/src/Discord.Net.Rest/Entities/Interactions/MessageComponents/RestMessageComponent.cs
@@ -37,15 +37,15 @@ namespace Discord.Rest
Data = new RestMessageComponentData(dataModel);
}
- internal new static async Task CreateAsync(DiscordRestClient client, Model model)
+ internal new static async Task CreateAsync(DiscordRestClient client, Model model, bool doApiCall)
{
var entity = new RestMessageComponent(client, model);
- await entity.UpdateAsync(client, model).ConfigureAwait(false);
+ await entity.UpdateAsync(client, model, doApiCall).ConfigureAwait(false);
return entity;
}
- internal override async Task UpdateAsync(DiscordRestClient discord, Model model)
+ internal override async Task UpdateAsync(DiscordRestClient discord, Model model, bool doApiCall)
{
- await base.UpdateAsync(discord, model).ConfigureAwait(false);
+ await base.UpdateAsync(discord, model, doApiCall).ConfigureAwait(false);
if (model.Message.IsSpecified && model.ChannelId.IsSpecified)
{
diff --git a/src/Discord.Net.Rest/Entities/Interactions/Modals/RestModal.cs b/src/Discord.Net.Rest/Entities/Interactions/Modals/RestModal.cs
index 5f54fe051..9229b63b5 100644
--- a/src/Discord.Net.Rest/Entities/Interactions/Modals/RestModal.cs
+++ b/src/Discord.Net.Rest/Entities/Interactions/Modals/RestModal.cs
@@ -26,10 +26,10 @@ namespace Discord.Rest
Data = new RestModalData(dataModel);
}
- internal new static async Task CreateAsync(DiscordRestClient client, ModelBase model)
+ internal new static async Task CreateAsync(DiscordRestClient client, ModelBase model, bool doApiCall)
{
var entity = new RestModal(client, model);
- await entity.UpdateAsync(client, model);
+ await entity.UpdateAsync(client, model, doApiCall);
return entity;
}
diff --git a/src/Discord.Net.Rest/Entities/Interactions/RestInteraction.cs b/src/Discord.Net.Rest/Entities/Interactions/RestInteraction.cs
index b8c0f961d..59adc0347 100644
--- a/src/Discord.Net.Rest/Entities/Interactions/RestInteraction.cs
+++ b/src/Discord.Net.Rest/Entities/Interactions/RestInteraction.cs
@@ -16,6 +16,10 @@ namespace Discord.Rest
///
public abstract class RestInteraction : RestEntity, IDiscordInteraction
{
+ // Added so channel & guild methods don't need a client reference
+ private Func> _getChannel = null;
+ private Func> _getGuild = null;
+
///
public InteractionType Type { get; private set; }
@@ -31,6 +35,10 @@ namespace Discord.Rest
///
/// Gets the user who invoked the interaction.
///
+ ///
+ /// If this user is an and is set to false,
+ /// will return
+ ///
public RestUser User { get; private set; }
///
@@ -48,14 +56,38 @@ namespace Discord.Rest
public bool IsValidToken
=> InteractionHelper.CanRespondOrFollowup(this);
+ ///
+ /// Gets the ID of the channel this interaction was executed in.
+ ///
+ ///
+ /// if the interaction was not executed in a guild.
+ ///
+ public ulong? ChannelId { get; private set; } = null;
+
///
/// Gets the channel that this interaction was executed in.
///
+ ///
+ /// if is set to false.
+ /// Call to set this property and get the interaction channel.
+ ///
public IRestMessageChannel Channel { get; private set; }
///
- /// Gets the guild this interaction was executed in.
+ /// Gets the ID of the guild this interaction was executed in if applicable.
///
+ ///
+ /// if the interaction was not executed in a guild.
+ ///
+ public ulong? GuildId { get; private set; } = null;
+
+ ///
+ /// Gets the guild this interaction was executed in if applicable.
+ ///
+ ///
+ /// This property will be if is set to false
+ /// or if the interaction was not executed in a guild.
+ ///
public RestGuild Guild { get; private set; }
///
@@ -72,11 +104,11 @@ namespace Discord.Rest
: DateTime.UtcNow;
}
- internal static async Task CreateAsync(DiscordRestClient client, Model model)
+ internal static async Task CreateAsync(DiscordRestClient client, Model model, bool doApiCall)
{
if(model.Type == InteractionType.Ping)
{
- return await RestPingInteraction.CreateAsync(client, model);
+ return await RestPingInteraction.CreateAsync(client, model, doApiCall);
}
if (model.Type == InteractionType.ApplicationCommand)
@@ -90,26 +122,26 @@ namespace Discord.Rest
return dataModel.Type switch
{
- ApplicationCommandType.Slash => await RestSlashCommand.CreateAsync(client, model).ConfigureAwait(false),
- ApplicationCommandType.Message => await RestMessageCommand.CreateAsync(client, model).ConfigureAwait(false),
- ApplicationCommandType.User => await RestUserCommand.CreateAsync(client, model).ConfigureAwait(false),
+ ApplicationCommandType.Slash => await RestSlashCommand.CreateAsync(client, model, doApiCall).ConfigureAwait(false),
+ ApplicationCommandType.Message => await RestMessageCommand.CreateAsync(client, model, doApiCall).ConfigureAwait(false),
+ ApplicationCommandType.User => await RestUserCommand.CreateAsync(client, model, doApiCall).ConfigureAwait(false),
_ => null
};
}
if (model.Type == InteractionType.MessageComponent)
- return await RestMessageComponent.CreateAsync(client, model).ConfigureAwait(false);
+ return await RestMessageComponent.CreateAsync(client, model, doApiCall).ConfigureAwait(false);
if (model.Type == InteractionType.ApplicationCommandAutocomplete)
- return await RestAutocompleteInteraction.CreateAsync(client, model).ConfigureAwait(false);
+ return await RestAutocompleteInteraction.CreateAsync(client, model, doApiCall).ConfigureAwait(false);
if (model.Type == InteractionType.ModalSubmit)
- return await RestModal.CreateAsync(client, model).ConfigureAwait(false);
+ return await RestModal.CreateAsync(client, model, doApiCall).ConfigureAwait(false);
return null;
}
- internal virtual async Task UpdateAsync(DiscordRestClient discord, Model model)
+ internal virtual async Task UpdateAsync(DiscordRestClient discord, Model model, bool doApiCall)
{
IsDMInteraction = !model.GuildId.IsSpecified;
@@ -120,16 +152,23 @@ namespace Discord.Rest
Version = model.Version;
Type = model.Type;
- if(Guild == null && model.GuildId.IsSpecified)
+ if (Guild == null && model.GuildId.IsSpecified)
{
- Guild = await discord.GetGuildAsync(model.GuildId.Value);
+ GuildId = model.GuildId.Value;
+ if (doApiCall)
+ Guild = await discord.GetGuildAsync(model.GuildId.Value);
+ else
+ {
+ Guild = null;
+ _getGuild = new(async (opt, ul) => await discord.GetGuildAsync(ul, opt));
+ }
}
if (User == null)
{
if (model.Member.IsSpecified && model.GuildId.IsSpecified)
{
- User = RestGuildUser.Create(Discord, Guild, model.Member.Value);
+ User = RestGuildUser.Create(Discord, Guild, model.Member.Value, (Guild is null) ? model.GuildId.Value : null);
}
else
{
@@ -137,18 +176,33 @@ namespace Discord.Rest
}
}
- if(Channel == null && model.ChannelId.IsSpecified)
+ if (Channel == null && model.ChannelId.IsSpecified)
{
try
{
- Channel = (IRestMessageChannel)await discord.GetChannelAsync(model.ChannelId.Value);
+ ChannelId = model.ChannelId.Value;
+ if (doApiCall)
+ Channel = (IRestMessageChannel)await discord.GetChannelAsync(model.ChannelId.Value);
+ else
+ {
+ _getChannel = new(async (opt, ul) =>
+ {
+ if (Guild is null)
+ 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;
+ }
}
- catch(HttpException x) when(x.DiscordCode == DiscordErrorCode.MissingPermissions) { } // ignore
+ catch (HttpException x) when (x.DiscordCode == DiscordErrorCode.MissingPermissions) { } // ignore
}
UserLocale = model.UserLocale.IsSpecified
- ? model.UserLocale.Value
- : null;
+ ? model.UserLocale.Value
+ : null;
+
GuildLocale = model.GuildLocale.IsSpecified
? model.GuildLocale.Value
: null;
@@ -164,6 +218,59 @@ namespace Discord.Rest
return json.ToString();
}
+ ///
+ /// Gets the channel this interaction was executed in. Will be a DM channel if the interaction was executed in DM.
+ ///
+ ///
+ /// Calling this method succesfully will populate the property.
+ /// After this, further calls to this method will no longer call the API, and depend on the value set in .
+ ///
+ /// The request options for this request.
+ /// A Rest channel to send messages to.
+ /// Thrown if no channel can be received.
+ public async Task GetChannelAsync(RequestOptions options = null)
+ {
+ if (IsDMInteraction && Channel is null)
+ {
+ var channel = await User.CreateDMChannelAsync(options);
+ Channel = channel;
+ }
+
+ else if (Channel is null)
+ {
+ var channel = await _getChannel(options, ChannelId.Value);
+
+ 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.
+ }
+
+ return Channel;
+ }
+
+ ///
+ /// Gets the guild this interaction was executed in if applicable.
+ ///
+ ///
+ /// Calling this method succesfully will populate the property.
+ /// After this, further calls to this method will no longer call the API, and depend on the value set in .
+ ///
+ /// The request options for this request.
+ /// The guild this interaction was executed in. if the interaction was executed inside DM.
+ public async Task GetGuildAsync(RequestOptions options)
+ {
+ if (IsDMInteraction)
+ return null;
+
+ if (Guild is null)
+ Guild = await _getGuild(options, GuildId.Value);
+
+ _getGuild = null; // get rid of it, we don't need it anymore.
+ return Guild;
+ }
+
///
public abstract string Defer(bool ephemeral = false, RequestOptions options = null);
///
diff --git a/src/Discord.Net.Rest/Entities/Interactions/RestPingInteraction.cs b/src/Discord.Net.Rest/Entities/Interactions/RestPingInteraction.cs
index bd15bc2d3..47e1a3b0f 100644
--- a/src/Discord.Net.Rest/Entities/Interactions/RestPingInteraction.cs
+++ b/src/Discord.Net.Rest/Entities/Interactions/RestPingInteraction.cs
@@ -18,10 +18,10 @@ namespace Discord.Rest
{
}
- internal static new async Task CreateAsync(DiscordRestClient client, Model model)
+ internal static new async Task CreateAsync(DiscordRestClient client, Model model, bool doApiCall)
{
var entity = new RestPingInteraction(client, model.Id);
- await entity.UpdateAsync(client, model);
+ await entity.UpdateAsync(client, model, doApiCall);
return entity;
}
diff --git a/src/Discord.Net.Rest/Entities/Interactions/SlashCommands/RestAutocompleteInteraction.cs b/src/Discord.Net.Rest/Entities/Interactions/SlashCommands/RestAutocompleteInteraction.cs
index 24dbae37a..27c536240 100644
--- a/src/Discord.Net.Rest/Entities/Interactions/SlashCommands/RestAutocompleteInteraction.cs
+++ b/src/Discord.Net.Rest/Entities/Interactions/SlashCommands/RestAutocompleteInteraction.cs
@@ -32,10 +32,10 @@ namespace Discord.Rest
Data = new RestAutocompleteInteractionData(dataModel);
}
- internal new static async Task CreateAsync(DiscordRestClient client, Model model)
+ internal new static async Task CreateAsync(DiscordRestClient client, Model model, bool doApiCall)
{
var entity = new RestAutocompleteInteraction(client, model);
- await entity.UpdateAsync(client, model).ConfigureAwait(false);
+ await entity.UpdateAsync(client, model, doApiCall).ConfigureAwait(false);
return entity;
}
diff --git a/src/Discord.Net.Rest/Entities/Interactions/SlashCommands/RestSlashCommand.cs b/src/Discord.Net.Rest/Entities/Interactions/SlashCommands/RestSlashCommand.cs
index 21184fcf6..f955e7855 100644
--- a/src/Discord.Net.Rest/Entities/Interactions/SlashCommands/RestSlashCommand.cs
+++ b/src/Discord.Net.Rest/Entities/Interactions/SlashCommands/RestSlashCommand.cs
@@ -23,22 +23,22 @@ namespace Discord.Rest
{
}
- internal new static async Task CreateAsync(DiscordRestClient client, Model model)
+ internal new static async Task CreateAsync(DiscordRestClient client, Model model, bool doApiCall)
{
var entity = new RestSlashCommand(client, model);
- await entity.UpdateAsync(client, model).ConfigureAwait(false);
+ await entity.UpdateAsync(client, model, doApiCall).ConfigureAwait(false);
return entity;
}
- internal override async Task UpdateAsync(DiscordRestClient client, Model model)
+ internal override async Task UpdateAsync(DiscordRestClient client, Model model, bool doApiCall)
{
- await base.UpdateAsync(client, model).ConfigureAwait(false);
+ await base.UpdateAsync(client, model, doApiCall).ConfigureAwait(false);
var dataModel = model.Data.IsSpecified
? (DataModel)model.Data.Value
: null;
- Data = await RestSlashCommandData.CreateAsync(client, dataModel, Guild, Channel).ConfigureAwait(false);
+ Data = await RestSlashCommandData.CreateAsync(client, dataModel, Guild, Channel, doApiCall).ConfigureAwait(false);
}
//ISlashCommandInteraction
diff --git a/src/Discord.Net.Rest/Entities/Interactions/SlashCommands/RestSlashCommandData.cs b/src/Discord.Net.Rest/Entities/Interactions/SlashCommands/RestSlashCommandData.cs
index f967cc628..19a819ab4 100644
--- a/src/Discord.Net.Rest/Entities/Interactions/SlashCommands/RestSlashCommandData.cs
+++ b/src/Discord.Net.Rest/Entities/Interactions/SlashCommands/RestSlashCommandData.cs
@@ -14,15 +14,15 @@ namespace Discord.Rest
internal RestSlashCommandData(DiscordRestClient client, Model model)
: base(client, model) { }
- internal static new async Task CreateAsync(DiscordRestClient client, Model model, RestGuild guild, IRestMessageChannel channel)
+ internal static new async Task CreateAsync(DiscordRestClient client, Model model, RestGuild guild, IRestMessageChannel channel, bool doApiCall)
{
var entity = new RestSlashCommandData(client, model);
- await entity.UpdateAsync(client, model, guild, channel).ConfigureAwait(false);
+ await entity.UpdateAsync(client, model, guild, channel, doApiCall).ConfigureAwait(false);
return entity;
}
- internal override async Task UpdateAsync(DiscordRestClient client, Model model, RestGuild guild, IRestMessageChannel channel)
+ internal override async Task UpdateAsync(DiscordRestClient client, Model model, RestGuild guild, IRestMessageChannel channel, bool doApiCall)
{
- await base.UpdateAsync(client, model, guild, channel).ConfigureAwait(false);
+ await base.UpdateAsync(client, model, guild, channel, doApiCall).ConfigureAwait(false);
Options = model.Options.IsSpecified
? model.Options.Value.Select(x => new RestSlashCommandDataOption(this, x)).ToImmutableArray()
diff --git a/src/Discord.Net.Rest/Entities/Users/RestGuildUser.cs b/src/Discord.Net.Rest/Entities/Users/RestGuildUser.cs
index 0a4a33099..6c311b6b5 100644
--- a/src/Discord.Net.Rest/Entities/Users/RestGuildUser.cs
+++ b/src/Discord.Net.Rest/Entities/Users/RestGuildUser.cs
@@ -35,7 +35,7 @@ namespace Discord.Rest
///
public DateTimeOffset? PremiumSince => DateTimeUtils.FromTicks(_premiumSinceTicks);
///
- public ulong GuildId => Guild.Id;
+ public ulong GuildId { get; }
///
public bool? IsPending { get; private set; }
///
@@ -80,14 +80,16 @@ namespace Discord.Rest
///
public DateTimeOffset? JoinedAt => DateTimeUtils.FromTicks(_joinedAtTicks);
- internal RestGuildUser(BaseDiscordClient discord, IGuild guild, ulong id)
+ internal RestGuildUser(BaseDiscordClient discord, IGuild guild, ulong id, ulong? guildId = null)
: base(discord, id)
{
- Guild = guild;
+ if (guild is not null)
+ Guild = guild;
+ GuildId = guildId ?? Guild.Id;
}
- internal static RestGuildUser Create(BaseDiscordClient discord, IGuild guild, Model model)
+ internal static RestGuildUser Create(BaseDiscordClient discord, IGuild guild, Model model, ulong? guildId = null)
{
- var entity = new RestGuildUser(discord, guild, model.User.Id);
+ var entity = new RestGuildUser(discord, guild, model.User.Id, guildId);
entity.Update(model);
return entity;
}
@@ -116,7 +118,7 @@ namespace Discord.Rest
private void UpdateRoles(ulong[] roleIds)
{
var roles = ImmutableArray.CreateBuilder(roleIds.Length + 1);
- roles.Add(Guild.Id);
+ roles.Add(GuildId);
for (int i = 0; i < roleIds.Length; i++)
roles.Add(roleIds[i]);
_roleIds = roles.ToImmutable();