From 06321380eed0fe621210a4f1eb712354b0e72970 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Tue, 21 May 2024 00:33:40 +0000 Subject: [PATCH] add: Added .quteedit command add: Added an edit button to .quoteshow and .exprshow commands that opens a modal which lets you edit the quote or expr in question --- .../Modules/Expressions/NadekoExpressions.cs | 91 +++++++++++++------ src/NadekoBot/Modules/Gambling/Gambling.cs | 4 +- .../Modules/Utility/Quote/QuoteCommands.cs | 90 ++++++++++++++++-- src/NadekoBot/Modules/Xp/Xp.cs | 2 +- src/NadekoBot/NadekoBot.csproj | 23 ++--- .../Interaction/INadekoInteractionService.cs | 14 ++- .../Models/NadekoButtonInteraction.cs | 4 +- .../Models/NadekoInteractionExtensions.cs | 4 +- .../Models/NadekoSelectInteraction.cs | 4 +- .../_common/Interaction/NadekoInteraction.cs | 80 +++++++++++++++- .../Interaction/NadekoInteractionService.cs | 42 +++++++-- .../ResponseBuilder.PaginationSender.cs | 8 +- .../_common/Sender/ResponseBuilder.cs | 10 +- .../_common/Sender/ResponseMessageModel.cs | 2 +- src/NadekoBot/data/aliases.yml | 3 + .../data/strings/commands/commands.en-US.yml | 9 ++ .../strings/responses/responses.en-US.json | 1 + 17 files changed, 313 insertions(+), 78 deletions(-) diff --git a/src/NadekoBot/Modules/Expressions/NadekoExpressions.cs b/src/NadekoBot/Modules/Expressions/NadekoExpressions.cs index 22bb3b515..a4ff43e8c 100644 --- a/src/NadekoBot/Modules/Expressions/NadekoExpressions.cs +++ b/src/NadekoBot/Modules/Expressions/NadekoExpressions.cs @@ -1,5 +1,7 @@ #nullable disable +using NadekoBot.Db.Models; + namespace NadekoBot.Modules.NadekoExpressions; [Name("Expressions")] @@ -34,12 +36,12 @@ public partial class NadekoExpressions : NadekoModule await Response() .Embed(_sender.CreateEmbed() - .WithOkColor() - .WithTitle(GetText(strs.expr_new)) - .WithDescription($"#{new kwum(ex.Id)}") - .AddField(GetText(strs.trigger), key) - .AddField(GetText(strs.response), - message.Length > 1024 ? GetText(strs.redacted_too_long) : message)) + .WithOkColor() + .WithTitle(GetText(strs.expr_new)) + .WithDescription($"#{new kwum(ex.Id)}") + .AddField(GetText(strs.trigger), key) + .AddField(GetText(strs.response), + message.Length > 1024 ? GetText(strs.redacted_too_long) : message)) .SendAsync(); } @@ -93,8 +95,7 @@ public partial class NadekoExpressions : NadekoModule return; } - if ((channel is null && !_creds.IsOwner(ctx.User)) - || (channel is not null && !((IGuildUser)ctx.User).GuildPermissions.Administrator)) + if (!IsValidExprEditor()) { await Response().Error(strs.expr_insuff_perms).SendAsync(); return; @@ -105,12 +106,12 @@ public partial class NadekoExpressions : NadekoModule { await Response() .Embed(_sender.CreateEmbed() - .WithOkColor() - .WithTitle(GetText(strs.expr_edited)) - .WithDescription($"#{id}") - .AddField(GetText(strs.trigger), ex.Trigger) - .AddField(GetText(strs.response), - message.Length > 1024 ? GetText(strs.redacted_too_long) : message)) + .WithOkColor() + .WithTitle(GetText(strs.expr_edited)) + .WithDescription($"#{id}") + .AddField(GetText(strs.trigger), ex.Trigger) + .AddField(GetText(strs.response), + message.Length > 1024 ? GetText(strs.redacted_too_long) : message)) .SendAsync(); } else @@ -119,6 +120,10 @@ public partial class NadekoExpressions : NadekoModule } } + private bool IsValidExprEditor() + => (ctx.Guild is not null && ((IGuildUser)ctx.User).GuildPermissions.Administrator) + || (ctx.Guild is null && _creds.IsOwner(ctx.User)); + [Cmd] [Priority(1)] public async Task ExprList(int page = 1) @@ -132,7 +137,7 @@ public partial class NadekoExpressions : NadekoModule .OrderBy(x => x.Trigger) .ToArray(); - if (allExpressions is null || !allExpressions.Any()) + if (!allExpressions.Any()) { await Response().Error(strs.expr_no_found).SendAsync(); return; @@ -171,16 +176,48 @@ public partial class NadekoExpressions : NadekoModule return; } + var inter = CreateEditInteraction(id, found); + await Response() + .Interaction(IsValidExprEditor() ? inter : null) .Embed(_sender.CreateEmbed() - .WithOkColor() - .WithDescription($"#{id}") - .AddField(GetText(strs.trigger), found.Trigger.TrimTo(1024)) - .AddField(GetText(strs.response), - found.Response.TrimTo(1000).Replace("](", "]\\("))) + .WithOkColor() + .WithDescription($"#{id}") + .AddField(GetText(strs.trigger), found.Trigger.TrimTo(1024)) + .AddField(GetText(strs.response), + found.Response.TrimTo(1000).Replace("](", "]\\("))) .SendAsync(); } + private NadekoInteractionBase CreateEditInteraction(kwum id, NadekoExpression found) + { + var modal = new ModalBuilder() + .WithCustomId("expr:edit_modal") + .WithTitle($"Edit expression {id}") + .AddTextInput(new TextInputBuilder() + .WithLabel(GetText(strs.response)) + .WithValue(found.Response) + .WithMinLength(1) + .WithCustomId("expr:edit_modal:response") + .WithStyle(TextInputStyle.Paragraph)); + + var inter = _inter.Create(ctx.User.Id, + new ButtonBuilder() + .WithEmote(Emoji.Parse("📝")) + .WithLabel("Edit") + .WithStyle(ButtonStyle.Primary) + .WithCustomId("test"), + modal, + async (sm) => + { + var msg = sm.Data.Components.FirstOrDefault()?.Value; + + await ExprEdit(id, msg); + } + ); + return inter; + } + public async Task ExprDeleteInternalAsync(kwum id) { var ex = await _service.DeleteAsync(ctx.Guild?.Id, id); @@ -189,11 +226,11 @@ public partial class NadekoExpressions : NadekoModule { await Response() .Embed(_sender.CreateEmbed() - .WithOkColor() - .WithTitle(GetText(strs.expr_deleted)) - .WithDescription($"#{id}") - .AddField(GetText(strs.trigger), ex.Trigger.TrimTo(1024)) - .AddField(GetText(strs.response), ex.Response.TrimTo(1024))) + .WithOkColor() + .WithTitle(GetText(strs.expr_deleted)) + .WithDescription($"#{id}") + .AddField(GetText(strs.trigger), ex.Trigger.TrimTo(1024)) + .AddField(GetText(strs.response), ex.Response.TrimTo(1024))) .SendAsync(); } else @@ -340,8 +377,8 @@ public partial class NadekoExpressions : NadekoModule public async Task ExprClear() { if (await PromptUserConfirmAsync(_sender.CreateEmbed() - .WithTitle("Expression clear") - .WithDescription("This will delete all expressions on this server."))) + .WithTitle("Expression clear") + .WithDescription("This will delete all expressions on this server."))) { var count = _service.DeleteAllExpressions(ctx.Guild.Id); await Response().Confirm(strs.exprs_cleared(count)).SendAsync(); diff --git a/src/NadekoBot/Modules/Gambling/Gambling.cs b/src/NadekoBot/Modules/Gambling/Gambling.cs index 9ccac5dad..bfa085da9 100644 --- a/src/NadekoBot/Modules/Gambling/Gambling.cs +++ b/src/NadekoBot/Modules/Gambling/Gambling.cs @@ -154,7 +154,7 @@ public partial class Gambling : GamblingModule await smc.RespondConfirmAsync(_sender, GetText(strs.remind_timely(tt)), ephemeral: true); } - private NadekoInteraction CreateRemindMeInteraction(int period) + private NadekoInteractionBase CreateRemindMeInteraction(int period) => _inter .Create(ctx.User.Id, new ButtonBuilder( @@ -415,7 +415,7 @@ public partial class Gambling : GamblingModule .Pipe(text => smc.RespondConfirmAsync(_sender, text, ephemeral: true)); } - private NadekoInteraction CreateCashInteraction() + private NadekoInteractionBase CreateCashInteraction() => _inter.Create(ctx.User.Id, new ButtonBuilder( customId: "cash:bank_show_balance", diff --git a/src/NadekoBot/Modules/Utility/Quote/QuoteCommands.cs b/src/NadekoBot/Modules/Utility/Quote/QuoteCommands.cs index 97cf2b591..aba93e516 100644 --- a/src/NadekoBot/Modules/Utility/Quote/QuoteCommands.cs +++ b/src/NadekoBot/Modules/Utility/Quote/QuoteCommands.cs @@ -1,4 +1,6 @@ #nullable disable warnings +using LinqToDB; +using LinqToDB.EntityFrameworkCore; using NadekoBot.Common.Yml; using NadekoBot.Db; using NadekoBot.Db.Models; @@ -133,23 +135,54 @@ public partial class Utility await ShowQuoteData(quote); } - private async Task ShowQuoteData(Quote data) + private NadekoInteractionBase CreateEditInteraction(kwum id, Quote found) { + var modal = new ModalBuilder() + .WithCustomId("quote:edit_modal") + .WithTitle($"Edit expression {id}") + .AddTextInput(new TextInputBuilder() + .WithLabel(GetText(strs.response)) + .WithValue(found.Text) + .WithMinLength(1) + .WithCustomId("quote:edit_modal:response") + .WithStyle(TextInputStyle.Paragraph)); + + var inter = _inter.Create(ctx.User.Id, + new ButtonBuilder() + .WithEmote(Emoji.Parse("📝")) + .WithLabel("Edit") + .WithStyle(ButtonStyle.Primary) + .WithCustomId("test"), + modal, + async (sm) => + { + var msg = sm.Data.Components.FirstOrDefault()?.Value; + + if(!string.IsNullOrWhiteSpace(msg)) + await QuoteEdit(id, msg); + } + ); + return inter; + } + + private async Task ShowQuoteData(Quote quote) + { + var inter = CreateEditInteraction(quote.Id, quote); var eb = _sender.CreateEmbed() .WithOkColor() - .WithTitle($"{GetText(strs.quote_id($"`{new kwum(data.Id)}"))}`") - .WithDescription(Format.Sanitize(data.Text).Replace("](", "]\\(").TrimTo(4096)) - .AddField(GetText(strs.trigger), data.Keyword) + .WithTitle($"{GetText(strs.quote_id($"`{new kwum(quote.Id)}"))}`") + .WithDescription(Format.Sanitize(quote.Text).Replace("](", "]\\(").TrimTo(4096)) + .AddField(GetText(strs.trigger), quote.Keyword) .WithFooter( - GetText(strs.created_by($"{data.AuthorName} ({data.AuthorId})"))); + GetText(strs.created_by($"{quote.AuthorName} ({quote.AuthorId})"))); - if (!(data.Text.Length > 4096)) + if (!(quote.Text.Length > 4096)) { - await Response().Embed(eb).SendAsync(); + await Response().Embed(eb).Interaction(quote.AuthorId == ctx.User.Id ? inter : null).SendAsync(); return; } - await using var textStream = await data.Text.ToStream(); + await using var textStream = await quote.Text.ToStream(); await Response() .Embed(eb) @@ -255,6 +288,47 @@ public partial class Utility await Response().Confirm(strs.quote_added_new(Format.Code(new kwum(q.Id).ToString()))).SendAsync(); } + [Cmd] + [RequireContext(ContextType.Guild)] + public async Task QuoteEdit(kwum quoteId, [Leftover] string text) + { + if (string.IsNullOrWhiteSpace(text)) + { + return; + } + + Quote q; + await using (var uow = _db.GetDbContext()) + { + var intId = (int)quoteId; + var result = await uow.GetTable() + .Where(x => x.Id == intId && x.AuthorId == ctx.User.Id) + .Set(x => x.Text, text) + .UpdateWithOutputAsync((del, ins) => ins); + + q = result.FirstOrDefault(); + + await uow.SaveChangesAsync(); + } + + if (q is not null) + { + await Response() + .Embed(_sender.CreateEmbed() + .WithOkColor() + .WithTitle(GetText(strs.quote_edited)) + .WithDescription($"#{quoteId}") + .AddField(GetText(strs.trigger), q.Keyword) + .AddField(GetText(strs.response), + text.Length > 1024 ? GetText(strs.redacted_too_long) : text)) + .SendAsync(); + } + else + { + await Response().Error(strs.expr_no_found_id).SendAsync(); + } + } + [Cmd] [RequireContext(ContextType.Guild)] public async Task QuoteDelete(kwum quoteId) diff --git a/src/NadekoBot/Modules/Xp/Xp.cs b/src/NadekoBot/Modules/Xp/Xp.cs index dba4afff2..fd9570002 100644 --- a/src/NadekoBot/Modules/Xp/Xp.cs +++ b/src/NadekoBot/Modules/Xp/Xp.cs @@ -506,7 +506,7 @@ public partial class Xp : NadekoModule { var result = await _service.BuyShopItemAsync(ctx.User.Id, (XpShopItemType)type, key); - NadekoInteraction GetUseInteraction() + NadekoInteractionBase GetUseInteraction() { return _inter.Create(ctx.User.Id, new(label: "Use", customId: "xpshop:use_item", emote: Emoji.Parse("👐")), diff --git a/src/NadekoBot/NadekoBot.csproj b/src/NadekoBot/NadekoBot.csproj index 8c8be7dff..a60e6015e 100644 --- a/src/NadekoBot/NadekoBot.csproj +++ b/src/NadekoBot/NadekoBot.csproj @@ -1,5 +1,4 @@  - net8.0 enable @@ -31,9 +30,9 @@ - + - + @@ -52,11 +51,11 @@ - - + + - + @@ -68,14 +67,14 @@ - + - + @@ -100,7 +99,7 @@ - + @@ -109,6 +108,8 @@ + + @@ -131,10 +132,6 @@ - - - - false diff --git a/src/NadekoBot/_common/Interaction/INadekoInteractionService.cs b/src/NadekoBot/_common/Interaction/INadekoInteractionService.cs index 88c2eb246..b3955bc2e 100644 --- a/src/NadekoBot/_common/Interaction/INadekoInteractionService.cs +++ b/src/NadekoBot/_common/Interaction/INadekoInteractionService.cs @@ -2,22 +2,30 @@ public interface INadekoInteractionService { - public NadekoInteraction Create( + public NadekoInteractionBase Create( ulong userId, ButtonBuilder button, Func onTrigger, bool singleUse = true); - public NadekoInteraction Create( + public NadekoInteractionBase Create( ulong userId, ButtonBuilder button, Func onTrigger, in T state, bool singleUse = true); - NadekoInteraction Create( + NadekoInteractionBase Create( ulong userId, SelectMenuBuilder menu, Func onTrigger, bool singleUse = true); + + NadekoInteractionBase Create( + ulong userId, + ButtonBuilder button, + ModalBuilder modal, + Func onTrigger, + bool singleUse = true); + } \ No newline at end of file diff --git a/src/NadekoBot/_common/Interaction/Models/NadekoButtonInteraction.cs b/src/NadekoBot/_common/Interaction/Models/NadekoButtonInteraction.cs index f1fd2cd61..9cb2cd8e8 100644 --- a/src/NadekoBot/_common/Interaction/Models/NadekoButtonInteraction.cs +++ b/src/NadekoBot/_common/Interaction/Models/NadekoButtonInteraction.cs @@ -1,8 +1,8 @@ namespace NadekoBot; -public sealed class NadekoButtonInteraction : NadekoInteraction +public sealed class NadekoButtonInteractionHandler : NadekoInteractionBase { - public NadekoButtonInteraction( + public NadekoButtonInteractionHandler( DiscordSocketClient client, ulong authorId, ButtonBuilder button, diff --git a/src/NadekoBot/_common/Interaction/Models/NadekoInteractionExtensions.cs b/src/NadekoBot/_common/Interaction/Models/NadekoInteractionExtensions.cs index dff0ed2f8..f775127cd 100644 --- a/src/NadekoBot/_common/Interaction/Models/NadekoInteractionExtensions.cs +++ b/src/NadekoBot/_common/Interaction/Models/NadekoInteractionExtensions.cs @@ -3,12 +3,12 @@ public static class NadekoInteractionExtensions { public static MessageComponent CreateComponent( - this NadekoInteraction nadekoInteraction + this NadekoInteractionBase nadekoInteractionBase ) { var cb = new ComponentBuilder(); - nadekoInteraction.AddTo(cb); + nadekoInteractionBase.AddTo(cb); return cb.Build(); } diff --git a/src/NadekoBot/_common/Interaction/Models/NadekoSelectInteraction.cs b/src/NadekoBot/_common/Interaction/Models/NadekoSelectInteraction.cs index 3bdef588a..5d668c384 100644 --- a/src/NadekoBot/_common/Interaction/Models/NadekoSelectInteraction.cs +++ b/src/NadekoBot/_common/Interaction/Models/NadekoSelectInteraction.cs @@ -1,8 +1,8 @@ namespace NadekoBot; -public sealed class NadekoSelectInteraction : NadekoInteraction +public sealed class NadekoButtonSelectInteractionHandler : NadekoInteractionBase { - public NadekoSelectInteraction( + public NadekoButtonSelectInteractionHandler( DiscordSocketClient client, ulong authorId, SelectMenuBuilder menu, diff --git a/src/NadekoBot/_common/Interaction/NadekoInteraction.cs b/src/NadekoBot/_common/Interaction/NadekoInteraction.cs index 29936c0b3..e8734be9a 100644 --- a/src/NadekoBot/_common/Interaction/NadekoInteraction.cs +++ b/src/NadekoBot/_common/Interaction/NadekoInteraction.cs @@ -1,6 +1,6 @@ namespace NadekoBot; -public abstract class NadekoInteraction +public abstract class NadekoInteractionBase { private readonly ulong _authorId; private readonly Func _onAction; @@ -13,7 +13,7 @@ public abstract class NadekoInteraction private readonly string _customId; private readonly bool _singleUse; - public NadekoInteraction( + public NadekoInteractionBase( DiscordSocketClient client, ulong authorId, string customId, @@ -85,4 +85,80 @@ public abstract class NadekoInteraction public Task ExecuteOnActionAsync(SocketMessageComponent smc) => _onAction(smc); +} + +public sealed class NadekoModalSubmitHandler +{ + private readonly ulong _authorId; + private readonly Func _onAction; + private readonly bool _onlyAuthor; + public DiscordSocketClient Client { get; } + + private readonly TaskCompletionSource _interactionCompletedSource; + + private IUserMessage message = null!; + private readonly string _customId; + + public NadekoModalSubmitHandler( + DiscordSocketClient client, + ulong authorId, + string customId, + Func onAction, + bool onlyAuthor) + { + _authorId = authorId; + _customId = customId; + _onAction = onAction; + _onlyAuthor = onlyAuthor; + _interactionCompletedSource = new(TaskCreationOptions.RunContinuationsAsynchronously); + + Client = client; + } + + public async Task RunAsync(IUserMessage msg) + { + message = msg; + + Client.ModalSubmitted += OnInteraction; + await Task.WhenAny(Task.Delay(300_000), _interactionCompletedSource.Task); + Client.ModalSubmitted -= OnInteraction; + + await msg.ModifyAsync(m => m.Components = new ComponentBuilder().Build()); + } + + private Task OnInteraction(SocketModal sm) + { + if (sm.Message.Id != message.Id) + return Task.CompletedTask; + + if (_onlyAuthor && sm.User.Id != _authorId) + return Task.CompletedTask; + + if (sm.Data.CustomId != _customId) + return Task.CompletedTask; + + _ = Task.Run(async () => + { + try + { + _interactionCompletedSource.TrySetResult(true); + await ExecuteOnActionAsync(sm); + + if (!sm.HasResponded) + { + await sm.DeferAsync(); + } + } + catch (Exception ex) + { + Log.Warning(ex, "An exception occured while handling a: {Message}", ex.Message); + } + }); + + return Task.CompletedTask; + } + + + public Task ExecuteOnActionAsync(SocketModal smd) + => _onAction(smd); } \ No newline at end of file diff --git a/src/NadekoBot/_common/Interaction/NadekoInteractionService.cs b/src/NadekoBot/_common/Interaction/NadekoInteractionService.cs index d6c0f9702..8956758e6 100644 --- a/src/NadekoBot/_common/Interaction/NadekoInteractionService.cs +++ b/src/NadekoBot/_common/Interaction/NadekoInteractionService.cs @@ -9,19 +9,19 @@ public class NadekoInteractionService : INadekoInteractionService, INService _client = client; } - public NadekoInteraction Create( + public NadekoInteractionBase Create( ulong userId, ButtonBuilder button, Func onTrigger, bool singleUse = true) - => new NadekoButtonInteraction(_client, + => new NadekoButtonInteractionHandler(_client, userId, button, onTrigger, onlyAuthor: true, singleUse: singleUse); - public NadekoInteraction Create( + public NadekoInteractionBase Create( ulong userId, ButtonBuilder button, Func onTrigger, @@ -32,16 +32,46 @@ public class NadekoInteractionService : INadekoInteractionService, INService ((Func>)((data) => smc => onTrigger(smc, data)))(state), singleUse); - - public NadekoInteraction Create( + + public NadekoInteractionBase Create( ulong userId, SelectMenuBuilder menu, Func onTrigger, bool singleUse = true) - => new NadekoSelectInteraction(_client, + => new NadekoButtonSelectInteractionHandler(_client, userId, menu, onTrigger, onlyAuthor: true, singleUse: singleUse); + + + /// + /// Create an interaction which opens a modal + /// + /// Id of the author + /// Button builder for the button that will open the modal + /// Modal + /// The function that will be called when the modal is submitted + /// Whether the button is single use + /// + public NadekoInteractionBase Create( + ulong userId, + ButtonBuilder button, + ModalBuilder modal, + Func onTrigger, + bool singleUse = true) + => Create(userId, + button, + async (smc) => + { + await smc.RespondWithModalAsync(modal.Build()); + var modalHandler = new NadekoModalSubmitHandler(_client, + userId, + modal.CustomId, + onTrigger, + true); + await modalHandler.RunAsync(smc.Message); + }, + singleUse: singleUse); } \ No newline at end of file diff --git a/src/NadekoBot/_common/Sender/ResponseBuilder.PaginationSender.cs b/src/NadekoBot/_common/Sender/ResponseBuilder.PaginationSender.cs index ea43c15ad..4048fa268 100644 --- a/src/NadekoBot/_common/Sender/ResponseBuilder.PaginationSender.cs +++ b/src/NadekoBot/_common/Sender/ResponseBuilder.PaginationSender.cs @@ -34,11 +34,11 @@ public partial class ResponseBuilder if (_paginationBuilder.AddPaginatedFooter) embed.AddPaginatedFooter(currentPage, lastPage); - NadekoInteraction? maybeInter = null; + NadekoInteractionBase? maybeInter = null; var model = await _builder.BuildAsync(ephemeral); - async Task<(NadekoButtonInteraction left, NadekoInteraction? extra, NadekoButtonInteraction right)> + async Task<(NadekoButtonInteractionHandler left, NadekoInteractionBase? extra, NadekoButtonInteractionHandler right)> GetInteractions() { var leftButton = new ButtonBuilder() @@ -47,7 +47,7 @@ public partial class ResponseBuilder .WithEmote(InteractionHelpers.ArrowLeft) .WithDisabled(lastPage == 0 || currentPage <= 0); - var leftBtnInter = new NadekoButtonInteraction(_client, + var leftBtnInter = new NadekoButtonInteractionHandler(_client, model.User?.Id ?? 0, leftButton, (smc) => @@ -80,7 +80,7 @@ public partial class ResponseBuilder .WithEmote(InteractionHelpers.ArrowRight) .WithDisabled(lastPage == 0 || currentPage >= lastPage); - var rightBtnInter = new NadekoButtonInteraction(_client, + var rightBtnInter = new NadekoButtonInteractionHandler(_client, model.User?.Id ?? 0, rightButton, (smc) => diff --git a/src/NadekoBot/_common/Sender/ResponseBuilder.cs b/src/NadekoBot/_common/Sender/ResponseBuilder.cs index 2031be96f..84c1b026b 100644 --- a/src/NadekoBot/_common/Sender/ResponseBuilder.cs +++ b/src/NadekoBot/_common/Sender/ResponseBuilder.cs @@ -19,7 +19,7 @@ public sealed partial class ResponseBuilder private readonly IBotStrings _bs; private readonly BotConfigService _bcs; private EmbedBuilder? embedBuilder; - private NadekoInteraction? inter; + private NadekoInteractionBase? inter; private Stream? fileStream; private string? fileName; private EmbedColor color = EmbedColor.Ok; @@ -340,7 +340,7 @@ public sealed partial class ResponseBuilder return this; } - public ResponseBuilder Interaction(NadekoInteraction? interaction) + public ResponseBuilder Interaction(NadekoInteractionBase? interaction) { inter = interaction; return this; @@ -395,7 +395,7 @@ public sealed class SourcedPaginatedResponseBuilder : PaginatedResponseBuilde return Task.FromResult>(ReadOnlyCollection.Empty); }; - public Func>? InteractionFunc { get; private set; } + public Func>? InteractionFunc { get; private set; } public int? Elems { get; private set; } = 1; public int ItemsPerPage { get; private set; } = 9; @@ -478,13 +478,13 @@ public sealed class SourcedPaginatedResponseBuilder : PaginatedResponseBuilde return paginationSender.SendAsync(IsEphemeral); } - public SourcedPaginatedResponseBuilder Interaction(Func> func) + public SourcedPaginatedResponseBuilder Interaction(Func> func) { InteractionFunc = func; //async (i) => await func(i); return this; } - public SourcedPaginatedResponseBuilder Interaction(NadekoInteraction inter) + public SourcedPaginatedResponseBuilder Interaction(NadekoInteractionBase inter) { InteractionFunc = _ => Task.FromResult(inter); return this; diff --git a/src/NadekoBot/_common/Sender/ResponseMessageModel.cs b/src/NadekoBot/_common/Sender/ResponseMessageModel.cs index 592b18e9d..7c8fb6040 100644 --- a/src/NadekoBot/_common/Sender/ResponseMessageModel.cs +++ b/src/NadekoBot/_common/Sender/ResponseMessageModel.cs @@ -8,5 +8,5 @@ public required AllowedMentions SanitizeMentions { get; set; } public IUser? User { get; set; } public bool Ephemeral { get; set; } - public NadekoInteraction? Interaction { get; set; } + public NadekoInteractionBase? Interaction { get; set; } } \ No newline at end of file diff --git a/src/NadekoBot/data/aliases.yml b/src/NadekoBot/data/aliases.yml index 8b02fbfb0..7cd878f96 100644 --- a/src/NadekoBot/data/aliases.yml +++ b/src/NadekoBot/data/aliases.yml @@ -341,6 +341,9 @@ allcmdcooldowns: quoteadd: - quoteadd - . +quoteedit: + - quoteedit + - qedit quoteprint: - quoteprint - .. diff --git a/src/NadekoBot/data/strings/commands/commands.en-US.yml b/src/NadekoBot/data/strings/commands/commands.en-US.yml index e4dbd8e1f..b0f51c72d 100644 --- a/src/NadekoBot/data/strings/commands/commands.en-US.yml +++ b/src/NadekoBot/data/strings/commands/commands.en-US.yml @@ -1245,6 +1245,15 @@ quoteadd: desc: "The name of the quote used to retrieve the quote." text: desc: "The message of the quote." +quoteedit: + desc: Edits a quote with the specified ID. + ex: + - 55 This is the new response. + params: + - quoteId: + desc: "The ID of the quote being edited." + text: + desc: "The new message of the quote." quoteprint: desc: Prints a random quote with a specified name. ex: diff --git a/src/NadekoBot/data/strings/responses/responses.en-US.json b/src/NadekoBot/data/strings/responses/responses.en-US.json index 24303ffe5..7fd3434bb 100644 --- a/src/NadekoBot/data/strings/responses/responses.en-US.json +++ b/src/NadekoBot/data/strings/responses/responses.en-US.json @@ -617,6 +617,7 @@ "quotes_remove_none": "No quotes found which you can remove.", "quote_added_new": "Quote #{0} added.", "quote_deleted": "Quote #{0} deleted.", + "quote_edited": "Quote Edited", "region": "Region", "remind": "I will remind {0} to {1} in {2} `({3:d.M.yyyy.} at {4:HH:mm})`", "remind_timely": "I will remind you about your timely reward {0}",