diff --git a/src/Discord.Net.Interactions/Extensions/RestExtensions.cs b/src/Discord.Net.Interactions/Extensions/RestExtensions.cs new file mode 100644 index 000000000..2641617e0 --- /dev/null +++ b/src/Discord.Net.Interactions/Extensions/RestExtensions.cs @@ -0,0 +1,25 @@ +using Discord.Interactions; +using System; + +namespace Discord.Rest +{ + public static class RestExtensions + { + /// + /// Respond to an interaction with a . + /// + /// Type of the implementation. + /// The interaction to respond to. + /// The request options for this request. + /// Serialized payload to be used to create a HTTP response. + public static string RespondWithModal(this RestInteraction interaction, string customId, RequestOptions options = null, Action modifyModal = null) + where T : class, IModal + { + if (!ModalUtils.TryGet(out var modalInfo)) + throw new ArgumentException($"{typeof(T).FullName} isn't referenced by any registered Modal Interaction Command and doesn't have a cached {typeof(ModalInfo)}"); + + var modal = modalInfo.ToModal(customId, modifyModal); + return interaction.RespondWithModal(modal, options); + } + } +} diff --git a/src/Discord.Net.Interactions/RestInteractionModuleBase.cs b/src/Discord.Net.Interactions/RestInteractionModuleBase.cs index a07614f7f..e83c91fef 100644 --- a/src/Discord.Net.Interactions/RestInteractionModuleBase.cs +++ b/src/Discord.Net.Interactions/RestInteractionModuleBase.cs @@ -65,5 +65,39 @@ namespace Discord.Interactions else await InteractionService._restResponseCallback(Context, payload).ConfigureAwait(false); } + + /// + /// Responds to the interaction with a modal. + /// + /// The modal to respond with. + /// The request options for this request. + /// A string that contains json to write back to the incoming http request. + /// + /// + protected override async Task RespondWithModalAsync(Modal modal, RequestOptions options = null) + { + if (Context.Interaction is not RestInteraction restInteraction) + throw new InvalidOperationException($"Invalid interaction type. Interaction must be a type of {nameof(RestInteraction)} in order to execute this method"); + + var payload = restInteraction.RespondWithModal(modal, options); + + if (Context is IRestInteractionContext restContext && restContext.InteractionResponseCallback != null) + await restContext.InteractionResponseCallback.Invoke(payload).ConfigureAwait(false); + else + await InteractionService._restResponseCallback(Context, payload).ConfigureAwait(false); + } + + protected override async Task RespondWithModalAsync(string customId, RequestOptions options = null) + { + if (Context.Interaction is not RestInteraction restInteraction) + throw new InvalidOperationException($"Invalid interaction type. Interaction must be a type of {nameof(RestInteraction)} in order to execute this method"); + + var payload = restInteraction.RespondWithModal(customId, options); + + if (Context is IRestInteractionContext restContext && restContext.InteractionResponseCallback != null) + await restContext.InteractionResponseCallback.Invoke(payload).ConfigureAwait(false); + else + await InteractionService._restResponseCallback(Context, payload).ConfigureAwait(false); + } } } diff --git a/src/Discord.Net.Interactions/Utilities/ApplicationCommandRestUtil.cs b/src/Discord.Net.Interactions/Utilities/ApplicationCommandRestUtil.cs index 46f0f4a4a..c2052b7c7 100644 --- a/src/Discord.Net.Interactions/Utilities/ApplicationCommandRestUtil.cs +++ b/src/Discord.Net.Interactions/Utilities/ApplicationCommandRestUtil.cs @@ -196,5 +196,26 @@ namespace Discord.Interactions }).ToList(), Options = commandOption.Options?.Select(x => x.ToApplicationCommandOptionProps()).ToList() }; + + public static Modal ToModal(this ModalInfo modalInfo, string customId, Action modifyModal = null) + { + var builder = new ModalBuilder(modalInfo.Title, customId); + + foreach (var input in modalInfo.Components) + switch (input) + { + case TextInputComponentInfo textComponent: + builder.AddTextInput(textComponent.Label, textComponent.CustomId, textComponent.Style, textComponent.Placeholder, textComponent.IsRequired ? textComponent.MinLength : null, + textComponent.MaxLength, textComponent.IsRequired, textComponent.InitialValue); + break; + default: + throw new InvalidOperationException($"{input.GetType().FullName} isn't a valid component info class"); + } + + if(modifyModal is not null) + modifyModal(builder); + + return builder.Build(); + } } }