[Feature] Add Message property and UpdateAsync() to IModalInteraction (#2645)

* initial commit

* better (?) comments

* whoops, accidentally commited this
This commit is contained in:
Misha133
2023-03-31 14:15:19 +03:00
committed by GitHub
parent bdd755b8cf
commit 83dfa0cea5
5 changed files with 150 additions and 7 deletions

View File

@@ -1,3 +1,6 @@
using System;
using System.Threading.Tasks;
namespace Discord namespace Discord
{ {
/// <summary> /// <summary>
@@ -9,5 +12,24 @@ namespace Discord
/// Gets the data received with this interaction; contains the clicked button. /// Gets the data received with this interaction; contains the clicked button.
/// </summary> /// </summary>
new IModalInteractionData Data { get; } new IModalInteractionData Data { get; }
/// <summary>
/// Gets the message the modal originates from.
/// </summary>
/// <remarks>
/// This property is only populated if the modal was created from a message component.
/// </remarks>
IUserMessage Message { get; }
/// <summary>
/// Updates the message which this modal originates from with the type <see cref="InteractionResponseType.UpdateMessage"/>
/// </summary>
/// <param name="func">A delegate containing the properties to modify the message with.</param>
/// <param name="options">The options to be used when sending the request.</param>
/// <returns>A task that represents the asynchronous operation of updating the message.</returns>
/// <remarks>
/// This method can be used only if the modal was created from a message component.
/// </remarks>
Task UpdateAsync(Action<MessageProperties> func, RequestOptions options = null);
} }
} }

View File

@@ -20,9 +20,7 @@ namespace Discord.Rest
/// </summary> /// </summary>
public new RestMessageComponentData Data { get; } public new RestMessageComponentData Data { get; }
/// <summary> /// <inheritdoc cref="IComponentInteraction.Message"/>
/// Gets the message that contained the trigger for this interaction.
/// </summary>
public RestUserMessage Message { get; private set; } public RestUserMessage Message { get; private set; }
private object _lock = new object(); private object _lock = new object();

View File

@@ -1,11 +1,13 @@
using Discord.Net.Rest; using Discord.Net.Rest;
using Discord.Rest; using Discord.Rest;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using System.Threading.Tasks; using System.Threading.Tasks;
using DataModel = Discord.API.ModalInteractionData; using DataModel = Discord.API.ModalInteractionData;
using ModelBase = Discord.API.Interaction; using ModelBase = Discord.API.Interaction;
@@ -23,6 +25,11 @@ namespace Discord.Rest
? (DataModel)model.Data.Value ? (DataModel)model.Data.Value
: null; : null;
if (model.Message.IsSpecified && model.ChannelId.IsSpecified)
{
Message = RestUserMessage.Create(Discord, Channel, User, model.Message.Value);
}
Data = new RestModalData(dataModel, client, Guild); Data = new RestModalData(dataModel, client, Guild);
} }
@@ -395,8 +402,100 @@ namespace Discord.Rest
public override string RespondWithModal(Modal modal, RequestOptions requestOptions = null) public override string RespondWithModal(Modal modal, RequestOptions requestOptions = null)
=> throw new NotSupportedException("Modal interactions cannot have modal responces!"); => throw new NotSupportedException("Modal interactions cannot have modal responces!");
/// <inheritdoc cref="IModalInteraction.Data"/>
public new RestModalData Data { get; set; } public new RestModalData Data { get; set; }
/// <inheritdoc cref="IModalInteraction.Message"/>
public RestUserMessage Message { get; private set; }
IUserMessage IModalInteraction.Message => Message;
IModalInteractionData IModalInteraction.Data => Data; IModalInteractionData IModalInteraction.Data => Data;
/// <inheritdoc/>
public async Task UpdateAsync(Action<MessageProperties> func, RequestOptions options = null)
{
var args = new MessageProperties();
func(args);
if (!IsValidToken)
throw new InvalidOperationException("Interaction token is no longer valid");
if (!InteractionHelper.CanSendResponse(this))
throw new TimeoutException($"Cannot respond to an interaction after {InteractionHelper.ResponseTimeLimit} seconds!");
if (args.AllowedMentions.IsSpecified)
{
var allowedMentions = args.AllowedMentions.Value;
Preconditions.AtMost(allowedMentions?.RoleIds?.Count ?? 0, 100, nameof(allowedMentions), "A max of 100 role Ids are allowed.");
Preconditions.AtMost(allowedMentions?.UserIds?.Count ?? 0, 100, nameof(allowedMentions), "A max of 100 user Ids are allowed.");
}
var embed = args.Embed;
var embeds = args.Embeds;
bool hasText = args.Content.IsSpecified ? !string.IsNullOrEmpty(args.Content.Value) : false;
bool hasEmbeds = embed.IsSpecified && embed.Value != null || embeds.IsSpecified && embeds.Value?.Length > 0;
if (!hasText && !hasEmbeds)
Preconditions.NotNullOrEmpty(args.Content.IsSpecified ? args.Content.Value : string.Empty, nameof(args.Content));
var apiEmbeds = embed.IsSpecified || embeds.IsSpecified ? new List<API.Embed>() : null;
if (embed.IsSpecified && embed.Value != null)
{
apiEmbeds.Add(embed.Value.ToModel());
}
if (embeds.IsSpecified && embeds.Value != null)
{
apiEmbeds.AddRange(embeds.Value.Select(x => x.ToModel()));
}
Preconditions.AtMost(apiEmbeds?.Count ?? 0, 10, nameof(args.Embeds), "A max of 10 embeds are allowed.");
// check that user flag and user Id list are exclusive, same with role flag and role Id list
if (args.AllowedMentions.IsSpecified && args.AllowedMentions.Value != null && args.AllowedMentions.Value.AllowedTypes.HasValue)
{
var allowedMentions = args.AllowedMentions.Value;
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(args.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(args.AllowedMentions));
}
}
var response = new API.InteractionResponse
{
Type = InteractionResponseType.UpdateMessage,
Data = new API.InteractionCallbackData
{
Content = args.Content,
AllowedMentions = args.AllowedMentions.IsSpecified ? args.AllowedMentions.Value?.ToModel() : Optional<API.AllowedMentions>.Unspecified,
Embeds = apiEmbeds?.ToArray() ?? Optional<API.Embed[]>.Unspecified,
Components = args.Components.IsSpecified
? args.Components.Value?.Components.Select(x => new API.ActionRowComponent(x)).ToArray() ?? Array.Empty<API.ActionRowComponent>()
: Optional<API.ActionRowComponent[]>.Unspecified,
Flags = args.Flags.IsSpecified ? args.Flags.Value ?? Optional<MessageFlags>.Unspecified : Optional<MessageFlags>.Unspecified
}
};
lock (_lock)
{
if (HasResponded)
{
throw new InvalidOperationException("Cannot respond, update, or defer twice to the same interaction");
}
}
await InteractionHelper.SendInteractionResponseAsync(Discord, response, this, Channel, options).ConfigureAwait(false);
HasResponded = true;
}
} }
} }

