Beispiel #1
0
        static async Task NotifyActionLogsMentionsFound(Dictionary <ulong, List <DiscordMessage> > warnDict, DiscordChannel channel)
        {
            foreach (ulong snowflake in warnDict.Keys)
            {   // Iterate through each user snowflake logged in the dictionary.
                // Only make an embed if there are actually mentions.
                if (warnDict[snowflake].Count > 0)
                {
                    var mentionList = warnDict[snowflake];

                    var embed         = new DiscordEmbedBuilder();
                    var stringBuilder = new StringBuilder();

                    // Build header.
                    stringBuilder.Append($"__**{Generics.GetMention(snowflake)} has had {mentionList.Count + 1} total mention{(mentionList.Count == 1 ? String.Empty : @"s")} (including the most recent one)" +
                                         $"in {channel.Mention} in the last {Program.Settings.MaxActionAgeMonths} months:**__\n");

                    // Build link list.
                    stringBuilder.AppendJoin(' ',
                                             Generics.BuildLimitedLinkList(
                                                 links: mentionList
                                                 .Select(a => Generics.GetMessageUrl(a))
                                                 .ToArray(),
                                                 endMessage: @"... Too many to display...",
                                                 maxLength: 2000 - stringBuilder.Length));

                    embed.WithDescription(stringBuilder.ToString());
                    embed.WithTitle($"Previous mention{(mentionList.Count == 1 ? String.Empty : @"s")} found");
                    embed.WithColor(DiscordColor.Red);

                    await channel.SendMessageAsync(embed : embed);
                } // end if
            }     // end foreach
        }
