public async Task SetCooldownAsync(CommandContext ctx,
                                                   [Description("Cooldown.")] TimeSpan cooldown)
                {
                    if (cooldown.TotalSeconds < 5 || cooldown.TotalSeconds > 60)
                    {
                        throw new CommandFailedException("The cooldown timespan is not in the valid range ([5, 60] seconds).");
                    }

                    AntifloodSettings settings = await this.Database.GetAntifloodSettingsAsync(ctx.Guild.Id);

                    settings.Cooldown = (short)cooldown.TotalSeconds;
                    await this.Database.SetAntifloodSettingsAsync(ctx.Guild.Id, settings);

                    DiscordChannel logchn = this.Shared.GetLogChannelForGuild((DiscordClientImpl)ctx.Client, ctx.Guild);

                    if (logchn != null)
                    {
                        var emb = new DiscordEmbedBuilder()
                        {
                            Title = "Guild config changed",
                            Color = this.ModuleColor
                        };
                        emb.AddField("User responsible", ctx.User.Mention, inline: true);
                        emb.AddField("Invoked in", ctx.Channel.Mention, inline: true);
                        emb.AddField("Antiflood cooldown changed to", $"{settings.Cooldown}s");
                        await logchn.SendMessageAsync(embed : emb.Build());
                    }

                    await this.InformAsync(ctx, $"Antiflood cooldown for this guild has been changed to {settings.Cooldown}s", important : false);
                }
        public async Task HandleMemberJoinAsync(GuildMemberAddEventArgs e, AntifloodSettings settings)
        {
            if (!this.guildFloodUsers.ContainsKey(e.Guild.Id) && !this.TryAddGuildToWatch(e.Guild.Id))
            {
                throw new ConcurrentOperationException("Failed to add guild to antiflood watch list!");
            }

            if (!this.guildFloodUsers[e.Guild.Id].Add(e.Member))
            {
                throw new ConcurrentOperationException("Failed to add member to antiflood watch list!");
            }

            if (this.guildFloodUsers[e.Guild.Id].Count >= settings.Sensitivity)
            {
                foreach (DiscordMember m in this.guildFloodUsers[e.Guild.Id])
                {
                    await this.PunishMemberAsync(e.Guild, m, settings.Action);

                    await Task.Delay(TimeSpan.FromMilliseconds(100));
                }
                this.guildFloodUsers[e.Guild.Id].Clear();
                return;
            }

            await Task.Delay(TimeSpan.FromSeconds(settings.Cooldown));

            if (this.guildFloodUsers.ContainsKey(e.Guild.Id) && !this.guildFloodUsers[e.Guild.Id].TryRemove(e.Member))
            {
                throw new ConcurrentOperationException("Failed to remove member from antiflood watch list!");
            }
        }
                public async Task SetSensitivityAsync(CommandContext ctx,
                                                      [Description("Sensitivity (number of users allowed to join within a given timespan).")] short sensitivity)
                {
                    if (sensitivity < 2 || sensitivity > 20)
                    {
                        throw new CommandFailedException("The sensitivity is not in the valid range ([2, 20]).");
                    }

                    AntifloodSettings settings = await this.Database.GetAntifloodSettingsAsync(ctx.Guild.Id);

                    settings.Sensitivity = sensitivity;
                    await this.Database.SetAntifloodSettingsAsync(ctx.Guild.Id, settings);

                    DiscordChannel logchn = this.Shared.GetLogChannelForGuild((DiscordClientImpl)ctx.Client, ctx.Guild);

                    if (logchn != null)
                    {
                        var emb = new DiscordEmbedBuilder()
                        {
                            Title = "Guild config changed",
                            Color = this.ModuleColor
                        };
                        emb.AddField("User responsible", ctx.User.Mention, inline: true);
                        emb.AddField("Invoked in", ctx.Channel.Mention, inline: true);
                        emb.AddField("Antiflood sensitivity changed to", $"Max {settings.Sensitivity} users per {settings.Cooldown}s");
                        await logchn.SendMessageAsync(embed : emb.Build());
                    }

                    await this.InformAsync(ctx, $"Antiflood sensitivity for this guild has been changed to {Formatter.Bold(sensitivity.ToString())} users per {settings.Cooldown}s", important : false);
                }
                public async Task SetActionAsync(CommandContext ctx,
                                                 [Description("Action type.")] PunishmentActionType action)
                {
                    AntifloodSettings settings = await this.Database.GetAntifloodSettingsAsync(ctx.Guild.Id);

                    settings.Action = action;
                    await this.Database.SetAntifloodSettingsAsync(ctx.Guild.Id, settings);

                    DiscordChannel logchn = this.Shared.GetLogChannelForGuild((DiscordClientImpl)ctx.Client, ctx.Guild);

                    if (logchn != null)
                    {
                        var emb = new DiscordEmbedBuilder()
                        {
                            Title = "Guild config changed",
                            Color = this.ModuleColor
                        };
                        emb.AddField("User responsible", ctx.User.Mention, inline: true);
                        emb.AddField("Invoked in", ctx.Channel.Mention, inline: true);
                        emb.AddField("Antiflood action changed to", action.ToTypeString());
                        await logchn.SendMessageAsync(embed : emb.Build());
                    }

                    await this.InformAsync(ctx, $"Antiflood action for this guild has been changed to {Formatter.Bold(settings.Action.ToTypeString())}", important : false);
                }
                public async Task ExecuteGroupAsync(CommandContext ctx,
                                                    [Description("Enable?")] bool enable,
                                                    [Description("Sensitivity (number of users allowed to join within a given timespan).")] short sensitivity,
                                                    [Description("Action type.")] PunishmentActionType action = PunishmentActionType.Kick,
                                                    [Description("Cooldown.")] TimeSpan?cooldown = null)
                {
                    if (sensitivity < 2 || sensitivity > 20)
                    {
                        throw new CommandFailedException("The sensitivity is not in the valid range ([2, 20]).");
                    }

                    if (cooldown?.TotalSeconds < 5 || cooldown?.TotalSeconds > 60)
                    {
                        throw new CommandFailedException("The cooldown timespan is not in the valid range ([5, 60] seconds).");
                    }

                    var settings = new AntifloodSettings {
                        Action      = action,
                        Cooldown    = (short?)cooldown?.TotalSeconds ?? 10,
                        Enabled     = enable,
                        Sensitivity = sensitivity
                    };

                    using (DatabaseContext db = this.Database.CreateContext()) {
                        DatabaseGuildConfig gcfg = await this.GetGuildConfigAsync(ctx.Guild.Id);

                        gcfg.AntifloodSettings = settings;
                        db.GuildConfig.Update(gcfg);
                        await db.SaveChangesAsync();
                    }

                    DiscordChannel logchn = this.Shared.GetLogChannelForGuild(ctx.Client, ctx.Guild);

                    if (!(logchn is null))
                    {
                        var emb = new DiscordEmbedBuilder {
                            Title       = "Guild config changed",
                            Description = $"Antiflood {(enable ? "enabled" : "disabled")}",
                            Color       = this.ModuleColor
                        };
                        emb.AddField("User responsible", ctx.User.Mention, inline: true);
                        emb.AddField("Invoked in", ctx.Channel.Mention, inline: true);
                        if (enable)
                        {
                            emb.AddField("Antiflood sensitivity", settings.Sensitivity.ToString(), inline: true);
                            emb.AddField("Antiflood cooldown", settings.Cooldown.ToString(), inline: true);
                            emb.AddField("Antiflood action", settings.Action.ToTypeString(), inline: true);
                        }
                        await logchn.SendMessageAsync(embed : emb.Build());
                    }

                    await this.InformAsync(ctx, $"{Formatter.Bold(enable ? "Enabled" : "Disabled")} antiflood actions.", important : false);
                }
            public async Task ResetAsync(CommandContext ctx)
            {
                await ctx.WithGuildConfigAsync(gcfg => {
                    return(!gcfg.AntifloodEnabled ? throw new CommandFailedException(ctx, "cmd-err-reset-af-off") : Task.CompletedTask);
                });

                if (!await ctx.WaitForBoolReplyAsync("q-setup-reset"))
                {
                    return;
                }

                var settings = new AntifloodSettings();

                await this.ExecuteGroupAsync(ctx, true, settings.Action, settings.Sensitivity, TimeSpan.FromSeconds(settings.Cooldown));
            }
        public static Task SetAntifloodSettingsAsync(this DBService db, ulong gid, AntifloodSettings settings)
        {
            return(db.ExecuteCommandAsync(cmd => {
                cmd.CommandText = $"UPDATE gf.guild_cfg SET " +
                                  $"(antiflood_enabled, antiflood_sens, antiflood_cooldown, antiflood_action) = " +
                                  $"(@antiflood_enabled, @antiflood_sens, @antiflood_cooldown, @antiflood_action) " +
                                  $"WHERE gid = @gid;";
                cmd.Parameters.Add(new NpgsqlParameter <long>("gid", (long)gid));
                cmd.Parameters.Add(new NpgsqlParameter <bool>("antiflood_enabled", settings.Enabled));
                cmd.Parameters.Add(new NpgsqlParameter <short>("antiflood_action", (short)settings.Action));
                cmd.Parameters.Add(new NpgsqlParameter <short>("antiflood_cooldown", settings.Cooldown));
                cmd.Parameters.Add(new NpgsqlParameter <short>("antiflood_sens", settings.Sensitivity));

                return cmd.ExecuteNonQueryAsync();
            }));
        }
                public async Task ExecuteGroupAsync(CommandContext ctx)
                {
                    AntifloodSettings settings = (await this.GetGuildConfigAsync(ctx.Guild.Id)).AntifloodSettings;

                    if (settings.Enabled)
                    {
                        var sb = new StringBuilder();
                        sb.Append(Formatter.Bold("Sensitivity: ")).AppendLine(settings.Sensitivity.ToString());
                        sb.Append(Formatter.Bold("Cooldown: ")).AppendLine(settings.Cooldown.ToString());
                        sb.Append(Formatter.Bold("Action: ")).AppendLine(settings.Action.ToString());
                        await this.InformAsync(ctx, $"Antiflood watch for this guild is {Formatter.Bold("enabled")}\n\n{sb.ToString()}");
                    }
                    else
                    {
                        await this.InformAsync(ctx, $"Antiflood watch for this guild is {Formatter.Bold("disabled")}");
                    }
                }
            public async Task ExecuteGroupAsync(CommandContext ctx,
                                                [Description("desc-enable")] bool enable,
                                                [Description("desc-sens")] short sens,
                                                [Description("desc-punish-action")] PunishmentAction action = PunishmentAction.Kick,
                                                [Description("desc-cooldown")] TimeSpan?cooldown            = null)
            {
                if (sens is < AntifloodSettings.MinSensitivity or > AntifloodSettings.MaxSensitivity)
                {
                    throw new CommandFailedException(ctx, "cmd-err-range-sens", AntifloodSettings.MinSensitivity, AntifloodSettings.MaxSensitivity);
                }

                cooldown ??= TimeSpan.FromSeconds(10);
                if (cooldown.Value.TotalSeconds is < AntifloodSettings.MinCooldown or > AntifloodSettings.MaxCooldown)
                {
                    throw new CommandFailedException(ctx, "cmd-err-range-cd", AntifloodSettings.MinCooldown, AntifloodSettings.MaxCooldown);
                }

                var settings = new AntifloodSettings {
                    Action      = action,
                    Cooldown    = (short)cooldown.Value.TotalSeconds,
                    Enabled     = enable,
                    Sensitivity = sens
                };

                await ctx.Services.GetRequiredService <GuildConfigService>().ModifyConfigAsync(ctx.Guild.Id, gcfg => gcfg.AntifloodSettings = settings);

                await ctx.GuildLogAsync(emb => {
                    emb.WithLocalizedTitle("evt-cfg-upd");
                    emb.WithColor(this.ModuleColor);
                    if (enable)
                    {
                        emb.WithLocalizedDescription("evt-af-enable");
                        emb.AddLocalizedTitleField("str-sensitivity", settings.Sensitivity, inline: true);
                        emb.AddLocalizedTitleField("str-cooldown", settings.Cooldown, inline: true);
                        emb.AddLocalizedTitleField("str-punish-action", settings.Action.Humanize(), inline: true);
                    }
                    else
                    {
                        emb.WithLocalizedDescription("evt-af-disable");
                    }
                });

                await ctx.InfoAsync(this.ModuleColor, enable? "evt-af-enable" : "evt-af-disable");
            }
        public static async Task <AntifloodSettings> GetAntifloodSettingsAsync(this DBService db, ulong gid)
        {
            var settings = new AntifloodSettings();

            await db.ExecuteCommandAsync(async (cmd) => {
                cmd.CommandText = $"SELECT antiflood_enabled, antiflood_sens, antiflood_cooldown, antiflood_action FROM gf.guild_cfg WHERE gid = @gid LIMIT 1;";
                cmd.Parameters.Add(new NpgsqlParameter <long>("gid", (long)gid));

                using (var reader = await cmd.ExecuteReaderAsync().ConfigureAwait(false)) {
                    if (await reader.ReadAsync().ConfigureAwait(false))
                    {
                        settings.Action      = (PunishmentActionType)(short)reader["antiflood_action"];
                        settings.Cooldown    = (short)reader["antiflood_cooldown"];
                        settings.Enabled     = (bool)reader["antiflood_enabled"];
                        settings.Sensitivity = (short)reader["antiflood_sens"];
                    }
                }
            });

            return(settings);
        }
Example #11
0
        public static async Task MemberJoinProtectionEventHandlerAsync(TheGodfatherShard shard, GuildMemberAddEventArgs e)
        {
            if (e.Member == null || e.Member.IsBot)
            {
                return;
            }

            AntifloodSettings antifloodSettings = await shard.DatabaseService.GetAntifloodSettingsAsync(e.Guild.Id);

            if (antifloodSettings.Enabled)
            {
                await shard.CNext.Services.GetService <AntifloodService>().HandleMemberJoinAsync(e, antifloodSettings);
            }

            AntiInstantLeaveSettings antiILSettings = await shard.DatabaseService.GetAntiInstantLeaveSettingsAsync(e.Guild.Id);

            if (antiILSettings.Enabled)
            {
                await shard.CNext.Services.GetService <AntiInstantLeaveService>().HandleMemberJoinAsync(e, antiILSettings);
            }
        }