diff --git a/NadekoBot.Core/Modules/Administration/Administration.cs b/NadekoBot.Core/Modules/Administration/Administration.cs index 9f3c92c9..bafd390a 100644 --- a/NadekoBot.Core/Modules/Administration/Administration.cs +++ b/NadekoBot.Core/Modules/Administration/Administration.cs @@ -261,7 +261,7 @@ namespace NadekoBot.Modules.Administration public async Task CreatVoiChanl([Remainder] string channelName) { var ch = await Context.Guild.CreateVoiceChannelAsync(channelName).ConfigureAwait(false); - await ReplyConfirmLocalized("createvoich",Format.Bold(ch.Name)).ConfigureAwait(false); + await ReplyConfirmLocalized("createvoich", Format.Bold(ch.Name)).ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] @@ -312,7 +312,7 @@ namespace NadekoBot.Modules.Administration [RequireUserPermission(GuildPermission.MentionEveryone)] public async Task MentionRole(params IRole[] roles) { - string send = "❕" +GetText("menrole",Context.User.Mention); + string send = "❕" + GetText("menrole", Context.User.Mention); foreach (var role in roles) { send += $"\n**{role.Name}**\n"; diff --git a/NadekoBot.Core/Modules/Administration/UserPunishCommands.cs b/NadekoBot.Core/Modules/Administration/UserPunishCommands.cs index 1303e4e2..35f5629f 100644 --- a/NadekoBot.Core/Modules/Administration/UserPunishCommands.cs +++ b/NadekoBot.Core/Modules/Administration/UserPunishCommands.cs @@ -18,10 +18,15 @@ namespace NadekoBot.Modules.Administration public class UserPunishCommands : NadekoSubmodule { private readonly DbService _db; + private readonly CurrencyService _cs; + private readonly IBotConfigProvider _bc; - public UserPunishCommands(DbService db, MuteService muteService) + public UserPunishCommands(DbService db, MuteService muteService, + CurrencyService cs, IBotConfigProvider bc) { _db = db; + _cs = cs; + _bc = bc; } [NadekoCommand, Usage, Description, Aliases] @@ -101,7 +106,7 @@ namespace NadekoBot.Modules.Administration var embed = new EmbedBuilder().WithOkColor() .WithTitle(GetText("warnlog_for", (Context.Guild as SocketGuild)?.GetUser(userId)?.ToString() ?? userId.ToString())) - .WithFooter(efb => efb.WithText(GetText("page", page + 1))); + .WithFooter(efb => efb.WithText(GetText("page", page + 1))); if (!warnings.Any()) { @@ -202,8 +207,8 @@ namespace NadekoBot.Modules.Administration uow.Complete(); } - await ReplyConfirmLocalized("warn_punish_set", - Format.Bold(punish.ToString()), + await ReplyConfirmLocalized("warn_punish_set", + Format.Bold(punish.ToString()), Format.Bold(number.ToString())).ConfigureAwait(false); } @@ -397,6 +402,92 @@ namespace NadekoBot.Modules.Administration .AddField(efb => efb.WithName("ID").WithValue(user.Id.ToString()).WithIsInline(true))) .ConfigureAwait(false); } + + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + [RequireUserPermission(GuildPermission.BanMembers)] + [RequireBotPermission(GuildPermission.BanMembers)] + [OwnerOnly] + public async Task MassKill([Remainder] string people) + { + if (string.IsNullOrWhiteSpace(people)) + return; + + var gusers = ((SocketGuild)Context.Guild).Users; + //get user objects and reasons + var bans = people.Split("\n") + .Select(x => + { + var split = x.Trim().Split(" "); + + var reason = string.Join(" ", split.Skip(1)); + + if (ulong.TryParse(split[0], out var id)) + return (Original: split[0], Id: id, Reason: reason); + + return (Original: split[0], + Id: gusers + .FirstOrDefault(u => u.ToString().ToLowerInvariant() == x) + ?.Id, + Reason: reason); + }) + .ToArray(); + + //if user is null, means that person couldn't be found + var missing = bans + .Where(x => !x.Id.HasValue) + .ToArray(); + + //get only data for found users + var found = bans + .Where(x => x.Id.HasValue) + .Select(x => x.Id.Value) + .ToArray(); + + var missStr = string.Join("\n", missing); + if (string.IsNullOrWhiteSpace(missStr)) + missStr = "-"; + + //send a message but don't wait for it + var banningMessageTask = Context.Channel.EmbedAsync(new EmbedBuilder() + .WithDescription(GetText("mass_kill_in_progress", bans.Length)) + .AddField(GetText("invalid", missing.Length), missStr) + .WithOkColor()); + + using (var uow = _db.UnitOfWork) + { + var bc = uow.BotConfig.GetOrCreate(set => set.Include(x => x.Blacklist)); + //blacklist the users + bc.Blacklist.AddRange(found.Select(x => + new BlacklistItem + { + ItemId = x, + Type = BlacklistType.User, + })); + //clear their currencies + uow.Currency.RemoveFromMany(found.Select(x => (long)x).ToList()); + uow.Complete(); + } + + _bc.Reload(); + + //do the banning + await Task.WhenAll(bans + .Where(x => x.Id.HasValue) + .Select(x => Context.Guild.AddBanAsync(x.Id.Value, 7, x.Reason, new RequestOptions() { + RetryMode = RetryMode.AlwaysRetry, + }))) + .ConfigureAwait(false); + + //wait for the message and edit it + var banningMessage = await banningMessageTask.ConfigureAwait(false); + + await banningMessage.ModifyAsync(x => x.Embed = new EmbedBuilder() + .WithDescription(GetText("mass_kill_completed", bans.Length)) + .AddField(GetText("invalid", missing.Length), missStr) + .WithOkColor() + .Build()).ConfigureAwait(false); + } } } } diff --git a/NadekoBot.Core/Services/Database/Repositories/ICurrencyRepository.cs b/NadekoBot.Core/Services/Database/Repositories/ICurrencyRepository.cs index 51f35cf0..0a1f484b 100644 --- a/NadekoBot.Core/Services/Database/Repositories/ICurrencyRepository.cs +++ b/NadekoBot.Core/Services/Database/Repositories/ICurrencyRepository.cs @@ -9,5 +9,6 @@ namespace NadekoBot.Core.Services.Database.Repositories long GetUserCurrency(ulong userId); bool TryUpdateState(ulong userId, long change); IEnumerable GetTopRichest(int count, int skip); + void RemoveFromMany(List ids); } } diff --git a/NadekoBot.Core/Services/Database/Repositories/Impl/CurrencyRepository.cs b/NadekoBot.Core/Services/Database/Repositories/Impl/CurrencyRepository.cs index e21c63a1..bbc0e8f1 100644 --- a/NadekoBot.Core/Services/Database/Repositories/Impl/CurrencyRepository.cs +++ b/NadekoBot.Core/Services/Database/Repositories/Impl/CurrencyRepository.cs @@ -33,6 +33,11 @@ namespace NadekoBot.Core.Services.Database.Repositories.Impl public long GetUserCurrency(ulong userId) => GetOrCreate(userId).Amount; + public void RemoveFromMany(List ids) + { + _set.RemoveRange(_set.Where(x => ids.Contains((long)x.UserId))); + } + public bool TryUpdateState(ulong userId, long change) { var cur = GetOrCreate(userId); diff --git a/NadekoBot.Core/Services/Impl/BotConfigProvider.cs b/NadekoBot.Core/Services/Impl/BotConfigProvider.cs index c9152299..cdbc4d36 100644 --- a/NadekoBot.Core/Services/Impl/BotConfigProvider.cs +++ b/NadekoBot.Core/Services/Impl/BotConfigProvider.cs @@ -6,11 +6,14 @@ namespace NadekoBot.Core.Services.Impl public class BotConfigProvider : IBotConfigProvider { private readonly DbService _db; + private readonly IDataCache _cache; + public BotConfig BotConfig { get; private set; } - public BotConfigProvider(DbService db, BotConfig bc) + public BotConfigProvider(DbService db, BotConfig bc, IDataCache cache) { _db = db; + _cache = cache; BotConfig = bc; } diff --git a/NadekoBot.Core/Services/NadekoBot.cs b/NadekoBot.Core/Services/NadekoBot.cs index e4ee216d..af42ae0a 100644 --- a/NadekoBot.Core/Services/NadekoBot.cs +++ b/NadekoBot.Core/Services/NadekoBot.cs @@ -129,7 +129,7 @@ namespace NadekoBot { AllGuildConfigs = uow.GuildConfigs.GetAllGuildConfigs(startingGuildIdList).ToImmutableArray(); - IBotConfigProvider botConfigProvider = new BotConfigProvider(_db, _botConfig); + IBotConfigProvider botConfigProvider = new BotConfigProvider(_db, _botConfig, Cache); //initialize Services Services = new NServiceProvider() diff --git a/src/NadekoBot/_strings/ResponseStrings.en-US.json b/src/NadekoBot/_strings/ResponseStrings.en-US.json index 6cca1fea..c92aaf75 100644 --- a/src/NadekoBot/_strings/ResponseStrings.en-US.json +++ b/src/NadekoBot/_strings/ResponseStrings.en-US.json @@ -919,5 +919,8 @@ "searches_crypto_not_found": "Cryptocurrency with that name was not found.", "searches_did_you_mean": "Did you mean {0}?", "administration_self_assign_level_req": "Self assignable role {0} now requires at least server level {1}.", - "administration_self_assign_not_level": "That self-assignable role requires at least server level {0}." + "administration_self_assign_not_level": "That self-assignable role requires at least server level {0}.", + "administration_invalid": "Invalid / Can't be found ({0})", + "administration_mass_kill_in_progress": "Mass Banning and Blacklisting of {0} users is in progress...", + "administration_mass_kill_completed": "Mass Banning and Blacklisting of {0} users is complete." } \ No newline at end of file diff --git a/src/NadekoBot/data/command_strings.json b/src/NadekoBot/data/command_strings.json index 3b44ba3c..c38b05b1 100644 --- a/src/NadekoBot/data/command_strings.json +++ b/src/NadekoBot/data/command_strings.json @@ -3113,5 +3113,12 @@ "usage": [ "{0}rlr 5 SomeRole" ] + }, + "masskill": { + "cmd": "masskill", + "desc": "Specify a new-line separated list of `userid reason`. You can use Username#discrim instead of UserId. Specified users will be banned from the current server, blacklisted from the bot, and have all of their flowers taken away.", + "usage": [ + "{0}masskill BadPerson#1234 Toxic person" + ] } }