Beispiel #2
0
        private static async Task FilterSystem_FilterTriggered(Filter.FilterEventArgs e)
        {
            var stringBuilder = new StringBuilder();

            // Append all the found bad words to the string builder.
            foreach (string str in e.BadWords)
            {
                stringBuilder.Append(str);
                stringBuilder.Append(' ');
            }

            // Create the Discord Embed
            var deb = new DiscordEmbedBuilder()
            {
                Title = "Filter: Word Detected",
                Color = DiscordColor.Red
            };

            deb.WithDescription(String.Format("Filter Trigger(s):```{0}```Excerpt:```{1}```",
                                              stringBuilder.ToString(), e.NotatedMessage));

            deb.AddField(@"Author ID", e.User.Id.ToString(), inline: true);
            deb.AddField(@"Author Username", $"{e.User.Username}#{e.User.Discriminator}", inline: true);
            deb.AddField(@"Author Mention", e.User.Mention, inline: true);
            deb.AddField(@"Channel", e.Channel.Mention, inline: true);
            deb.AddField(@"Timestamp (UTC)", e.Message.CreationTimestamp.UtcDateTime.ToString(Generics.DateFormat), inline: true);
            deb.AddField(@"Link", Generics.GetMessageUrl(e.Message));

            deb.WithThumbnail(Generics.URL_FILTER_BUBBLE);

            // Notify the filter channel.
            await NotifyFilterChannel(deb.Build());
        }
        public static async Task SeekWarns(CommandContext ctx, ulong[] memberIds)
        {
            const int MAX_FIELDS = 10;

            DiscordChannel actionLogChannel = await Program.BotClient.GetChannelAsync(Program.Settings.ActionChannelId);

            Dictionary <ulong, List <DiscordMessage> > warnDict =
                await QueryMemberMentions(memberIds.Distinct().ToList(), actionLogChannel, Program.Settings.MaxActionAgeMonths, ctx.Message);

            // Let's start paginating.
            var pages = new Page[warnDict.Keys.Count];
            int page  = 0;

            if (warnDict.Keys.Count > 0)
            {
                // Want to generate a page for each member.
                foreach (var member in warnDict.Keys)
                {
                    // We want a boolean to check first because if there's no key, we'll get an exception trying to get the count.
                    bool warnsFound = warnDict.ContainsKey(member) && warnDict[member].Count > 0;

                    var deb = new DiscordEmbedBuilder
                    {
                        Title       = $"Mentions found in action logs",
                        Description = Generics.NeutralDirectResponseTemplate(mention: ctx.Member.Mention,
                                                                             body: warnsFound ? // Warning, really f*****g long string ahead:
                                                                             $"I found {warnDict[member].Count} mention{(warnDict[member].Count == 1 ? String.Empty : @"s")} for " +
                                                                             $"{Generics.GetMention(member)} in {actionLogChannel.Mention} in the last {Program.Settings.MaxActionAgeMonths} months. " +
                                                                             $"{(warnDict[member].Count > MAX_FIELDS ? $"There are over {MAX_FIELDS}. I will only show the most recent." : String.Empty)}" :
                                                                             $"{ctx.Member.Mention}, I did not find any mentions for {Generics.GetMention(member)}. Good for them..."),
                        Color = warnsFound ? Generics.NegativeColor : Generics.NeutralColor
                    };

                    if (warnsFound)
                    {         // Only continue here if there are actually warns, otherwise just slap a footer on.
                        foreach (var message in warnDict[member])
                        {     // Generate a field for each detected message.
                            if (deb.Fields.Count < MAX_FIELDS)
                            { // Only continue if we have less than MAX_FIELDS fields.
                                // This SB is for all the content.
                                var stringBuilder = new StringBuilder();
                                // This SB is for all the misc information.
                                var stringBuilderFooter = new StringBuilder();

                                stringBuilder.Append($"{ChatObjects.Generics.GetMention(message.Author.Id)}: ");

                                stringBuilder.Append(message.Content);

                                if (message.Attachments.Count > 0)
                                {
                                    stringBuilderFooter.Append($"\n\n{Formatter.Bold(@"There is an image attached:")} ");

                                    stringBuilderFooter.Append(Formatter.MaskedUrl(@"Image", new Uri(message.Attachments[0].Url)));
                                } // end if

                                stringBuilderFooter.Append("\n\n");
                                stringBuilderFooter.Append(Formatter.MaskedUrl(@"Link", new Uri(Generics.GetMessageUrl(message))));

                                // We want to prefer the footer's information over the content. So let's figure out how much of the content we
                                // need to trim out.

                                var finalStringBuilder = new StringBuilder();

                                if (stringBuilder.Length + stringBuilderFooter.Length > 1000)
                                {     // We need to do some trimming.
                                    if (stringBuilder.Length > 0)
                                    { // Let's get the content in there.
                                        finalStringBuilder.Append(Generics.BuildLimitedString(
                                                                      originalString: stringBuilder.ToString(),
                                                                      endMessage: @". . . Unable to preview long message...",
                                                                      maxLength: 1000 - stringBuilderFooter.Length));
                                    }
                                    if (stringBuilderFooter.Length > 0)
                                    {   // Let's get the footer in there.
                                        finalStringBuilder.Append(stringBuilderFooter);
                                    }
                                }
                                else
                                {     // We don't need to do any trimming.
                                    if (stringBuilder.Length > 0)
                                    { // Let's get the content in there.
                                        finalStringBuilder.Append(stringBuilder);
                                    }
                                    if (stringBuilderFooter.Length > 0)
                                    {   // Let's get the footer in there.
                                        finalStringBuilder.Append(stringBuilderFooter);
                                    }
                                }

                                deb.AddField($"Action on {message.Timestamp.ToString(Generics.DateFormat)}", finalStringBuilder.ToString());
                            }
                            else
                            {          // Stop the loop if we have MAX_FIELDS fields.
                                break; // NON-SESE ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! !
                            } // end else
                        } // end foreach
                    } // end if

                    deb.WithFooter($"Page {page + 1}/{warnDict.Keys.Count}");

                    pages[page++] = new Page(embed: deb);
                } // end foreach
            }     // end if

            // Delete the message if it's the action channel so it's kind of out of the way and doesn't get logged again in the future.
            if (ctx.Message.ChannelId == Program.Settings.ActionChannelId)
            {
                await ctx.Message.DeleteAsync();
            }

            if (pages.Length > 1)
            {   // More than 1 page.
                var interactivity = Program.BotClient.GetInteractivity();

                await interactivity.SendPaginatedMessageAsync
                (
                    c : ctx.Channel,
                    u : ctx.User,
                    pages : pages,
                    emojis : Generics.DefaultPaginationEmojis
                );
            }
            else
            {   // Only one page, we want to send it as a regular embed instead.
                var anotherDeb = new DiscordEmbedBuilder(pages[0].Embed);

                // Clear the footer. We don't want the page count.
                anotherDeb.WithFooter(null, null);

                await ctx.Channel.SendMessageAsync(embed : anotherDeb);
            }
        }
