Пример #1
0
        private static DiscordEmbedBuilder FormatFilter(Piracystring filter, string error = null, int highlight = -1)
        {
            var field  = 1;
            var result = new DiscordEmbedBuilder
            {
                Title = "Filter preview",
                Color = string.IsNullOrEmpty(error) ? Config.Colors.Help : Config.Colors.Maintenance,
            };

            if (!string.IsNullOrEmpty(error))
            {
                result.AddField("Entry error", error);
            }

            var validTrigger = string.IsNullOrEmpty(filter.String) || filter.String.Length < Config.MinimumPiracyTriggerLength ? "⚠ " : "";

            result.AddFieldEx(validTrigger + "Trigger", filter.String, highlight == field++, true)
            .AddFieldEx("Context", filter.Context.ToString(), highlight == field++, true)
            .AddFieldEx("Actions", filter.Actions.ToFlagsString(), highlight == field++, true)
            .AddFieldEx("Validation", filter.ValidatingRegex, highlight == field++, true);
            if (filter.Actions.HasFlag(FilterAction.SendMessage))
            {
                result.AddFieldEx("Message", filter.CustomMessage, highlight == field, true);
            }
            field++;
            if (filter.Actions.HasFlag(FilterAction.ShowExplain))
            {
                var validExplainTerm = string.IsNullOrEmpty(filter.ExplainTerm) ? "⚠ " : "";
                result.AddFieldEx(validExplainTerm + "Explain", filter.ExplainTerm, highlight == field, true);
            }
#if DEBUG
            result.WithFooter("Test bot instance");
#endif
            return(result);
        }
Пример #2
0
        public async Task Add(CommandContext ctx, [RemainingText, Description("A plain string to match")] string trigger)
        {
            using (var db = new BotDb())
            {
                Piracystring filter;
                if (string.IsNullOrEmpty(trigger))
                {
                    filter = new Piracystring();
                }
                else
                {
                    filter = await db.Piracystring.FirstOrDefaultAsync(ps => ps.String == trigger && ps.Disabled).ConfigureAwait(false);

                    if (filter == null)
                    {
                        filter = new Piracystring {
                            String = trigger
                        }
                    }
                    ;
                    else
                    {
                        filter.Disabled = false;
                    }
                }
                var isNewFilter = filter.Id == default;
                if (isNewFilter)
                {
                    filter.Context = FilterContext.Chat | FilterContext.Log;
                    filter.Actions = FilterAction.RemoveContent | FilterAction.IssueWarning | FilterAction.SendMessage;
                }

                var(success, msg) = await EditFilterPropertiesAsync(ctx, db, filter).ConfigureAwait(false);

                if (success)
                {
                    if (isNewFilter)
                    {
                        await db.Piracystring.AddAsync(filter).ConfigureAwait(false);
                    }
                    await db.SaveChangesAsync().ConfigureAwait(false);

                    await msg.UpdateOrCreateMessageAsync(ctx.Channel, embed : FormatFilter(filter).WithTitle("Created a new content filter")).ConfigureAwait(false);

                    var member    = ctx.Member ?? ctx.Client.GetMember(ctx.User);
                    var reportMsg = $"{member.GetMentionWithNickname()} added a new content filter: `{filter.String.Sanitize()}`";
                    if (!string.IsNullOrEmpty(filter.ValidatingRegex))
                    {
                        reportMsg += $"\nValidation: `{filter.ValidatingRegex}`";
                    }
                    await ctx.Client.ReportAsync("🆕 Content filter created", reportMsg, null, ReportSeverity.Low).ConfigureAwait(false);

                    ContentFilter.RebuildMatcher();
                }
                else
                {
                    await msg.UpdateOrCreateMessageAsync(ctx.Channel, "Content filter creation aborted").ConfigureAwait(false);
                }
            }
        }
