.prune improved
This commit is contained in:
		@@ -9,7 +9,6 @@ using NadekoBot.Services;
 | 
			
		||||
using NadekoBot.Attributes;
 | 
			
		||||
using NadekoBot.Services.Database.Models;
 | 
			
		||||
using NadekoBot.Services.Administration;
 | 
			
		||||
using Discord.WebSocket;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Modules.Administration
 | 
			
		||||
{
 | 
			
		||||
@@ -311,67 +310,6 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
            await ReplyConfirmLocalized("set_channel_name").ConfigureAwait(false);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        //delets her own messages, no perm required
 | 
			
		||||
        [NadekoCommand, Usage, Description, Aliases]
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task Prune()
 | 
			
		||||
        {
 | 
			
		||||
            var user = await Context.Guild.GetCurrentUserAsync().ConfigureAwait(false);
 | 
			
		||||
 | 
			
		||||
            var enumerable = (await Context.Channel.GetMessagesAsync().Flatten())
 | 
			
		||||
                .Where(x => x.Author.Id == user.Id && DateTime.UtcNow - x.CreatedAt < twoWeeks);
 | 
			
		||||
            await Context.Channel.DeleteMessagesAsync(enumerable).ConfigureAwait(false);
 | 
			
		||||
            Context.Message.DeleteAfter(3);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        private TimeSpan twoWeeks => TimeSpan.FromDays(14);
 | 
			
		||||
        // prune x
 | 
			
		||||
        [NadekoCommand, Usage, Description, Aliases]
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        [RequireUserPermission(ChannelPermission.ManageMessages)]
 | 
			
		||||
        [RequireBotPermission(GuildPermission.ManageMessages)]
 | 
			
		||||
        [Priority(0)]
 | 
			
		||||
        public async Task Prune(int count)
 | 
			
		||||
        {
 | 
			
		||||
            if (count < 1)
 | 
			
		||||
                return;
 | 
			
		||||
            await Context.Message.DeleteAsync().ConfigureAwait(false);
 | 
			
		||||
            int limit = (count < 100) ? count + 1 : 100;
 | 
			
		||||
            var enumerable = (await Context.Channel.GetMessagesAsync(limit: limit).Flatten().ConfigureAwait(false))
 | 
			
		||||
                .Where(x => DateTime.UtcNow - x.CreatedAt < twoWeeks);
 | 
			
		||||
            if (enumerable.FirstOrDefault()?.Id == Context.Message.Id)
 | 
			
		||||
                enumerable = enumerable.Skip(1).ToArray();
 | 
			
		||||
            else
 | 
			
		||||
                enumerable = enumerable.Take(count);
 | 
			
		||||
            await Context.Channel.DeleteMessagesAsync(enumerable).ConfigureAwait(false);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //prune @user [x]
 | 
			
		||||
        [NadekoCommand, Usage, Description, Aliases]
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        [RequireUserPermission(ChannelPermission.ManageMessages)]
 | 
			
		||||
        [RequireBotPermission(GuildPermission.ManageMessages)]
 | 
			
		||||
        [Priority(1)]
 | 
			
		||||
        public async Task Prune(IGuildUser user, int count = 100)
 | 
			
		||||
        {
 | 
			
		||||
            if (count < 1)
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            if (count > 100)
 | 
			
		||||
                count = 100;
 | 
			
		||||
 | 
			
		||||
            if (user.Id == Context.User.Id)
 | 
			
		||||
                count += 1;
 | 
			
		||||
            var enumerable = (await Context.Channel.GetMessagesAsync().Flatten())
 | 
			
		||||
                .Where(m => m.Author.Id == user.Id && DateTime.UtcNow - m.CreatedAt < twoWeeks)
 | 
			
		||||
                .Take(count);
 | 
			
		||||
            await Context.Channel.DeleteMessagesAsync(enumerable).ConfigureAwait(false);
 | 
			
		||||
 | 
			
		||||
            Context.Message.DeleteAfter(3);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [NadekoCommand, Usage, Description, Aliases]
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        [RequireUserPermission(GuildPermission.MentionEveryone)]
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,70 @@
 | 
			
		||||
using Discord;
 | 
			
		||||
using Discord.Commands;
 | 
			
		||||
using NadekoBot.Attributes;
 | 
			
		||||
using NadekoBot.Extensions;
 | 
			
		||||
using NadekoBot.Services.Administration;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Modules.Administration
 | 
			
		||||
{
 | 
			
		||||
    public partial class Administration
 | 
			
		||||
    {
 | 
			
		||||
        [Group]
 | 
			
		||||
        public class PruneCommands : ModuleBase
 | 
			
		||||
        {
 | 
			
		||||
            private readonly TimeSpan twoWeeks = TimeSpan.FromDays(14);
 | 
			
		||||
            private readonly PruneService _prune;
 | 
			
		||||
 | 
			
		||||
            public PruneCommands(PruneService prune)
 | 
			
		||||
            {
 | 
			
		||||
                _prune = prune;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            //delets her own messages, no perm required
 | 
			
		||||
            [NadekoCommand, Usage, Description, Aliases]
 | 
			
		||||
            [RequireContext(ContextType.Guild)]
 | 
			
		||||
            public async Task Prune()
 | 
			
		||||
            {
 | 
			
		||||
                var user = await Context.Guild.GetCurrentUserAsync().ConfigureAwait(false);
 | 
			
		||||
 | 
			
		||||
                await _prune.PruneWhere((ITextChannel)Context.Channel, 100, (x) => x.Author.Id == user.Id).ConfigureAwait(false);
 | 
			
		||||
                Context.Message.DeleteAfter(3);
 | 
			
		||||
            }
 | 
			
		||||
            // prune x
 | 
			
		||||
            [NadekoCommand, Usage, Description, Aliases]
 | 
			
		||||
            [RequireContext(ContextType.Guild)]
 | 
			
		||||
            [RequireUserPermission(ChannelPermission.ManageMessages)]
 | 
			
		||||
            [RequireBotPermission(GuildPermission.ManageMessages)]
 | 
			
		||||
            [Priority(0)]
 | 
			
		||||
            public async Task Prune(int count)
 | 
			
		||||
            {
 | 
			
		||||
                if (count < 1)
 | 
			
		||||
                    return;
 | 
			
		||||
                if (count > 1000)
 | 
			
		||||
                    count = 1000;
 | 
			
		||||
                await Context.Message.DeleteAsync().ConfigureAwait(false);
 | 
			
		||||
                await _prune.PruneWhere((ITextChannel)Context.Channel, count, x => true).ConfigureAwait(false);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            //prune @user [x]
 | 
			
		||||
            [NadekoCommand, Usage, Description, Aliases]
 | 
			
		||||
            [RequireContext(ContextType.Guild)]
 | 
			
		||||
            [RequireUserPermission(ChannelPermission.ManageMessages)]
 | 
			
		||||
            [RequireBotPermission(GuildPermission.ManageMessages)]
 | 
			
		||||
            [Priority(1)]
 | 
			
		||||
            public async Task Prune(IGuildUser user, int count = 100)
 | 
			
		||||
            {
 | 
			
		||||
                if (count < 1)
 | 
			
		||||
                    return;
 | 
			
		||||
 | 
			
		||||
                if (count > 1000)
 | 
			
		||||
                    count = 1000;
 | 
			
		||||
                await _prune.PruneWhere((ITextChannel)Context.Channel, count, m => m.Author.Id == user.Id && DateTime.UtcNow - m.CreatedAt < twoWeeks);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -121,8 +121,10 @@ namespace NadekoBot.Modules
 | 
			
		||||
                        return Task.CompletedTask;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    userInputTask.SetResult(arg.Content);
 | 
			
		||||
                    userMsg.DeleteAfter(1);
 | 
			
		||||
                    if (userInputTask.TrySetResult(arg.Content))
 | 
			
		||||
                    {
 | 
			
		||||
                        userMsg.DeleteAfter(1);
 | 
			
		||||
                    }
 | 
			
		||||
                    return Task.CompletedTask;
 | 
			
		||||
                });
 | 
			
		||||
                return Task.CompletedTask;
 | 
			
		||||
 
 | 
			
		||||
@@ -92,7 +92,7 @@ namespace NadekoBot
 | 
			
		||||
            CommandService = new CommandService(new CommandServiceConfig()
 | 
			
		||||
            {
 | 
			
		||||
                CaseSensitiveCommands = false,
 | 
			
		||||
                DefaultRunMode = RunMode.Sync,
 | 
			
		||||
                DefaultRunMode = RunMode.Async,
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            //foundation services
 | 
			
		||||
@@ -127,6 +127,7 @@ namespace NadekoBot
 | 
			
		||||
            var commandMapService = new CommandMapService(AllGuildConfigs);
 | 
			
		||||
            var patreonRewardsService = new PatreonRewardsService(Credentials, Db, Currency);
 | 
			
		||||
            var verboseErrorsService = new VerboseErrorsService(AllGuildConfigs, Db, CommandHandler, helpService);
 | 
			
		||||
            var pruneService = new PruneService();
 | 
			
		||||
            #endregion
 | 
			
		||||
 | 
			
		||||
            #region permissions
 | 
			
		||||
@@ -197,6 +198,7 @@ namespace NadekoBot
 | 
			
		||||
                    .Add(converterService)
 | 
			
		||||
                    .Add(verboseErrorsService)
 | 
			
		||||
                    .Add(patreonRewardsService)
 | 
			
		||||
                    .Add(pruneService)
 | 
			
		||||
                .Add<SearchesService>(searchesService)
 | 
			
		||||
                    .Add(streamNotificationService)
 | 
			
		||||
                    .Add(animeSearchService)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										68
									
								
								src/NadekoBot/Services/Administration/PruneService.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								src/NadekoBot/Services/Administration/PruneService.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,68 @@
 | 
			
		||||
using Discord;
 | 
			
		||||
using NadekoBot.Extensions;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Concurrent;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Services.Administration
 | 
			
		||||
{
 | 
			
		||||
    public class PruneService
 | 
			
		||||
    {
 | 
			
		||||
        //channelids where prunes are currently occuring
 | 
			
		||||
        private ConcurrentHashSet<ulong> _pruningChannels = new ConcurrentHashSet<ulong>();
 | 
			
		||||
        private readonly TimeSpan twoWeeks = TimeSpan.FromDays(14);
 | 
			
		||||
 | 
			
		||||
        public async Task PruneWhere(ITextChannel channel, int amount, Func<IMessage, bool> predicate)
 | 
			
		||||
        {
 | 
			
		||||
            channel.ThrowIfNull(nameof(channel));
 | 
			
		||||
            if (amount <= 0)
 | 
			
		||||
                throw new ArgumentOutOfRangeException(nameof(amount));
 | 
			
		||||
 | 
			
		||||
            if (!_pruningChannels.Add(channel.Id))
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                IMessage[] msgs;
 | 
			
		||||
                IMessage lastMessage = null;
 | 
			
		||||
                msgs = (await channel.GetMessagesAsync(amount > 100 ? 100 : amount).Flatten()).Where(predicate).ToArray();
 | 
			
		||||
                while (amount > 0 && msgs.Any())
 | 
			
		||||
                {
 | 
			
		||||
                    lastMessage = msgs[msgs.Length - 1];
 | 
			
		||||
 | 
			
		||||
                    var bulkDeletable = new List<IMessage>();
 | 
			
		||||
                    var singleDeletable = new List<IMessage>();
 | 
			
		||||
                    foreach (var x in msgs)
 | 
			
		||||
                    {
 | 
			
		||||
                        if (DateTime.UtcNow - x.CreatedAt < twoWeeks)
 | 
			
		||||
                            bulkDeletable.Add(x);
 | 
			
		||||
                        else
 | 
			
		||||
                            singleDeletable.Add(x);
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    if (bulkDeletable.Count > 0)
 | 
			
		||||
                        await Task.WhenAll(Task.Delay(1000), channel.DeleteMessagesAsync(bulkDeletable)).ConfigureAwait(false);
 | 
			
		||||
 | 
			
		||||
                    var i = 0;
 | 
			
		||||
                    foreach (var group in singleDeletable.GroupBy(x => ++i / (singleDeletable.Count / 5)))
 | 
			
		||||
                        await Task.WhenAll(Task.Delay(1000), Task.WhenAll(group.Select(x => x.DeleteAsync()))).ConfigureAwait(false);
 | 
			
		||||
 | 
			
		||||
                    amount -= 100;
 | 
			
		||||
                    if(amount > 0)
 | 
			
		||||
                        msgs = (await channel.GetMessagesAsync(lastMessage, Direction.Before, amount > 100 ? 100 : amount).Flatten()).Where(predicate).ToArray();
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            catch (Exception ex)
 | 
			
		||||
            {
 | 
			
		||||
 | 
			
		||||
            }
 | 
			
		||||
            finally
 | 
			
		||||
            {
 | 
			
		||||
                _pruningChannels.TryRemove(channel.Id);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user