示例#1
0
        public async Task Command(SocketGuildUser user, [Remainder] string reason = null)
        {
            Server server = await DatabaseQueries.GetOrCreateServerAsync(Context.Guild.Id);

            IRole role = Context.Guild.Roles.FirstOrDefault(x => x.Name == SB_ROLE);

            if (role == null)
            {
                await SendBasicErrorEmbedAsync($"The role `{SB_ROLE}` does not exist, therefore there are no active shadowbans.");

                return;
            }

            if (!user.Roles.Contains(role))
            {
                await SendBasicErrorEmbedAsync($"{user.Mention} is not shadowbanned.");

                return;
            }

            reason ??= "<No reason provided>";

            await user.RemoveRoleAsync(role);

            await ReplyAsync($"{Context.User.Mention} Successfully unshadowbanned `{user}`.");

            KaguyaEvents.TriggerUnshadowban(new ModeratorEventArgs(server, Context.Guild, user, (SocketGuildUser)Context.User, reason, null));
        }
示例#2
0
文件: UnWarn.cs 项目: mmattbtw/Kaguya
        private async Task ReactionReply(SocketGuildUser user,
                                         IReadOnlyCollection <WarnedUser> warnings,
                                         Embed embed,
                                         int warnCount,
                                         Server server,
                                         string reason)
        {
            Emoji[] emojis = GlobalProperties.EmojisOneThroughNine();

            var data      = new ReactionCallbackData("", embed, false, false, TimeSpan.FromSeconds(300));
            var callbacks = new List <(IEmote, Func <SocketCommandContext, SocketReaction, Task>)>();

            for (int j = 0; j < warnCount; j++)
            {
                int j1 = j;
                callbacks.Add((emojis[j], async(c, r) =>
                {
                    var uwArgs = new ModeratorEventArgs(server, Context.Guild, user, (SocketGuildUser)Context.User, reason, null);
                    KaguyaEvents.TriggerUnwarn(uwArgs);

                    await DatabaseQueries.DeleteAsync(warnings.ElementAt(j1));
                    await c.Channel.SendMessageAsync($"{r.User.Value.Mention} " +
                                                     $"`Successfully removed warning #{j1 + 1}`");
                }));
            }

            data.SetCallbacks(callbacks);
            await InlineReactionReplyAsync(data);
        }
示例#3
0
        public async Task ShadowbanUser(SocketGuildUser user, [Remainder] string reason = null)
        {
            SocketGuild guild  = Context.Guild;
            IRole       role   = guild.Roles.FirstOrDefault(x => x.Name == SB_ROLE);
            Server      server = await DatabaseQueries.GetOrCreateServerAsync(Context.Guild.Id);

            if (role == null)
            {
                await ReplyAsync($"{Context.User.Mention} Could not find role `{SB_ROLE}`. Creating...");

                RestRole newRole = await guild.CreateRoleAsync(SB_ROLE, GuildPermissions.None, null, false, false, null);

                role = newRole;
                await ReplyAsync($"{Context.User.Mention} Created role `{SB_ROLE}` with permissions: `none`.");
                await ReplyAsync($"{Context.User.Mention} Scanning permission overwrites for channels...");
            }

            if (string.IsNullOrWhiteSpace(reason))
            {
                reason = "<No reason provided>";
            }

            try
            {
                await ScanChannelsForPermissions(role);

                if (user.Roles.Contains(role))
                {
                    await SendBasicErrorEmbedAsync($"{user.Mention} already has the role {role.Mention}.");

                    return;
                }

                await user.AddRoleAsync(role);
            }
            catch (Exception e)
            {
                throw new KaguyaSupportException("Failed to add `kaguya-mute` role to user!\n\n" +
                                                 $"Error Log: ```{e}```");
            }

            IEnumerable <SocketRole> roles = user.Roles.Where(x => !x.IsManaged && x.Name != "@everyone");
            await user.RemoveRolesAsync(roles);

            var successEmbed = new KaguyaEmbedBuilder
            {
                Description = $"`{user}` has been transported to the shadowlands...",
                Footer      = new EmbedFooterBuilder
                {
                    Text = "In the shadowlands, users may not interact with any text or voice channel, " +
                           "or view who is in the server.\n\n" +
                           "Use the unshadowban command to undo this action."
                }
            };

            KaguyaEvents.TriggerShadowban(new ModeratorEventArgs(server, guild, user, (SocketGuildUser)Context.User, reason, null));
            await ReplyAsync(embed : successEmbed.Build());
        }
