diff --git a/src/NadekoBot/Modules/Administration/Prune/PruneCommands.cs b/src/NadekoBot/Modules/Administration/Prune/PruneCommands.cs index 4468dd6f0..85c44dad6 100644 --- a/src/NadekoBot/Modules/Administration/Prune/PruneCommands.cs +++ b/src/NadekoBot/Modules/Administration/Prune/PruneCommands.cs @@ -1,4 +1,5 @@ #nullable disable +using CommandLine; using NadekoBot.Modules.Administration.Services; namespace NadekoBot.Modules.Administration; @@ -10,17 +11,34 @@ public partial class Administration { private static readonly TimeSpan _twoWeeks = TimeSpan.FromDays(14); - //delets her own messages, no perm required + public sealed class PruneOptions : INadekoCommandOptions + { + [Option(shortName: 's', longName: "safe", Default = false, HelpText = "Whether pinned messages should be deleted.", Required = false)] + public bool Safe { get; set; } + + [Option(shortName: 'a', longName: "after", Default = null, HelpText = "Prune only messages after the specified message ID.", Required = false)] + public ulong? After { get; set; } + + public void NormalizeOptions() + { + } + } + + //deletes her own messages, no perm required [Cmd] [RequireContext(ContextType.Guild)] - public async Task Prune(string parameter = null) + [NadekoOptions(typeof(PruneOptions))] + public async Task Prune(params string[] args) { + var (opts, _) = OptionsParser.ParseFrom(new PruneOptions(), args); + var user = await ctx.Guild.GetCurrentUserAsync(); - if (parameter is "-s" or "--safe") - await _service.PruneWhere((ITextChannel)ctx.Channel, 100, x => x.Author.Id == user.Id && !x.IsPinned); + if (opts.Safe) + await _service.PruneWhere((ITextChannel)ctx.Channel, 100, x => x.Author.Id == user.Id && !x.IsPinned, opts.After); else - await _service.PruneWhere((ITextChannel)ctx.Channel, 100, x => x.Author.Id == user.Id); + await _service.PruneWhere((ITextChannel)ctx.Channel, 100, x => x.Author.Id == user.Id, opts.After); + ctx.Message.DeleteAfter(3); } @@ -29,19 +47,22 @@ public partial class Administration [RequireContext(ContextType.Guild)] [UserPerm(ChannelPerm.ManageMessages)] [BotPerm(ChannelPerm.ManageMessages)] + [NadekoOptions(typeof(PruneOptions))] [Priority(1)] - public async Task Prune(int count, string parameter = null) + public async Task Prune(int count, params string[] args) { count++; if (count < 1) return; if (count > 1000) count = 1000; + + var (opts, _) = OptionsParser.ParseFrom(new PruneOptions(), args); - if (parameter is "-s" or "--safe") - await _service.PruneWhere((ITextChannel)ctx.Channel, count, x => !x.IsPinned); + if (opts.Safe) + await _service.PruneWhere((ITextChannel)ctx.Channel, count, x => !x.IsPinned, opts.After); else - await _service.PruneWhere((ITextChannel)ctx.Channel, count, _ => true); + await _service.PruneWhere((ITextChannel)ctx.Channel, count, _ => true, opts.After); } //prune @user [x] @@ -49,17 +70,19 @@ public partial class Administration [RequireContext(ContextType.Guild)] [UserPerm(ChannelPerm.ManageMessages)] [BotPerm(ChannelPerm.ManageMessages)] + [NadekoOptions(typeof(PruneOptions))] [Priority(0)] - public Task Prune(IGuildUser user, int count = 100, string parameter = null) - => Prune(user.Id, count, parameter); + public Task Prune(IGuildUser user, int count = 100, string args = null) + => Prune(user.Id, count, args); //prune userid [x] [Cmd] [RequireContext(ContextType.Guild)] [UserPerm(ChannelPerm.ManageMessages)] [BotPerm(ChannelPerm.ManageMessages)] + [NadekoOptions(typeof(PruneOptions))] [Priority(0)] - public async Task Prune(ulong userId, int count = 100, string parameter = null) + public async Task Prune(ulong userId, int count = 100, params string[] args) { if (userId == ctx.User.Id) count++; @@ -70,17 +93,21 @@ public partial class Administration if (count > 1000) count = 1000; - if (parameter is "-s" or "--safe") + var (opts, _) = OptionsParser.ParseFrom(new PruneOptions(), args); + + if (opts.Safe) { await _service.PruneWhere((ITextChannel)ctx.Channel, count, - m => m.Author.Id == userId && DateTime.UtcNow - m.CreatedAt < _twoWeeks && !m.IsPinned); + m => m.Author.Id == userId && DateTime.UtcNow - m.CreatedAt < _twoWeeks && !m.IsPinned, + opts.After); } else { await _service.PruneWhere((ITextChannel)ctx.Channel, count, - m => m.Author.Id == userId && DateTime.UtcNow - m.CreatedAt < _twoWeeks); + m => m.Author.Id == userId && DateTime.UtcNow - m.CreatedAt < _twoWeeks, + opts.After); } } } diff --git a/src/NadekoBot/Modules/Administration/Prune/PruneService.cs b/src/NadekoBot/Modules/Administration/Prune/PruneService.cs index 3f9aafd12..100e14374 100644 --- a/src/NadekoBot/Modules/Administration/Prune/PruneService.cs +++ b/src/NadekoBot/Modules/Administration/Prune/PruneService.cs @@ -1,6 +1,4 @@ #nullable disable -using Nadeko.Common; - namespace NadekoBot.Modules.Administration.Services; public class PruneService : INService @@ -13,7 +11,7 @@ public class PruneService : INService public PruneService(ILogCommandService logService) => _logService = logService; - public async Task PruneWhere(ITextChannel channel, int amount, Func predicate) + public async Task PruneWhere(ITextChannel channel, int amount, Func predicate, ulong? after = null) { ArgumentNullException.ThrowIfNull(channel, nameof(channel)); @@ -28,7 +26,14 @@ public class PruneService : INService var now = DateTime.UtcNow; IMessage[] msgs; IMessage lastMessage = null; - msgs = (await channel.GetMessagesAsync(50).FlattenAsync()).Where(predicate).Take(amount).ToArray(); + var dled = await channel.GetMessagesAsync(50).FlattenAsync(); + + msgs = dled + .Where(predicate) + .Where(x => after is ulong a ? x.Id > a : true) + .Take(amount) + .ToArray(); + while (amount > 0 && msgs.Any()) { lastMessage = msgs[^1]; @@ -62,10 +67,13 @@ public class PruneService : INService amount -= 50; if (amount > 0) { - msgs = (await channel.GetMessagesAsync(lastMessage, Direction.Before, 50).FlattenAsync()) - .Where(predicate) - .Take(amount) - .ToArray(); + dled = await channel.GetMessagesAsync(lastMessage, Direction.Before, 50).FlattenAsync(); + + msgs = dled + .Where(predicate) + .Where(x => after is ulong a ? x.Id > a : true) + .Take(amount) + .ToArray(); } } }