diff --git a/src/Discord.Net.Interactions/Extensions/IDiscordInteractionExtensions.cs b/src/Discord.Net.Interactions/Extensions/IDiscordInteractionExtensions.cs index 5f66df92..6a6b3d66 100644 --- a/src/Discord.Net.Interactions/Extensions/IDiscordInteractionExtensions.cs +++ b/src/Discord.Net.Interactions/Extensions/IDiscordInteractionExtensions.cs @@ -84,23 +84,8 @@ namespace Discord.Interactions private static async Task SendModalResponseAsync(IDiscordInteraction interaction, string customId, ModalInfo modalInfo, RequestOptions options = null, 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); - - await interaction.RespondWithModalAsync(builder.Build(), options).ConfigureAwait(false); + var modal = modalInfo.ToModal(customId, modifyModal); + await interaction.RespondWithModalAsync(modal, options).ConfigureAwait(false); } } } diff --git a/src/Discord.Net.Interactions/Extensions/RestExtensions.cs b/src/Discord.Net.Interactions/Extensions/RestExtensions.cs index 2641617e..917da688 100644 --- a/src/Discord.Net.Interactions/Extensions/RestExtensions.cs +++ b/src/Discord.Net.Interactions/Extensions/RestExtensions.cs @@ -21,5 +21,41 @@ namespace Discord.Rest var modal = modalInfo.ToModal(customId, modifyModal); return interaction.RespondWithModal(modal, options); } + + /// + /// Respond to an interaction with an . + /// + /// Type of the implementation. + /// The interaction to respond to. + /// The instance to get field values from. + /// The request options for this request. + /// Delegate that can be used to modify the modal. + /// Serialized payload to be used to create a HTTP response. + public static string RespondWithModal(this RestInteraction interaction, string customId, T modal, 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 builder = new ModalBuilder(modal.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.Getter(modal) as string); + } + break; + default: + throw new InvalidOperationException($"{input.GetType().FullName} isn't a valid component info class"); + } + + if (modifyModal is not null) + modifyModal(builder); + + return interaction.RespondWithModal(builder.Build(), options); + } } } diff --git a/src/Discord.Net.Interactions/InteractionModuleBase.cs b/src/Discord.Net.Interactions/InteractionModuleBase.cs index 76b2da25..f3b9d11c 100644 --- a/src/Discord.Net.Interactions/InteractionModuleBase.cs +++ b/src/Discord.Net.Interactions/InteractionModuleBase.cs @@ -1,4 +1,3 @@ -using Discord.Rest; using System; using System.Collections.Generic; using System.IO; @@ -117,11 +116,16 @@ namespace Discord.Interactions } /// - protected virtual async Task RespondWithModalAsync(Modal modal, RequestOptions options = null) => await Context.Interaction.RespondWithModalAsync(modal); + protected virtual async Task RespondWithModalAsync(Modal modal, RequestOptions options = null) + => await Context.Interaction.RespondWithModalAsync(modal, options); + + /// + protected virtual async Task RespondWithModalAsync(string customId, TModal modal, RequestOptions options = null, Action modifyModal = null) where TModal : class, IModal + => await Context.Interaction.RespondWithModalAsync(customId, modal, options, modifyModal); /// - protected virtual async Task RespondWithModalAsync(string customId, RequestOptions options = null) where TModal : class, IModal - => await Context.Interaction.RespondWithModalAsync(customId, options); + protected virtual async Task RespondWithModalAsync(string customId, RequestOptions options = null, Action modifyModal = null) where TModal : class, IModal + => await Context.Interaction.RespondWithModalAsync(customId, options, modifyModal); /// protected virtual Task RespondWithPremiumRequiredAsync(RequestOptions options = null) diff --git a/src/Discord.Net.Interactions/RestInteractionModuleBase.cs b/src/Discord.Net.Interactions/RestInteractionModuleBase.cs index b570e6d8..bc97d5ed 100644 --- a/src/Discord.Net.Interactions/RestInteractionModuleBase.cs +++ b/src/Discord.Net.Interactions/RestInteractionModuleBase.cs @@ -26,17 +26,7 @@ namespace Discord.Interactions /// /// Thrown if the interaction isn't a type of . protected override async Task DeferAsync(bool ephemeral = false, 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.Defer(ephemeral, options); - - if (Context is IRestInteractionContext restContext && restContext.InteractionResponseCallback != null) - await restContext.InteractionResponseCallback.Invoke(payload).ConfigureAwait(false); - else - await InteractionService._restResponseCallback(Context, payload).ConfigureAwait(false); - } + => await HandleInteractionAsync(x => x.Defer(ephemeral, options)); /// /// Respond to a Rest based Discord Interaction using the delegate. @@ -54,45 +44,55 @@ namespace Discord.Interactions /// /// Thrown if the interaction isn't a type of . protected override async Task RespondAsync(string text = null, Embed[] embeds = null, bool isTTS = false, bool ephemeral = false, AllowedMentions allowedMentions = null, RequestOptions options = null, MessageComponent components = null, Embed embed = 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.Respond(text, embeds, isTTS, ephemeral, allowedMentions, components, embed, options); - - if (Context is IRestInteractionContext restContext && restContext.InteractionResponseCallback != null) - await restContext.InteractionResponseCallback.Invoke(payload).ConfigureAwait(false); - else - await InteractionService._restResponseCallback(Context, payload).ConfigureAwait(false); - } + => await HandleInteractionAsync(x => x.Respond(text, embeds, isTTS, ephemeral, allowedMentions, components, embed, options)); /// /// 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. - /// - /// + /// + /// A Task representing the operation of creating the interaction response. + /// + /// Thrown if the interaction isn't a type of . protected override async Task RespondWithModalAsync(Modal modal, RequestOptions options = null) + => await HandleInteractionAsync(x => x.RespondWithModal(modal, options)); + + /// + /// Responds to the interaction with a modal. + /// + /// The type of the modal. + /// The custom ID of the modal. + /// The modal to respond with. + /// The request options for this request. + /// Delegate that can be used to modify the modal. + /// + /// A Task representing the operation of creating the interaction response. + /// + /// Thrown if the interaction isn't a type of . + protected override async Task RespondWithModalAsync(string customId, TModal modal, RequestOptions options = null, Action modifyModal = null) + => await HandleInteractionAsync(x => x.RespondWithModal(customId, modal, options, modifyModal)); + + /// + /// Responds to the interaction with a modal. + /// + /// + /// The custom ID of the modal. + /// The request options for this request. + /// Delegate that can be used to modify the modal. + /// + /// A Task representing the operation of creating the interaction response. + /// + /// Thrown if the interaction isn't a type of . + protected override async Task RespondWithModalAsync(string customId, RequestOptions options = null, Action modifyModal = null) + => await HandleInteractionAsync(x => x.RespondWithModal(customId, options, modifyModal)); + + private async Task HandleInteractionAsync(Func action) { 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"); + throw new InvalidOperationException($"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); + var payload = action(restInteraction); if (Context is IRestInteractionContext restContext && restContext.InteractionResponseCallback != null) await restContext.InteractionResponseCallback.Invoke(payload).ConfigureAwait(false); diff --git a/src/Discord.Net.Interactions/Utilities/ApplicationCommandRestUtil.cs b/src/Discord.Net.Interactions/Utilities/ApplicationCommandRestUtil.cs index 1d1370cd..acd67a2a 100644 --- a/src/Discord.Net.Interactions/Utilities/ApplicationCommandRestUtil.cs +++ b/src/Discord.Net.Interactions/Utilities/ApplicationCommandRestUtil.cs @@ -296,8 +296,7 @@ namespace Discord.Interactions throw new InvalidOperationException($"{input.GetType().FullName} isn't a valid component info class"); } - if (modifyModal is not null) - modifyModal(builder); + modifyModal?.Invoke(builder); return builder.Build(); } diff --git a/src/Discord.Net.WebSocket/Entities/Interaction/SlashCommands/SocketAutocompleteInteraction.cs b/src/Discord.Net.WebSocket/Entities/Interaction/SlashCommands/SocketAutocompleteInteraction.cs index e0f31e0d..498eece9 100644 --- a/src/Discord.Net.WebSocket/Entities/Interaction/SlashCommands/SocketAutocompleteInteraction.cs +++ b/src/Discord.Net.WebSocket/Entities/Interaction/SlashCommands/SocketAutocompleteInteraction.cs @@ -104,7 +104,7 @@ namespace Discord.WebSocket /// public override Task RespondWithModalAsync(Modal modal, RequestOptions requestOptions = null) - => throw new NotSupportedException("Autocomplete interactions cannot have normal responces!"); + => throw new NotSupportedException("Autocomplete interactions cannot have normal responses!"); //IAutocompleteInteraction ///