示例#4
0
文件: Unmute.cs 项目: mmattbtw/Kaguya
        public async Task UnmuteUser(SocketGuildUser user, [Remainder] string reason = null)
        {
            Server server = await DatabaseQueries.GetOrCreateServerAsync(Context.Guild.Id);

            var mutedObject = await DatabaseQueries.GetFirstMatchAsync <MutedUser>(x => x.UserId == user.Id && x.ServerId == server.ServerId);

            reason ??= "<No reason provided>";

            if (mutedObject != null)
            {
                await DatabaseQueries.DeleteAsync(mutedObject);
            }

            if (server.IsPremium)
            {
                await DatabaseQueries.UpdateAsync(server);
            }

            try
            {
                SocketRole muteRole = Context.Guild.Roles.FirstOrDefault(x => x.Name.ToLower() == "kaguya-mute");

                if (!user.Roles.Contains(muteRole))
                {
                    await ReplyAsync($"{Context.User.Mention} **{user}** is not muted.");

                    return;
                }

                await user.RemoveRoleAsync(muteRole);
                await ReplyAsync($"{Context.User.Mention} Successfully unmuted **{user}**.");


                KaguyaEvents.TriggerUnmute(new ModeratorEventArgs(server, Context.Guild, user, (SocketGuildUser)Context.User, reason, null));
            }
            catch (NullReferenceException)
            {
                var errorEmbed = new KaguyaEmbedBuilder
                {
                    Description = "User was never muted because the mute role doesn't exist.",
                    Footer      = new EmbedFooterBuilder
                    {
                        Text = "Use the mute command to generate the mute role."
                    }
                };

                errorEmbed.SetColor(EmbedColor.RED);

                await ReplyAsync(embed : errorEmbed.Build());
            }
            catch (Exception e)
            {
                throw new KaguyaSupportException($"An unexpected error occurred.\n\nError Log: {e}");
            }
        }
示例#5
0
        public static Task Initialize()
        {
            var timer = new Timer(5000)
            {
                AutoReset = true,
                Enabled   = true
            };

            timer.Elapsed += async(_, _) =>
            {
                List <MutedUser> curMutedUsers = await DatabaseQueries.GetAllAsync <MutedUser>(x => x.ExpiresAt < DateTime.Now.ToOADate());

                foreach (MutedUser mutedUser in curMutedUsers)
                {
                    SocketGuild guild = ConfigProperties.Client.GetGuild(mutedUser.ServerId);

                    if (guild == null)
                    {
                        goto RemoveFromDB;
                    }

                    Server server = await DatabaseQueries.GetOrCreateServerAsync(guild.Id);

                    SocketGuildUser user     = guild.GetUser(mutedUser.UserId);
                    SocketGuildUser selfUser = guild.GetUser(ConfigProperties.Client.CurrentUser.Id);

                    try
                    {
                        SocketRole muteRole = guild.Roles.FirstOrDefault(x => x.Name == "kaguya-mute");
                        await user.RemoveRoleAsync(muteRole);

                        KaguyaEvents.TriggerUnmute(new ModeratorEventArgs(server, guild, user, selfUser,
                                                                          "Automatic unmute (timed mute has expired)", null));
                    }
                    catch (Exception)
                    {
                        await ConsoleLogger.LogAsync($"Exception handled when unmuting a user in guild [Name: {guild.Name} | ID: {guild.Id}]",
                                                     LogLvl.WARN);
                    }

                    await DatabaseQueries.UpdateAsync(server);

RemoveFromDB:
                    await DatabaseQueries.DeleteAsync(mutedUser);

                    await ConsoleLogger.LogAsync($"User [ID: {mutedUser.UserId}] has been automatically unmuted.",
                                                 LogLvl.DEBUG);
                }
            };

            return(Task.CompletedTask);
        }