Пример #3
0
        private async Task EditFilterCmd(CommandContext ctx, BotDb db, Piracystring filter)
        {
            var(success, msg) = await EditFilterPropertiesAsync(ctx, db, filter).ConfigureAwait(false);

            if (success)
            {
                await db.SaveChangesAsync().ConfigureAwait(false);

                await msg.UpdateOrCreateMessageAsync(ctx.Channel, embed : FormatFilter(filter).WithTitle("Updated content filter")).ConfigureAwait(false);

                var member    = ctx.Member ?? ctx.Client.GetMember(ctx.User);
                var reportMsg = $"{member.GetMentionWithNickname()} changed content filter: `{filter.String.Sanitize()}`";
                if (!string.IsNullOrEmpty(filter.ValidatingRegex))
                {
                    reportMsg += $"\nValidation: `{filter.ValidatingRegex}`";
                }
                await ctx.Client.ReportAsync("🆙 Content filter updated", reportMsg, null, ReportSeverity.Low).ConfigureAwait(false);

                ContentFilter.RebuildMatcher();
            }
            else
            {
                await msg.UpdateOrCreateMessageAsync(ctx.Channel, "Content filter update aborted").ConfigureAwait(false);
            }
        }
Пример #4
0
        public static Task <Piracystring> FindTriggerAsync(FilterContext ctx, string str)
        {
            if (string.IsNullOrEmpty(str))
            {
                return(Task.FromResult((Piracystring)null));
            }


            if (!filters.TryGetValue(ctx, out var matcher))
            {
                return(Task.FromResult((Piracystring)null));
            }

            Piracystring result = null;

            matcher?.ParseText(str, h =>
            {
                if (string.IsNullOrEmpty(h.Value.ValidatingRegex) || Regex.IsMatch(str, h.Value.ValidatingRegex, RegexOptions.IgnoreCase | RegexOptions.Multiline))
                {
                    result = h.Value;
                    return(h.Value.Actions.HasFlag(FilterAction.RemoveContent));
                }
                return(true);
            });

            return(Task.FromResult(result));
        }
Пример #5
0
        public static bool IsComplete(this Piracystring filter)
        {
            var result = !string.IsNullOrEmpty(filter.String) &&
                         filter.String.Length >= Config.MinimumPiracyTriggerLength &&
                         filter.Actions != 0;

            if (result && filter.Actions.HasFlag(FilterAction.ShowExplain))
            {
                result = !string.IsNullOrEmpty(filter.ExplainTerm);
            }
            return(result);
        }
Пример #6
0
 private static async Task PiracyCheckAsync(string line, LogParseState state)
 {
     if (await ContentFilter.FindTriggerAsync(FilterContext.Log, line).ConfigureAwait(false) is Piracystring match &&
         match.Actions.HasFlag(FilterAction.RemoveContent))
     {
         var m = match;
         if (line.Contains("not valid, removing from") || line.Contains("Invalid disc path registered"))
         {
             m = new Piracystring
             {
                 Id              = match.Id,
                 Actions         = match.Actions & ~FilterAction.IssueWarning,
                 Context         = match.Context,
                 CustomMessage   = match.CustomMessage,
                 Disabled        = match.Disabled,
                 ExplainTerm     = match.ExplainTerm,
                 String          = match.String,
                 ValidatingRegex = match.ValidatingRegex,
             }
         }
         ;
         if (state.FilterTriggers.TryGetValue(m.Id, out var fh))
         {
             var updatedActions = fh.filter.Actions | m.Actions;
             if (fh.context.Length > line.Length)
             {
                 m.Actions = updatedActions;
                 state.FilterTriggers[m.Id] = (m, line.ToUtf8());
             }
             else
             {
                 fh.filter.Actions = updatedActions;
             }
             if (updatedActions.HasFlag(FilterAction.IssueWarning))
             {
                 state.Error = LogParseState.ErrorCode.PiracyDetected;
             }
         }
         else
         {
             var utf8line = line.ToUtf8();
             state.FilterTriggers[m.Id] = (m, utf8line);
             if (m.Actions.HasFlag(FilterAction.IssueWarning))
             {
                 state.Error = LogParseState.ErrorCode.PiracyDetected;
             }
         }
     }
 }