View File

@@ -19,10 +19,8 @@ namespace Discord.WebSocket
/// Gets the data received with this interaction, contains the button that was clicked. /// Gets the data received with this interaction, contains the button that was clicked.
/// </summary> /// </summary>
public new SocketMessageComponentData Data { get; } public new SocketMessageComponentData Data { get; }
/// <summary> /// <inheritdoc cref="IComponentInteraction.Message"/>
/// Gets the message that contained the trigger for this interaction.
/// </summary>
public SocketUserMessage Message { get; private set; } public SocketUserMessage Message { get; private set; }
private object _lock = new object(); private object _lock = new object();

View File

@@ -1,11 +1,13 @@
using Discord.Net.Rest; using Discord.Net.Rest;
using Discord.Rest; using Discord.Rest;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using System.Threading.Tasks; using System.Threading.Tasks;
using DataModel = Discord.API.ModalInteractionData; using DataModel = Discord.API.ModalInteractionData;
using ModelBase = Discord.API.Interaction; using ModelBase = Discord.API.Interaction;
@@ -21,6 +23,11 @@ namespace Discord.WebSocket
/// </summary> /// </summary>
public new SocketModalData Data { get; set; } public new SocketModalData Data { get; set; }
/// <inheritdoc cref="IModalInteraction.Message"/>
public SocketUserMessage Message { get; private set; }
IUserMessage IModalInteraction.Message => Message;
internal SocketModal(DiscordSocketClient client, ModelBase model, ISocketMessageChannel channel, SocketUser user) internal SocketModal(DiscordSocketClient client, ModelBase model, ISocketMessageChannel channel, SocketUser user)
: base(client, model.Id, channel, user) : base(client, model.Id, channel, user)
{ {
@@ -28,6 +35,24 @@ namespace Discord.WebSocket
? (DataModel)model.Data.Value ? (DataModel)model.Data.Value
: null; : null;
if (model.Message.IsSpecified)
{
SocketUser author = null;
if (Channel is SocketGuildChannel ch)
{
if (model.Message.Value.WebhookId.IsSpecified)
author = SocketWebhookUser.Create(ch.Guild, Discord.State, model.Message.Value.Author.Value, model.Message.Value.WebhookId.Value);
else if (model.Message.Value.Author.IsSpecified)
author = ch.Guild.GetUser(model.Message.Value.Author.Value.Id);
}
else if (model.Message.Value.Author.IsSpecified)
author = (Channel as SocketChannel)?.GetUser(model.Message.Value.Author.Value.Id);
author ??= Discord.State.GetOrAddUser(model.Message.Value.Author.Value.Id, _ => SocketGlobalUser.Create(Discord, Discord.State, model.Message.Value.Author.Value));
Message = SocketUserMessage.Create(Discord, Discord.State, author, Channel, model.Message.Value);
}
Data = new SocketModalData(dataModel, client, client.State, client.State.GetGuild(model.GuildId.GetValueOrDefault()), model.User.GetValueOrDefault()); Data = new SocketModalData(dataModel, client, client.State, client.State.GetGuild(model.GuildId.GetValueOrDefault()), model.User.GetValueOrDefault());
} }
@@ -174,6 +199,7 @@ namespace Discord.WebSocket
HasResponded = true; HasResponded = true;
} }
/// <inheritdoc/>
public async Task UpdateAsync(Action<MessageProperties> func, RequestOptions options = null) public async Task UpdateAsync(Action<MessageProperties> func, RequestOptions options = null)
{ {
var args = new MessageProperties(); var args = new MessageProperties();