示例#6
0
文件: Warn.cs 项目: mmattbtw/Kaguya
        public async Task AddWarn(SocketGuildUser user, [Remainder] string reason = null)
        {
            Server server = await DatabaseQueries.GetOrCreateServerAsync(Context.Guild.Id);

            if (reason == null)
            {
                reason = "No reason specified.";
            }

            var wu = new WarnedUser
            {
                ServerId      = Context.Guild.Id,
                UserId        = user.Id,
                ModeratorName = Context.User.ToString(),
                Reason        = reason,
                Date          = DateTime.Now.ToOADate()
            };

            await DatabaseQueries.InsertAsync(wu);

            KaguyaEvents.TriggerWarning(new ModeratorEventArgs(server, Context.Guild, user, (SocketGuildUser)Context.User, reason, null));

            try
            {
                await user.SendMessageAsync(embed : (await WarnEmbed(wu, Context)).Build());
            }
            catch (Exception)
            {
                await ConsoleLogger.LogAsync($"Failed to DM user {user.Id} that they have been " +
                                             $"warned in guild {server.ServerId}. " +
                                             $"Database updated regardless.", LogLvl.DEBUG);
            }

            await ReplyAsync(embed : (await Reply(wu, user)).Build());

            await DatabaseQueries.UpdateAsync(server);
        }
示例#7
0
文件: Mute.cs 项目: mmattbtw/Kaguya
        public async Task MuteUser(SocketGuildUser user, string duration = null, [Remainder] string reason = null)
        {
            TimeSpan?   timeSpan = null;
            SocketGuild guild    = Context.Guild;
            Server      server   = await DatabaseQueries.GetOrCreateServerAsync(guild.Id);

            string muteString = "";

            reason ??= "<No reason provided>";

            if (duration != null)
            {
                if (!duration.Any(x => x.Equals('s') || x.Equals('m') || x.Equals('h') || x.Equals('d')))
                {
                    throw new FormatException("You did not specify a proper mute time.\nThe proper format is " +
                                              "`<user> <dhms>`.\nExample: `<user> 30m`");
                }

                timeSpan = duration.ParseToTimespan();
                double time = DateTime.Now.Add(timeSpan.Value).ToOADate();

                muteString = $"User will be unmuted `{DateTime.FromOADate(time).Humanize(false)}`";

                var muteObject = new MutedUser
                {
                    ServerId  = guild.Id,
                    UserId    = user.Id,
                    ExpiresAt = time
                };

                if (await DatabaseQueries.GetAllForServerAsync <MutedUser>(server.ServerId) != null)
                {
                    var existingObject =
                        await DatabaseQueries.GetFirstMatchAsync <MutedUser>(x =>
                                                                             x.UserId == user.Id && x.ServerId == server.ServerId);

                    if (existingObject != null)
                    {
                        await DatabaseQueries.DeleteAsync(existingObject);

                        await ConsoleLogger.LogAsync($"Removed duplicate mute entry for user {user.Id} in guild {guild.Id}.", LogLvl.DEBUG);
                    }
                }

                await DatabaseQueries.InsertAsync(muteObject);
            }

            SocketRole muteRole = guild.Roles.FirstOrDefault(x => x?.Name.ToLower() == "kaguya-mute");

            if (muteRole == null)
            {
                await Context.Guild.CreateRoleAsync("kaguya-mute", GuildPermissions.None, Color.Default, false, false, null);

                await ConsoleLogger.LogAsync($"New mute role created in guild [Name: {guild.Name} | ID: {guild.Id}]",
                                             LogLvl.DEBUG);

                /*
                 * We redefine guild because the object
                 * must now have an updated role collection
                 * in order for this to work.
                 */

                guild    = Context.Guild;
                muteRole = guild.Roles.FirstOrDefault(x => x.Name.ToLower() == "kaguya-mute");

                await ReplyAsync($"{Context.User.Mention} Mute role not found, so I created one.\n" +
                                 "Updating channel permissions. Please wait...");
            }

            int failCount = 0;

            foreach (SocketGuildChannel channel in guild.Channels)
            {
                if (channel.GetPermissionOverwrite(muteRole).HasValue)
                {
                    continue;
                }

                try
                {
                    await channel.AddPermissionOverwriteAsync(muteRole, OverwritePermissions.InheritAll);

                    await channel.AddPermissionOverwriteAsync(muteRole, new OverwritePermissions(
                                                                  addReactions : PermValue.Deny, speak : PermValue.Deny,
                                                                  sendTTSMessages : PermValue.Deny, connect : PermValue.Deny, createInstantInvite : PermValue.Deny,
                                                                  sendMessages : PermValue.Deny));

                    await ConsoleLogger.LogAsync($"Permission overwrite added for guild channel.\n" +
                                                 $"Guild: [Name: {guild.Name} | ID: {guild.Id}]\n" +
                                                 $"Channel: [Name: {channel.Name} | ID: {channel.Id}]", LogLvl.TRACE);
                }
                catch (Exception)
                {
                    if (failCount >= 3)
                    {
                        await ReplyAsync($"{Context.User.Mention} Could not update permissions for several channels! " +
                                         $"**Aborting mute!**");

                        return;
                    }

                    await ReplyAsync($"{Context.User.Mention} Could not update permissions for {channel}! Muted user " +
                                     $"can still type in this channel!");

                    failCount++;
                }
            }

            try
            {
                await user.AddRoleAsync(muteRole);
            }
            catch (Exception)
            {
                await ReplyAsync($"{Context.User.Mention} failed to mute user. Please ensure my 'Kaguya' role" +
                                 $" is at the top of the role hierarchy. I cannot mute users who have a role " +
                                 $"higher than me.");
            }

            await ConsoleLogger.LogAsync($"User muted. Guild: [Name: {guild.Name} | ID: {guild.Id}] " +
                                         $"User: [Name: {user} | ID: {user.Id}]", LogLvl.DEBUG);

            await ReplyAsync($"{Context.User.Mention} Successfully muted **{user}**. {muteString}");

            KaguyaEvents.TriggerMute(new ModeratorEventArgs(server, guild, user, (SocketGuildUser)Context.User, reason, timeSpan));
        }