Пример #7
0
        private async Task <(bool success, DiscordMessage message)> EditFilterPropertiesAsync(CommandContext ctx, BotDb db, Piracystring filter)
        {
            var interact     = ctx.Client.GetInteractivity();
            var abort        = DiscordEmoji.FromUnicode("🛑");
            var lastPage     = DiscordEmoji.FromUnicode("↪");
            var firstPage    = DiscordEmoji.FromUnicode("↩");
            var previousPage = DiscordEmoji.FromUnicode("⏪");
            var nextPage     = DiscordEmoji.FromUnicode("⏩");
            var trash        = DiscordEmoji.FromUnicode("🗑");
            var saveEdit     = DiscordEmoji.FromUnicode("💾");

            var letterC = DiscordEmoji.FromUnicode("🇨");
            var letterL = DiscordEmoji.FromUnicode("🇱");
            var letterR = DiscordEmoji.FromUnicode("🇷");
            var letterW = DiscordEmoji.FromUnicode("🇼");
            var letterM = DiscordEmoji.FromUnicode("🇲");
            var letterE = DiscordEmoji.FromUnicode("🇪");

            DiscordMessage msg      = null;
            string         errorMsg = null;
            DiscordMessage txt;
            MessageReactionAddEventArgs emoji;

step1:
            // step 1: define trigger string
            var embed = FormatFilter(filter, errorMsg, 1)
                        .WithDescription(
                "Any simple string that is used to flag potential content for a check using Validation regex.\n" +
                "**Must** be sufficiently long to reduce the number of checks."
                );

            msg = await msg.UpdateOrCreateMessageAsync(ctx.Channel, "Please specify a new **trigger**", embed : embed).ConfigureAwait(false);

            errorMsg          = null;
            (msg, txt, emoji) = await interact.WaitForMessageOrReactionAsync(msg, ctx.User, InteractTimeout, abort, lastPage, nextPage, (filter.IsComplete() ? saveEdit : null)).ConfigureAwait(false);

            if (emoji != null)
            {
                if (emoji.Emoji == abort)
                {
                    return(false, msg);
                }

                if (emoji.Emoji == saveEdit)
                {
                    return(true, msg);
                }

                if (emoji.Emoji == lastPage)
                {
                    if (filter.Actions.HasFlag(FilterAction.ShowExplain))
                    {
                        goto step6;
                    }

                    if (filter.Actions.HasFlag(FilterAction.SendMessage))
                    {
                        goto step5;
                    }

                    goto step4;
                }
            }
            else if (txt?.Content != null)
            {
                if (txt.Content.Length < Config.MinimumPiracyTriggerLength)
                {
                    errorMsg = "Trigger is too short";
                    goto step1;
                }

                filter.String = txt.Content;
            }
            else
            {
                return(false, msg);
            }

step2:
            // step 2: context of the filter where it is applicable
            embed = FormatFilter(filter, errorMsg, 2)
                    .WithDescription(
                "Context of the filter indicates where it is applicable.\n" +
                $"**`C`** = **`{FilterContext.Chat}`** will apply it in filtering discord messages.\n" +
                $"**`L`** = **`{FilterContext.Log}`** will apply it during log parsing.\n" +
                "Reactions will toggle the context, text message will set the specified flags."
                );
            msg = await msg.UpdateOrCreateMessageAsync(ctx.Channel, "Please specify filter **context(s)**", embed : embed).ConfigureAwait(false);

            errorMsg          = null;
            (msg, txt, emoji) = await interact.WaitForMessageOrReactionAsync(msg, ctx.User, InteractTimeout, abort, previousPage, nextPage, letterC, letterL, (filter.IsComplete() ? saveEdit : null)).ConfigureAwait(false);

            if (emoji != null)
            {
                if (emoji.Emoji == abort)
                {
                    return(false, msg);
                }

                if (emoji.Emoji == saveEdit)
                {
                    return(true, msg);
                }

                if (emoji.Emoji == previousPage)
                {
                    goto step1;
                }

                if (emoji.Emoji == letterC)
                {
                    filter.Context ^= FilterContext.Chat;
                    goto step2;
                }

                if (emoji.Emoji == letterL)
                {
                    filter.Context ^= FilterContext.Log;
                    goto step2;
                }
            }
            else if (txt != null)
            {
                var           flagsTxt = txt.Content.Split(Separators, StringSplitOptions.RemoveEmptyEntries);
                FilterContext newCtx   = 0;
                foreach (var f in flagsTxt)
                {
                    switch (f.ToUpperInvariant())
                    {
                    case "C":
                    case "CHAT":
                        newCtx |= FilterContext.Chat;
                        break;

                    case "L":
                    case "LOG":
                    case "LOGS":
                        newCtx |= FilterContext.Log;
                        break;

                    case "ABORT":
                        return(false, msg);

                    case "-":
                    case "SKIP":
                    case "NEXT":
                        break;

                    default:
                        errorMsg = $"Unknown context `{f}`.";
                        goto step2;
                    }
                }
                filter.Context = newCtx;
            }
            else
            {
                return(false, msg);
            }

step3:
            // step 3: actions that should be performed on match
            embed = FormatFilter(filter, errorMsg, 3)
                    .WithDescription(
                "Actions that will be executed on positive match.\n" +
                $"**`R`** = **`{FilterAction.RemoveContent}`** will remove the message / log.\n" +
                $"**`W`** = **`{FilterAction.IssueWarning}`** will issue a warning to the user.\n" +
                $"**`M`** = **`{FilterAction.SendMessage}`** send _a_ message with an explanation of why it was removed.\n" +
                $"**`E`** = **`{FilterAction.ShowExplain}`** show `explain` for the specified term (**not implemented**).\n" +
                "Reactions will toggle the action, text message will set the specified flags."
                );
            msg = await msg.UpdateOrCreateMessageAsync(ctx.Channel, "Please specify filter **action(s)**", embed : embed).ConfigureAwait(false);

            errorMsg          = null;
            (msg, txt, emoji) = await interact.WaitForMessageOrReactionAsync(msg, ctx.User, InteractTimeout, abort, previousPage, nextPage, letterR, letterW, letterM, letterE, (filter.IsComplete() ? saveEdit : null)).ConfigureAwait(false);

            if (emoji != null)
            {
                if (emoji.Emoji == abort)
                {
                    return(false, msg);
                }

                if (emoji.Emoji == saveEdit)
                {
                    return(true, msg);
                }

                if (emoji.Emoji == previousPage)
                {
                    goto step2;
                }

                if (emoji.Emoji == letterR)
                {
                    filter.Actions ^= FilterAction.RemoveContent;
                    goto step3;
                }

                if (emoji.Emoji == letterW)
                {
                    filter.Actions ^= FilterAction.IssueWarning;
                    goto step3;
                }

                if (emoji.Emoji == letterM)
                {
                    filter.Actions ^= FilterAction.SendMessage;
                    goto step3;
                }

                if (emoji.Emoji == letterE)
                {
                    filter.Actions ^= FilterAction.ShowExplain;
                    goto step3;
                }
            }
            else if (txt != null)
            {
                var flagsTxt = txt.Content.ToUpperInvariant().Split(Separators, StringSplitOptions.RemoveEmptyEntries);
                if (flagsTxt.Length == 1 &&
                    flagsTxt[0].Length <= Enum.GetValues(typeof(FilterAction)).Length)
                {
                    flagsTxt = flagsTxt[0].Select(c => c.ToString()).ToArray();
                }
                FilterAction newActions = 0;
                foreach (var f in flagsTxt)
                {
                    switch (f)
                    {
                    case "R":
                    case "REMOVE":
                    case "REMOVEMESSAGE":
                        newActions |= FilterAction.RemoveContent;
                        break;

                    case "W":
                    case "WARN":
                    case "WARNING":
                    case "ISSUEWARNING":
                        newActions |= FilterAction.IssueWarning;
                        break;

                    case "M":
                    case "MSG":
                    case "MESSAGE":
                    case "SENDMESSAGE":
                        newActions |= FilterAction.SendMessage;
                        break;

                    case "E":
                    case "X":
                    case "EXPLAIN":
                    case "SHOWEXPLAIN":
                    case "SENDEXPLAIN":
                        newActions |= FilterAction.ShowExplain;
                        break;

                    case "ABORT":
                        return(false, msg);

                    case "-":
                    case "SKIP":
                    case "NEXT":
                        break;

                    default:
                        errorMsg = $"Unknown action `{f.ToLowerInvariant()}`.";
                        goto step2;
                    }
                }
                filter.Actions = newActions;
            }
            else
            {
                return(false, msg);
            }

step4:
            // step 4: validation regex to filter out false positives of the plaintext triggers
            embed = FormatFilter(filter, errorMsg, 4)
                    .WithDescription(
                "Validation [regex](https://docs.microsoft.com/en-us/dotnet/standard/base-types/regular-expression-language-quick-reference) to optionally perform more strict trigger check.\n" +
                "**Please [test](https://regex101.com/) your regex**. Following flags are enabled: Multiline, IgnoreCase.\n" +
                "Additional validation can help reduce false positives of a plaintext trigger match."
                );
            msg = await msg.UpdateOrCreateMessageAsync(ctx.Channel, "Please specify filter **validation regex**", embed : embed).ConfigureAwait(false);

            errorMsg = null;
            var next = (filter.Actions & (FilterAction.SendMessage | FilterAction.ShowExplain)) == 0 ? firstPage : nextPage;

            (msg, txt, emoji) = await interact.WaitForMessageOrReactionAsync(msg, ctx.User, InteractTimeout, abort, previousPage, next, (string.IsNullOrEmpty(filter.ValidatingRegex) ? null : trash), (filter.IsComplete() ? saveEdit : null)).ConfigureAwait(false);

            if (emoji != null)
            {
                if (emoji.Emoji == abort)
                {
                    return(false, msg);
                }

                if (emoji.Emoji == saveEdit)
                {
                    return(true, msg);
                }

                if (emoji.Emoji == previousPage)
                {
                    goto step3;
                }

                if (emoji.Emoji == firstPage)
                {
                    goto step1;
                }

                if (emoji.Emoji == trash)
                {
                    filter.ValidatingRegex = null;
                }
            }
            else if (txt != null)
            {
                if (string.IsNullOrWhiteSpace(txt.Content) || txt.Content == "-" || txt.Content == ".*")
                {
                    filter.ValidatingRegex = null;
                }
                else
                {
                    try
                    {
                        Regex.IsMatch("test", txt.Content, RegexOptions.Multiline | RegexOptions.IgnoreCase);
                    }
                    catch (Exception e)
                    {
                        errorMsg = "Invalid regex expression: " + e.Message;
                        goto step4;
                    }

                    filter.ValidatingRegex = txt.Content;
                }
            }
            else
            {
                return(false, msg);
            }

            if (filter.Actions.HasFlag(FilterAction.SendMessage))
            {
                goto step5;
            }
            else if (filter.Actions.HasFlag(FilterAction.ShowExplain))
            {
                goto step6;
            }
            else
            {
                goto stepConfirm;
            }

step5:
            // step 5: optional custom message for the user
            embed = FormatFilter(filter, errorMsg, 5)
                    .WithDescription(
                "Optional custom message sent to the user.\n" +
                "If left empty, default piracy warning message will be used."
                );
            msg = await msg.UpdateOrCreateMessageAsync(ctx.Channel, "Please specify filter **validation regex**", embed : embed).ConfigureAwait(false);

            errorMsg          = null;
            next              = (filter.Actions.HasFlag(FilterAction.ShowExplain) ? nextPage : firstPage);
            (msg, txt, emoji) = await interact.WaitForMessageOrReactionAsync(msg, ctx.User, InteractTimeout, abort, previousPage, next, (filter.IsComplete() ? saveEdit : null)).ConfigureAwait(false);

            if (emoji != null)
            {
                if (emoji.Emoji == abort)
                {
                    return(false, msg);
                }

                if (emoji.Emoji == saveEdit)
                {
                    return(true, msg);
                }

                if (emoji.Emoji == previousPage)
                {
                    goto step4;
                }

                if (emoji.Emoji == firstPage)
                {
                    goto step1;
                }
            }
            else if (txt != null)
            {
                if (string.IsNullOrWhiteSpace(txt.Content) || txt.Content == "-")
                {
                    filter.CustomMessage = null;
                }
                else
                {
                    filter.CustomMessage = txt.Content;
                }
            }
            else
            {
                return(false, msg);
            }

            if (filter.Actions.HasFlag(FilterAction.ShowExplain))
            {
                goto step6;
            }
            else
            {
                goto stepConfirm;
            }

step6:
            // step 6: show explanation for the term
            embed = FormatFilter(filter, errorMsg, 6)
                    .WithDescription(
                "Explanation term that is used to show an explanation.\n" +
                "**__Currently not implemented__**."
                );
            msg = await msg.UpdateOrCreateMessageAsync(ctx.Channel, "Please specify filter **explanation term**", embed : embed).ConfigureAwait(false);

            errorMsg          = null;
            (msg, txt, emoji) = await interact.WaitForMessageOrReactionAsync(msg, ctx.User, InteractTimeout, abort, previousPage, firstPage, (filter.IsComplete() ? saveEdit : null)).ConfigureAwait(false);

            if (emoji != null)
            {
                if (emoji.Emoji == abort)
                {
                    return(false, msg);
                }

                if (emoji.Emoji == saveEdit)
                {
                    return(true, msg);
                }

                if (emoji.Emoji == previousPage)
                {
                    if (filter.Actions.HasFlag(FilterAction.SendMessage))
                    {
                        goto step5;
                    }
                    else
                    {
                        goto step4;
                    }
                }

                if (emoji.Emoji == firstPage)
                {
                    goto step1;
                }
            }
            else if (txt != null)
            {
                if (string.IsNullOrWhiteSpace(txt.Content) || txt.Content == "-")
                {
                    filter.ExplainTerm = null;
                }
                else
                {
                    var existingTerm = await db.Explanation.FirstOrDefaultAsync(exp => exp.Keyword == txt.Content.ToLowerInvariant()).ConfigureAwait(false);

                    if (existingTerm == null)
                    {
                        errorMsg = $"Term `{txt.Content.ToLowerInvariant().Sanitize()}` is not defined.";
                        goto step6;
                    }

                    filter.ExplainTerm = txt.Content;
                }
            }
            else
            {
                return(false, msg);
            }

stepConfirm:
            // last step: confirm
            if (errorMsg == null && !filter.IsComplete())
            {
                errorMsg = "Some required properties are not defined";
            }
            embed = FormatFilter(filter, errorMsg);
            msg   = await msg.UpdateOrCreateMessageAsync(ctx.Channel, "Does this look good? (y/n)", embed : embed.Build()).ConfigureAwait(false);

            errorMsg          = null;
            (msg, txt, emoji) = await interact.WaitForMessageOrReactionAsync(msg, ctx.User, InteractTimeout, abort, previousPage, firstPage, (filter.IsComplete() ? saveEdit : null)).ConfigureAwait(false);

            if (emoji != null)
            {
                if (emoji.Emoji == abort)
                {
                    return(false, msg);
                }

                if (emoji.Emoji == saveEdit)
                {
                    return(true, msg);
                }

                if (emoji.Emoji == previousPage)
                {
                    if (filter.Actions.HasFlag(FilterAction.ShowExplain))
                    {
                        goto step6;
                    }

                    if (filter.Actions.HasFlag(FilterAction.SendMessage))
                    {
                        goto step5;
                    }

                    goto step4;
                }

                if (emoji.Emoji == firstPage)
                {
                    goto step1;
                }
            }
            else if (!string.IsNullOrEmpty(txt?.Content))
            {
                if (!filter.IsComplete())
                {
                    goto step5;
                }

                switch (txt.Content.ToLowerInvariant())
                {
                case "yes":
                case "y":
                case "✅":
                case "☑":
                case "✔":
                case "👌":
                case "👍":
                    return(true, msg);

                case "no":
                case "n":
                case "❎":
                case "❌":
                case "👎":
                    return(false, msg);

                default:
                    errorMsg = "I don't know what you mean, so I'll just abort";
                    if (filter.Actions.HasFlag(FilterAction.ShowExplain))
                    {
                        goto step6;
                    }

                    if (filter.Actions.HasFlag(FilterAction.SendMessage))
                    {
                        goto step5;
                    }

                    goto step4;
                }
            }
            else
            {
                return(false, msg);
            }
            return(false, msg);
        }