Beispiel #4
0
        internal static async Task BotClientMessageReactionAdded(MessageReactionAddEventArgs e)
        {
            // We don't want the cached version of this message because if it was sent during downtime, the bot won't be able to do
            // anything with it.
            var message_noCache = await e.Channel.GetMessageAsync(e.Message.Id);

            // Before anything, let's make sure that...
            //  1) This is not the rimboard channel
            //  2) Rimboard is enabled.
            //  3) The Rimboard webhook is not default.
            //  4) This was not sent by the bot (requires nocache).
            if (e.Channel.Id != Program.Settings.RimboardChannelId &&
                e.Channel.Id != 401672277692776448 &&   // Temporary patch to ignore the announcements channel and
                e.Channel.Id != 220997547345313793 &&   // mod-updates channel while I work on the next
                Program.Settings.RimboardEnabled &&     // update. Please, please, PLEASE get a proper Rimboard-channel-ignore method at some point.
                Program.Settings.RimboardWebhookId != BotSettings.Default.RimboardWebhookId &&
                // De-cache the message so we can get its author.
                !(message_noCache.Author.IsBot))
            {
                DiscordEmoji emoji = GetReactionEmoji(e.Client);


                // This contains a list of the reactions that have rimboardEmoji. It's only ever really going to be be 1 long.
                var pinReactionsList = message_noCache.Reactions.Where(a => a.Emoji.Name == emoji.Name).ToArray();

                if (pinReactionsList.Length == 0)
                {
                    return;         // NON-SESE ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! !
                }
                int reactCount = pinReactionsList.FirstOrDefault().Count;

                // Let's now try to get the Rimboard message.

                PinInfo pinInfo = await QueryDatabaseForOriginalMessage(e.Message.Id, reactCount);

                bool validPinInfo = !pinInfo.Equals(PinInfo.Invalid);

                // Right now we want to check if the message has been posted already and react according to its reaction count.
                if (!validPinInfo && reactCount >= Program.Settings.RimboardReactionsNeeded)
                {   // We don't have stuff in the database, so it probably hasn't been pinned. Let's pin it.
                    bool file = false;

                    // DEB!
                    var deb = new DiscordEmbedBuilder();

                    deb.WithColor(DiscordColor.Gold);

                    UriBuilder avatarUri = new UriBuilder(message_noCache.Author.AvatarUrl)
                    {
                        Query = "?size=64"
                    };

                    deb.WithThumbnail(avatarUri.ToString());
                    deb.WithDescription(message_noCache.Content);
                    deb.AddField(@"Colonist", $"{message_noCache.Author.Mention}", true);
                    deb.AddField(@"Link", Generics.GetMessageUrl(message_noCache), true);

                    if (message_noCache.Attachments.Count > 0)
                    {
                        file = true;
                    }

                    // Let's send this shit already.

                    List <DiscordEmbed> embeds = new List <DiscordEmbed>
                    {
                        deb.Build()
                    };

                    if (message_noCache.Embeds.Count > 0)
                    {   // We only want to have up to 10 embeds. Keep in mind we alread have an embed, so we can only take up to 9.
                        embeds.AddRange(message_noCache.Embeds
                                        .Take(message_noCache.Embeds.Count >= 9 ? 9 : message_noCache.Embeds.Count));
                    }

                    DiscordMessage rimboardMessage;

#pragma warning disable IDE0063
                    if (file)
                    {   // Send a message with a file.
                        using (WebClient webclient = new WebClient())
                        {
                            string fileName = Path.Combine(
                                path1: Program.Files.RimboardTempFileDirectory,
                                path2: Path.ChangeExtension(
                                    path: Guid.NewGuid().ToString(),
                                    extension: Path.GetExtension(message_noCache.Attachments[0].FileName)));


                            await webclient.DownloadFileTaskAsync(new Uri(message_noCache.Attachments[0].Url), fileName);

                            using (FileStream fs = new FileStream(fileName, FileMode.Open))
                            {
                                // Send the file paired with the embed!

                                rimboardMessage = await WebhookDelegator.GetWebhook(webhookId : Program.Settings.RimboardWebhookId)
                                                  .SendWebhookMessage(
                                    embeds: embeds.ToArray(),
                                    fileStream: fs,
                                    fileName: fileName);
                            }

                            if (File.Exists(fileName))
                            {   // Delete it now that we're done with it.
                                File.Delete(fileName);
                            } // end if
                        } // end using
                    }
#pragma warning restore IDE0063
                    else
                    {   // Send a message with no file.
                        rimboardMessage = await WebhookDelegator.GetWebhook(webhookId : Program.Settings.RimboardWebhookId)
                                          .SendWebhookMessage(embeds: embeds.ToArray());
                    }

                    pinInfo = new PinInfo(
                        pinnedMessageId: rimboardMessage.Id,
                        pinnedChannelId: rimboardMessage.Channel.Id,
                        originalMessageId: message_noCache.Id,
                        originalChannelId: message_noCache.Channel.Id,
                        originalReactCount: reactCount);

                    validPinInfo = true; // The pin info has been validated.

                    await AddPinToDatabase(pinInfo);
                }
                else if (validPinInfo && reactCount >= Program.Settings.RimboardPinReactionsNeeded)
                {   // The pin is valid and is equal to or over the threshold to be actually pinned in the Rimboard channel.
                    var rimboardChannel = e.Guild.GetChannel(pinInfo.PinnedChannelId);

                    var b = rimboardChannel.GetPinnedMessagesAsync();
                    var c = rimboardChannel.GetMessageAsync(pinInfo.PinnedMessageId);

                    await Task.WhenAll(b, c);

                    var pinnedMessages = b.Result;
                    var messageToPin   = c.Result;

                    // Check if we need to get rid of the last pin.
                    if (pinnedMessages.Count() == 50)
                    {
                        await pinnedMessages.Last().UnpinAsync();
                    }

                    // Pin the message and react to it.
                    var f = messageToPin.PinAsync();
                    var g = messageToPin.CreateReactionAsync(GetPinEmoji(e.Client));

                    await Task.WhenAll(f, g);
                } // end else if
            }     // end if
        }         // end method