示例#8
0
        public async Task Command()
        {
            // Cooldown in seconds.
            const int FISHING_COOLDOWN         = 15;
            const int FISHING_COOLDOWN_PREMIUM = 5;

            User user = await DatabaseQueries.GetOrCreateUserAsync(Context.User.Id);

            Server server = await DatabaseQueries.GetOrCreateServerAsync(Context.Guild.Id);

            if (user.Points < user.FishCost())
            {
                var baitEmbed = new KaguyaEmbedBuilder(EmbedColor.RED)
                {
                    Description = $"You do not have enough points to play the fishing game.",
                    Footer      = new EmbedFooterBuilder
                    {
                        Text = $"You need {user.FishCost()} points to play. You have {user.Points} points."
                    }
                };

                await SendEmbedAsync(baitEmbed);

                return;
            }

            bool isPremium = user.IsPremium;

            if (user.LastFished >= DateTime.Now.AddSeconds(-FISHING_COOLDOWN).ToOADate() && !isPremium ||
                user.LastFished >= DateTime.Now.AddSeconds(-FISHING_COOLDOWN_PREMIUM).ToOADate() && isPremium)
            {
                TimeSpan ts = DateTime.FromOADate(user.LastFished) - DateTime.Now.AddSeconds(-15);

                if (isPremium)
                {
                    ts -= TimeSpan.FromSeconds(10);
                }

                var errorEmbed = new KaguyaEmbedBuilder(EmbedColor.RED)
                {
                    Description = $"Please wait `{ts.Humanize(minUnit: TimeUnit.Second)}` before fishing again."
                };

                await ReplyAndDeleteAsync("", false, errorEmbed.Build(), TimeSpan.FromSeconds(3));

                return;
            }

            int value;
            var embed = new KaguyaEmbedBuilder
            {
                Description = $"🎣 | {Context.User.Mention} "
            };

            var    r      = new Random();
            double roll   = r.NextDouble();
            int    fishId = r.Next(int.MaxValue);
            int    fishExp;

            while (await DatabaseQueries.ItemExistsAsync <Fish>(x => x.FishId == fishId))
            {
                fishId = r.Next(int.MaxValue);
            }

            var bonuses = new FishHandler.FishLevelBonuses(user.FishExp);

            roll *= 1 - (bonuses.BonusLuckPercent / 100);

            if (isPremium)
            {
                roll *= 0.95;
            }

            FishType fishType = GetFishType(roll);

            switch (fishType)
            {
            case FishType.SEAWEED:
                value              = 2;
                fishExp            = 0;
                embed.Description += $"Aw man, you caught `seaweed`. Better luck next time!";
                embed.SetColor(EmbedColor.GRAY);

                break;

            case FishType.PINFISH:
                value              = 15;
                fishExp            = r.Next(1, 3);
                embed.Description += $"you caught a `pinfish`!";
                embed.SetColor(EmbedColor.GRAY);

                break;

            case FishType.SMALL_BASS:
                value              = 25;
                fishExp            = r.Next(2, 6);
                embed.Description += $"you caught a `small bass`!";
                embed.SetColor(EmbedColor.GREEN);

                break;

            case FishType.SMALL_SALMON:
                value              = 25;
                fishExp            = r.Next(2, 6);
                embed.Description += $"you caught a `small salmon`!";
                embed.SetColor(EmbedColor.GREEN);

                break;

            case FishType.CATFISH:
                value              = 75;
                fishExp            = r.Next(5, 9);
                embed.Description += $"you caught a `catfish`!";
                embed.SetColor(EmbedColor.GREEN);

                break;

            case FishType.LARGE_BASS:
                value              = 150;
                fishExp            = r.Next(7, 11);
                embed.Description += $"Wow, you caught a `large bass`!";
                embed.SetColor(EmbedColor.LIGHT_BLUE);

                break;

            case FishType.LARGE_SALMON:
                value              = 150;
                fishExp            = r.Next(7, 11);
                embed.Description += $"Wow, you caught a `large salmon`!";
                embed.SetColor(EmbedColor.LIGHT_BLUE);

                break;

            case FishType.RED_DRUM:
                value              = 200;
                fishExp            = r.Next(7, 20);
                embed.Description += $"Holy smokes, you caught a `red drum`!";
                embed.SetColor(EmbedColor.RED);

                break;

            case FishType.TRIGGERFISH:
                value              = 350;
                fishExp            = r.Next(11, 30);
                embed.Description += $"Holy smokes, you caught a `triggerfish`!";
                embed.SetColor(EmbedColor.LIGHT_PURPLE);

                break;

            case FishType.GIANT_SEA_BASS:
                value              = 500;
                fishExp            = r.Next(18, 36);
                embed.Description += $"No way, you caught a `giant sea bass`! Nice work!";
                embed.SetColor(EmbedColor.LIGHT_PURPLE);

                break;

            case FishType.SMALLTOOTH_SAWFISH:
                value              = 1000;
                fishExp            = r.Next(29, 42);
                embed.Description += $"No way, you caught a `smalltooth sawfish`! Nice work!";
                embed.SetColor(EmbedColor.LIGHT_PURPLE);

                break;

            case FishType.DEVILS_HOLE_PUPFISH:
                value              = 2500;
                fishExp            = r.Next(40, 95);
                embed.Description += $"I can't believe my eyes!! you caught a `devils hold pupfish`! You're crazy!";
                embed.SetColor(EmbedColor.VIOLET);

                break;

            case FishType.ORANTE_SLEEPER_RAY:
                value              = 5000;
                fishExp            = r.Next(75, 325);
                embed.Description += $"Hot diggity dog, you caught an `orante sleeper ray`! This is unbelievable!";
                embed.SetColor(EmbedColor.ORANGE);

                break;

            case FishType.GIANT_SQUID:
                value              = 20000;
                fishExp            = r.Next(400, 900);
                embed.Description += $"Well butter my buttcheeks and call me a biscuit, you caught the second " +
                                     $"rarest fish in the sea! It's a `giant squid`!! Congratulations!";

                embed.SetColor(EmbedColor.ORANGE);

                break;

            case FishType.BIG_KAHUNA:
                value              = 50000;
                fishExp            = r.Next(1250, 4500);
                embed.Description += $"<a:siren:429784681316220939> NO WAY! You hit the jackpot " +
                                     $"and caught the **Legendary `BIG KAHUNA`**!!!! " +
                                     $"What an incredible moment this is! <a:siren:429784681316220939>";

                embed.SetColor(EmbedColor.GOLD);

                break;

            default:
                value              = 0;
                fishExp            = 0;
                embed.Description += $"Oh no, it took your bait! Better luck next time...";
                embed.SetColor(EmbedColor.GRAY);

                break;
            }

            user.FishExp   += fishExp;
            user.Points    -= user.FishCost();
            user.LastFished = DateTime.Now.ToOADate();

            var fish = new Fish
            {
                FishId     = fishId,
                UserId     = Context.User.Id,
                ServerId   = Context.Guild.Id,
                TimeCaught = DateTime.Now.ToOADate(),
                FishType   = fishType,
                FishString = fishType.ToString(),
                Value      = value,
                Exp        = fishExp,
                Sold       = false
            };

            value = Fish.GetPayoutForFish(fish, user.FishExp);

            await DatabaseQueries.InsertAsync(fish);

            await DatabaseQueries.UpdateAsync(user);

            await KaguyaEvents.TriggerFish(new FishHandlerEventArgs(user, fish, Context)); // Triggers the fish EXP service.

            if (fishType != FishType.BAIT_STOLEN)
            {
                List <Fish> existingFish = (await DatabaseQueries.GetFishForUserMatchingTypeAsync(fishType, user.UserId)).ToList();
                int         fishCount    = existingFish.Count(x => !x.Sold);
                string      fishString   = fishType.ToString().Replace("_", " ").ToLower();

                embed.Description += $"\n\nFish ID: `{fishId}`\n" +
                                     $"Fish Value: `{value:N0}` points.\n" +
                                     $"Fishing Exp Earned: `{fishExp:N0} exp`\n" +
                                     $"Points Remaining: `{user.Points:N0} (-{user.FishCost()})`\n\n" +
                                     $"You now have `{fishCount}` `{fishString}`";
            }
            else
            {
                embed.Description += $"\nPoints Remaining: `{user.Points:N0} (-{user.FishCost()})`";
            }

            embed.Footer = new EmbedFooterBuilder
            {
                Text = $"Use the {server.CommandPrefix}myfish command to view your fishing stats!\n" +
                       $"The {server.CommandPrefix}sellfish command may be used to sell your fish."
            };

            // Fish Embed
            await ReplyAsync(embed : embed.Build());
        }