Пример #8
0
        public static async Task PerformFilterActions(DiscordClient client, DiscordMessage message, Piracystring trigger, FilterAction ignoreFlags = 0, string triggerContext = null, string infraction = null, string warningReason = null)
        {
            if (trigger == null)
            {
                return;
            }

            var severity         = ReportSeverity.Low;
            var completedActions = new List <FilterAction>();

            if (trigger.Actions.HasFlag(FilterAction.RemoveContent) && !ignoreFlags.HasFlag(FilterAction.RemoveContent))
            {
                try
                {
                    DeletedMessagesMonitor.RemovedByBotCache.Set(message.Id, true, DeletedMessagesMonitor.CacheRetainTime);
                    await message.Channel.DeleteMessageAsync(message, $"Removed according to filter '{trigger}'").ConfigureAwait(false);

                    completedActions.Add(FilterAction.RemoveContent);
                }
                catch (Exception e)
                {
                    Config.Log.Warn(e);
                    severity = ReportSeverity.High;
                }
                try
                {
                    var author = client.GetMember(message.Author);
                    Config.Log.Debug($"Removed message from {author.GetMentionWithNickname()} in #{message.Channel.Name}: {message.Content}");
                }
                catch (Exception e)
                {
                    Config.Log.Warn(e);
                }
            }

            if (trigger.Actions.HasFlag(FilterAction.IssueWarning) && !ignoreFlags.HasFlag(FilterAction.IssueWarning))
            {
                try
                {
                    await Warnings.AddAsync(client, message, message.Author.Id, message.Author.Username, client.CurrentUser, warningReason ?? "Mention of piracy", message.Content.Sanitize()).ConfigureAwait(false);

                    completedActions.Add(FilterAction.IssueWarning);
                }
                catch (Exception e)
                {
                    Config.Log.Warn(e, $"Couldn't issue warning in #{message.Channel.Name}");
                }
            }

            if (trigger.Actions.HasFlag(FilterAction.SendMessage) && !ignoreFlags.HasFlag(FilterAction.SendMessage))
            {
                try
                {
                    var msgContent = trigger.CustomMessage;
                    if (string.IsNullOrEmpty(msgContent))
                    {
                        var rules = await client.GetChannelAsync(Config.BotRulesChannelId).ConfigureAwait(false);

                        msgContent = $"Please follow the {rules.Mention} and do not discuss piracy on this server. Repeated offence may result in a ban.";
                    }
                    await message.Channel.SendMessageAsync($"{message.Author.Mention} {msgContent}").ConfigureAwait(false);

                    completedActions.Add(FilterAction.SendMessage);
                }
                catch (Exception e)
                {
                    Config.Log.Warn(e, $"Failed to send message in #{message.Channel.Name}");
                }
            }

            if (trigger.Actions.HasFlag(FilterAction.ShowExplain) && !ignoreFlags.HasFlag(FilterAction.ShowExplain))
            {
                var result = await Explain.LookupTerm(trigger.ExplainTerm).ConfigureAwait(false);

                await Explain.SendExplanation(result, trigger.ExplainTerm, message).ConfigureAwait(false);
            }

            var actionList = "";

            foreach (FilterAction fa in Enum.GetValues(typeof(FilterAction)))
            {
                if (trigger.Actions.HasFlag(fa) && !ignoreFlags.HasFlag(fa))
                {
                    actionList += (completedActions.Contains(fa) ? "✅" : "❌") + " " + fa + ' ';
                }
            }

            try
            {
                if (!trigger.Actions.HasFlag(FilterAction.MuteModQueue) && !ignoreFlags.HasFlag(FilterAction.MuteModQueue))
                {
                    await client.ReportAsync(infraction ?? "🤬 Content filter hit", message, trigger.String, triggerContext ?? message.Content, severity, actionList).ConfigureAwait(false);
                }
            }
            catch (Exception e)
            {
                Config.Log.Error(e, "Failed to report content filter hit");
            }
        }
Пример #9
0
 private static async Task <(bool success, DiscordMessage?message)> EditFilterPropertiesAsync(CommandContext ctx, BotDb db, Piracystring filter)
 {
     try
     {
         return(await EditFilterPropertiesInternalAsync(ctx, db, filter).ConfigureAwait(false));
     }
     catch (Exception e)
     {
         Config.Log.Error(e, "Failed to edit content filter");
         return(false, null);
     }
 }