public async Task BanRaidRecovery(int minutes = 10, [Remainder] string banToken = "") { if (!RaidRecoveryTracker.Exists(Context.Channel.Id)) { await BetterReplyAsync($"The raid recovery system is not enabled. Use `@{Context.Guild.CurrentUser.Username} rr enable` to enable."); return; } if (minutes == 0 || minutes > 20160) { await BetterReplyAsync("Must be between 1 and 20160 (2 weeks). Rarely should this be greater than 10 unless a raid went unnoticed for longer.", minutes.ToString()); return; } if (!string.IsNullOrWhiteSpace(banToken)) { if (RaidRecoveryTracker.ValidateBanToken(Context.Channel.Id, banToken)) { IUserMessage banningMessage = await BetterReplyAsync(embed : LoadingEmbed("Banning users"), parameters : minutes.ToString()); HashSet <ulong> usersIdsToBan = RaidRecoveryTracker.UsersToBan(Context.Channel.Id); try { foreach (ulong user in usersIdsToBan) { await Context.Guild.AddBanAsync(user, 1, $"Banned by '{Context.User}' using the bot '{Context.Guild.CurrentUser.Username}' raid recovery system at {DateTime.UtcNow:o}"); } } catch { } await banningMessage.ModifyAsync(x => { x.Embed = null; x.Content = $"Banned {usersIdsToBan.Count} users."; }); await LogMessageEmbedAsync("Raid recovery system", $"Banned {usersIdsToBan.Count} users.{Environment.NewLine}{Environment.NewLine}{string.Join(", ", usersIdsToBan)}"); TrackStatistics(banningMessage.Id, parameters: $"token: {banToken}; banned: {string.Join(", ", usersIdsToBan)}"); return; } else { await BetterReplyAsync("Invalid ban token."); return; } } IUserMessage message = await BetterReplyAsync(embed : LoadingEmbed("Generating list of users to ban"), parameters : minutes.ToString()); ConcurrentBag <IMessage> messages = await GetMessagesAsync(); IEnumerable <IUser> usersToBan = messages.OrderByDescending(x => x.CreatedAt) .Where(x => x.CreatedAt > DateTime.UtcNow.AddMinutes(-minutes)) .Where(x => IsSuspected(x.Author)) .GroupBy(x => x.Author) .Where(x => x.Count() > _MessageThreshold) .Select(x => x.Key) .Distinct(); if (usersToBan.Count() > 0) { RaidRecoveryTracker.AddUsersToBan(Context.Channel.Id, usersToBan.Select(x => x.Id).ToHashSet()); StringBuilder builder = new StringBuilder(); builder.AppendLine($"The following {usersToBan.Count()} users will be banned."); builder.AppendLine("```"); foreach (IUser banUser in usersToBan) { builder.Append($"{banUser}; "); } builder.AppendLine("```"); await message.ModifyAsync(x => { x.Embed = null; x.Content = builder.ToString(); }); await BetterReplyAsync($"**Ban confirmation.** Selected time frame: {minutes.Minutes().Humanize(3)}; Token: `{RaidRecoveryTracker.BanToken(Context.Channel.Id)}`{Environment.NewLine}{Environment.NewLine}" + $"Type `@{Context.Guild.CurrentUser.Username} rr skip @User` to remove them from the ban list.{Environment.NewLine}" + $"Type `@{Context.Guild.CurrentUser.Username} rr ban {minutes} {RaidRecoveryTracker.BanToken(Context.Channel.Id)}` to ban the users above."); } else { await message.ModifyAsync(x => { x.Embed = null; x.Content = $"There are no suspected users to ban from the past {minutes.Minutes().Humanize(3)}."; }); } }