示例#9
0
        private static async Task ActionUsers(IEnumerable <ulong> userIds, ulong guildId, string action)
        {
            Server server = await DatabaseQueries.GetOrCreateServerAsync(guildId);

            SocketGuild guild      = ConfigProperties.Client.GetGuild(guildId);
            var         guildUsers = new List <SocketGuildUser>();

            foreach (ulong userId in userIds)
            {
                SocketGuildUser guildUser = guild.GetUser(userId);

                if (guildUser != null)
                {
                    guildUsers.Add(guildUser);
                }
            }

            if (guildUsers.Count == 0)
            {
                await ConsoleLogger.LogAsync($"The antiraid service was triggered in guild: {guild.Id} " +
                                             "but no guild users were found from the provided set of IDs!", LogLvl.WARN);

                return;
            }

            KaguyaEvents.TriggerRaid(new AntiRaidEventArgs(guildUsers, guild, action));

            // We need to message the actioned users, if applicable, before actioning.

            if (!string.IsNullOrWhiteSpace(server.AntiraidPunishmentDirectMessage))
            {
                foreach (SocketGuildUser guildUser in guildUsers)
                {
                    // content must be inside the foreach because of how we modify it below
                    // on a per-user basis.
                    string content = server.AntiraidPunishmentDirectMessage;

                    var embed = new KaguyaEmbedBuilder(EmbedColor.ORANGE)
                    {
                        Title       = "Kaguya Anti-Raid Notification",
                        Description = content
                    };

                    var sb = new StringBuilder(content);

                    sb = sb.Replace("{USERNAME}", guildUser.UsernameAndDescriminator());
                    sb = sb.Replace("{USERMENTION}", guildUser.Mention);
                    sb = sb.Replace("{SERVER}", guild.Name);
                    sb = sb.Replace("{PUNISHMENT}", FormattedAntiraidPunishment(action.ToLower()));

                    embed.Description = sb.ToString();

                    try
                    {
                        await guildUser.SendEmbedAsync(embed);
                    }
                    catch (HttpException httpEx)
                    {
                        await ConsoleLogger.LogAsync(
                            $"Tried to send user {guildUser.Id} a custom anti-raid DM notification " +
                            $"from guild [Name: {guild.Name} | ID: {guild.Id}] but failed to do so due to " +
                            $"an Http Exception (Failure Reason: {httpEx.Reason})", LogLvl.WARN);
                    }
                    catch (Exception ex)
                    {
                        await ConsoleLogger.LogAsync(ex, $"An unexpected error occurred when attempting to send user {guildUser.Id} a custom " +
                                                     $"anti-raid DM notification from guild [Name: {guild.Name} | ID: {guild.Id}].\n");
                    }
                }
            }

            switch (server.AntiRaid.Action.ToLower())
            {
            case "mute":
                var mute = new Mute();
                foreach (SocketGuildUser user in guildUsers)
                {
                    try
                    {
                        await mute.AutoMute(user);
                    }
                    catch (Exception)
                    {
                        await ConsoleLogger.LogAsync("Attempted to auto-mute user " +
                                                     $"{user.ToString() ?? "NULL"} as " +
                                                     "part of the antiraid service, but " +
                                                     "an exception was thrown!!", LogLvl.ERROR);
                    }
                }

                break;

            case "kick":
                var kick = new Kick();
                foreach (SocketGuildUser user in guildUsers)
                {
                    try
                    {
                        await kick.AutoKickUserAsync(user, "Kaguya Anti-Raid protection.");
                    }
                    catch (Exception)
                    {
                        await ConsoleLogger.LogAsync("Attempted to auto-kick user " +
                                                     $"{user.ToString() ?? "NULL"} as " +
                                                     "part of the antiraid service, but " +
                                                     "an exception was thrown!!", LogLvl.ERROR);
                    }
                }

                break;

            case "shadowban":
                var sb = new Shadowban();
                foreach (SocketGuildUser user in guildUsers)
                {
                    try
                    {
                        await sb.AutoShadowbanUserAsync(user);
                    }
                    catch (Exception)
                    {
                        await ConsoleLogger.LogAsync("Attempted to auto-shadowban user " +
                                                     $"{user.ToString() ?? "NULL"} as " +
                                                     "part of the antiraid service, but " +
                                                     "an exception was thrown!!", LogLvl.ERROR);
                    }
                }

                break;

            case "ban":
                var ban = new Ban();
                foreach (SocketGuildUser user in guildUsers)
                {
                    try
                    {
                        await ban.AutoBanUserAsync(user, "Kaguya Anti-Raid protection.");
                    }
                    catch (Exception)
                    {
                        await ConsoleLogger.LogAsync("Attempted to auto-ban user " +
                                                     $"{user.ToString() ?? "NULL"} as " +
                                                     "part of the antiraid service, but " +
                                                     "an exception was thrown!!", LogLvl.ERROR);
                    }
                }

                break;

            default:
                await ConsoleLogger.LogAsync("Antiraid service triggered, but no users actioned. " +
                                             "Antiraid action string is different than expected. " +
                                             "Expected \"mute\" \"kick\" \"shadowban\" OR \"ban\". " +
                                             $"Received: '{action.ToLower()}'. " +
                                             $"Guild: {guildId}.", LogLvl.ERROR);

                break;
            }

            await ConsoleLogger.LogAsync($"Antiraid: Successfully actioned {guildUsers.Count:N0} users in guild {guild.Id}.", LogLvl.INFO);
        }