Example #1
0
    public void Trim()
    {
        using var cmd   = _sql.CreateCommand();
        cmd.CommandText = "DELETE FROM log WHERE message_id < @message_id";
        var cutoff = SnowflakeUtils.ToSnowflake(DateTime.UtcNow.AddDays(-7));

        cmd.Parameters.AddWithValue("message_id", (long)cutoff);
        cmd.ExecuteNonQuery();
    }
Example #2
0
        private async void CleanUpOldMessages(SocketTextChannel channel, TimeSpan toDeleteOlderThan)
        {
            DateTime oneWeekAgo          = DateTime.Now.Add(toDeleteOlderThan);
            ulong    oneWeekAgoSnowflake = SnowflakeUtils.ToSnowflake(oneWeekAgo);
            var      oldMessages         = await channel.GetMessagesAsync(oneWeekAgoSnowflake, Direction.Before, 100 /*100 should be enought for a while*/).FlattenAsync();

            await channel.DeleteMessagesAsync(oldMessages);

            //var messageDelete = await channel.SendMessageAsync($"Deleting {oldMessages.Count()} messages"); // enable when this message is correct
            //Task.Delay(TimeSpan.FromMinutes(5));
            //messageDelete.DeleteAsync();
        }
Example #3
0
        public static async Task <string> GenerateMovieForUsers(ulong guildId, int hoursAmount = -1, int fps = 30, int groupByHours = 24, int groupByMinutes = -1, bool stacked = true, bool drawDots = true, string filePrefix = "", params ulong[] channelIds)
        {
            Stopwatch watch = new Stopwatch();

            watch.Start();
            var messageInfos = GetUserMessageInfos(hoursAmount < 0 ? null : SnowflakeUtils.ToSnowflake(DateTimeOffset.Now.AddHours(hoursAmount * (-1))));

            watch.Stop();

            var userIdsOfTopPosters = messageInfos.GroupBy(i => i.KeyId).OrderByDescending(i => i.Count()).Take(50).Select(i => i.Key);

            //await Context.Channel.SendMessageAsync($"Retrieved data in {watch.ElapsedMilliseconds}ms");

            var groups = GroupGraphEntryInfoBy(groupByHours, groupByMinutes, messageInfos);
            var keys   = groups.Select(x => x.Key);

            keys = FillMissingEntries(keys, new TimeSpan(Math.Max(groupByHours, 0), Math.Max(groupByMinutes, 0), 0));

            var users = DatabaseManager.Instance().GetDiscordUsers();

            users = users.Where(i => userIdsOfTopPosters.Contains(i.DiscordUserId)).ToList();

            //await Context.Channel.SendMessageAsync($"Total frames {groups.Count()}");

            var parsedMessageInfos = GetUserParsedMessageInfos(groups, users);

            (string basePath, string baseOutputPath) = CleanAndCreateMovieFolders();

            if (stacked)
            {
                StackResults(parsedMessageInfos);
            }

            try
            {
                await GenerateFrames(keys, parsedMessageInfos, basePath, drawDots);

                string fileName = await RunFFMpeg(basePath, baseOutputPath, fps, filePrefix);

                return(fileName);
            }
            catch (Exception ex)
            {
                //_logger.LogError(ex, "Error while creating movie");
                return(null);
            }
        }
Example #4
0
        public async Task ReportAsync(IUser user, [Remainder] string reportMessage = null)
        {
            if (Context.Guild != null)
            {
                await Context.Channel.DeleteMessageAsync(Context.Message);
            }

            if (string.IsNullOrEmpty(reportMessage))
            {
                throw new Exception("Please enter in a description of the report!");
            }

            var previous = Context.Guild != null?GetPreviousMessage(user) : null;

            var reportId = previous?.Id ?? SnowflakeUtils.ToSnowflake(DateTimeOffset.UtcNow);
            await QuickReportWatcher.FileReport(reportId, Context.User, user, Context.Channel, previous, reportMessage);
        }
Example #5
0
        public async Task CountMessages(SocketGuildUser userAccount = null)
        {
            var user = Context.User as SocketGuildUser;

            var weekFilter  = SnowflakeUtils.ToSnowflake(DateTimeOffset.UtcNow - TimeSpan.FromDays(7));
            var monthFilter = SnowflakeUtils.ToSnowflake(DateTimeOffset.UtcNow - TimeSpan.FromDays(31));
            var getWeek     = await Context.Channel.GetMessagesAsync(weekFilter, Direction.After, 1000, CacheMode.AllowDownload).FlattenAsync();

            var getMonth = await Context.Channel.GetMessagesAsync(monthFilter, Direction.After, 1000, CacheMode.AllowDownload).FlattenAsync();

            if (userAccount == null)
            {
                var userWeekMessages  = getWeek.Where(x => x.Author.Id == Context.User.Id);
                var userMonthMessages = getMonth.Where(x => x.Author.Id == Context.User.Id);

                var weekCount  = userWeekMessages.Count();
                var monthCount = userMonthMessages.Count();

                var embed = new EmbedBuilder();
                embed.WithAuthor(user);
                embed.WithDescription($"**User Message Counts**\n7 Days: `{weekCount} messages`\n31 Days: `{monthCount} messages`");
                embed.WithColor(Color.Blue);
                embed.WithCurrentTimestamp();
                await Context.Channel.SendMessageAsync("", false, embed.Build());
            }
            else
            {
                var userWeekMessages  = getWeek.Where(x => x.Author.Id == userAccount.Id);
                var userMonthMessages = getMonth.Where(x => x.Author.Id == userAccount.Id);

                var weekCount  = userWeekMessages.Count();
                var monthCount = userMonthMessages.Count();

                var embed = new EmbedBuilder();
                embed.WithAuthor(userAccount);
                embed.WithDescription($"**User Message Counts**\n7 Days: `{weekCount} messages`\n31 Days: `{monthCount} messages`");
                embed.WithColor(Color.Blue);
                embed.WithCurrentTimestamp();
                await Context.Channel.SendMessageAsync("", false, embed.Build());
            }
        }
        protected override void OnMessage(MessageEventArgs e)
        {
            Program.LogMsg(e.Data, LogSeverity.Verbose, "AppealsMsg");
            var json = JObject.Parse(e.Data);
            var type = json["type"].ToString();

            if (type == "GetMessages")
            {
                var before   = json["before"].ToObject <long>();
                var msgId    = SnowflakeUtils.ToSnowflake(DateTimeOffset.FromUnixTimeMilliseconds(before));
                var messages = Appeal.AppealChannel.GetMessagesAsync(msgId, Direction.Before).FlattenAsync().Result;
                foreach (var x in messages)
                {
                    if (x is IUserMessage u)
                    {
                        NewMessage(u);
                    }
                }
            }
            else if (type == "SendMessage")
            {
                if (Appeal.IsMuted)
                {
                    var time = Program.FormatTimeSpan(Appeal.MutedUntil.Value - DateTime.Now, true);
                    SendInfo("Error: This ban appeal is muted.", time);
                }
                else
                {
                    var content = json["content"].ToString();
                    try
                    {
                        Appeal.SendMessageAsync(content, User.Name, User.GetAvatarUrl()).Wait();
                    } catch (Exception ex)
                    {
                        Program.LogMsg(ex, "BanAppeal");
                        SendInfo($"Exception occured: {ex.Message}");
                    }
                }
            }
        }
Example #7
0
        public async ValueTask HandleLoggerBotCleanup(SocketMessage msg, GuildConfig cachedGuild)
        {
            // Bail if not enabled, or if we don't have permission here
            if (!cachedGuild.LogCleanupEnabled)
            {
                return;
            }
            if (!(msg.Channel is SocketTextChannel channel))
            {
                return;
            }
            if (!channel.Guild.GetUser(_client.CurrentUser.Id).GetPermissions(channel).ManageMessages)
            {
                return;
            }

            // If this message is from a *webhook*, check if the name matches one of the bots we know
            // TODO: do we need to do a deeper webhook origin check, or would that be too hard on the rate limit?
            // If it's from a *bot*, check the bot ID to see if we know it.
            LoggerBot bot = null;

            if (msg.Author.IsWebhook)
            {
                _botsByWebhookName.TryGetValue(msg.Author.Username, out bot);
            }
            else if (msg.Author.IsBot)
            {
                _bots.TryGetValue(msg.Author.Id, out bot);
            }

            // If we didn't find anything before, or what we found is an unsupported bot, bail
            if (bot == null)
            {
                return;
            }

            // We try two ways of extracting the actual message, depending on the bots
            if (bot.FuzzyExtractFunc != null)
            {
                // Some bots (Carl, Circle, etc) only give us a user ID and a rough timestamp, so we try our best to
                // "cross-reference" those with the message DB. We know the deletion event happens *after* the message
                // was sent, so we're checking for any messages sent in the same guild within 3 seconds before the
                // delete event timestamp, which is... good enough, I think? Potential for false positives and negatives
                // either way but shouldn't be too much, given it's constrained by user ID and guild.
                var fuzzy = bot.FuzzyExtractFunc(msg);
                if (fuzzy == null)
                {
                    return;
                }

                using var conn = await _db.Obtain();

                var mid = await conn.QuerySingleOrDefaultAsync <ulong?>(
                    "select mid from messages where sender = @User and mid > @ApproxID and guild = @Guild",
                    new
                {
                    fuzzy.Value.User,
                    Guild    = (msg.Channel as ITextChannel)?.GuildId ?? 0,
                    ApproxId = SnowflakeUtils.ToSnowflake(fuzzy.Value.ApproxTimestamp - TimeSpan.FromSeconds(3))
                });

                if (mid == null)
                {
                    return;              // If we didn't find a corresponding message, bail
                }
                // Otherwise, we can *reasonably assume* that this is a logged deletion, so delete the log message.
                await msg.DeleteAsync();
            }
            else if (bot.ExtractFunc != null)
            {
                // Other bots give us the message ID itself, and we can just extract that from the database directly.
                var extractedId = bot.ExtractFunc(msg);
                if (extractedId == null)
                {
                    return;                      // If we didn't find anything, bail.
                }
                using var conn = await _db.Obtain();

                // We do this through an inline query instead of through DataStore since we don't need all the joins it does
                var mid = await conn.QuerySingleOrDefaultAsync <ulong?>("select mid from messages where original_mid = @Mid", new { Mid = extractedId.Value });

                if (mid == null)
                {
                    return;
                }

                // If we've gotten this far, we found a logged deletion of a trigger message. Just yeet it!
                await msg.DeleteAsync();
            } // else should not happen, but idk, it might
        }
Example #8
0
        public override async Task DoWork(CancellationToken cancellationToken)
        {
            _logger.LogInformation($"{DateTime.Now:hh:mm:ss} {Name} is working.");
            // get settings per channel
            var botChannelSettings = DatabaseManager.Instance().GetAllChannelSettings(); // TODO filter for guild

            string result = "";

            // todo config
            ulong guildId     = 747752542741725244;
            ulong spamChannel = 768600365602963496;
            var   guild       = Program.Client.GetGuild(guildId);
            var   textChannel = guild.GetTextChannel(spamChannel);

            foreach (var item in Program.Client.Guilds)
            {
                if (item.Id != Program.BaseGuild)
                {
                    continue; // only sync eth dinfk for now
                }
                foreach (var botChannelSetting in botChannelSettings)
                {
                    // TODO fix channel where oldest post is year 2154
                    try
                    {
                        var channel = item.GetTextChannel(botChannelSetting.DiscordChannelId);


                        if (botChannelSetting != null && ((BotPermissionType)botChannelSetting?.ChannelPermissionFlags).HasFlag(BotPermissionType.Read))
                        {
                            if (channel != null)
                            {
                                // TODO alot of dupe code clean up and generalize


                                if (!botChannelSetting.ReachedOldestPreload)
                                {
                                    // should be 50 calls -> around 1 min per channel
                                    int amount = 20_000; // we do only 50k a day to not overload the requests + db

                                    // we still need to go back
                                    DateTimeOffset fromDate = DateTimeOffset.Now;

                                    if (botChannelSetting.OldestPostTimePreloaded.HasValue)
                                    {
                                        fromDate = botChannelSetting.OldestPostTimePreloaded.Value;
                                    }

                                    ulong fromSnowflake = SnowflakeUtils.ToSnowflake(fromDate);

                                    var processResponse = await ProcessLoadedMessages(channel, fromSnowflake, Direction.Before, amount);


                                    if (processResponse?.SuccessCount > 0 && !processResponse.ReachedEndOfChannel)
                                    {
                                        // we synced some successfully
                                        result += $"{channel.Name} synced. Msg: {processResponse.SuccessCount}/{processResponse.DuplicateCount} Users: {processResponse.NewUsers} Emotes: {processResponse.EmotesAdded} " +
                                                  $"Time: {processResponse.ElapsedMilliseconds / 1000}s Time: {SnowflakeUtils.FromSnowflake(processResponse.OldestMessageId)}/{SnowflakeUtils.FromSnowflake(processResponse.NewestMessageId)}" + Environment.NewLine;

                                        DatabaseManager.Instance().UpdateChannelSetting(botChannelSetting.DiscordChannelId, -1, processResponse.OldestMessageId, processResponse.NewestMessageId);
                                    }
                                    else if (processResponse.ReachedEndOfChannel)
                                    {
                                        result += $"{channel.Name} no new messages. Reached the end..." + Environment.NewLine;

                                        // reached the end
                                        DatabaseManager.Instance().UpdateChannelSetting(botChannelSetting.DiscordChannelId, -1, processResponse.OldestMessageId, processResponse.NewestMessageId, true);
                                    }
                                    else
                                    {
                                        // error which "hopefully got logged and we just ignore this case xD
                                    }

                                    //var messagesFromMsg = await channel.GetMessagesAsync(fromSnowflake, Direction.Before, amount).FlattenAsync();
                                }
                                else
                                {
                                    // should be 50 calls -> around 1 min per channel
                                    int amount = 20_000; // we do only 50k a day to not overload the requests + db

                                    // we still need to go back
                                    DateTimeOffset fromDate = DateTimeOffset.Now;

                                    if (botChannelSetting.NewestPostTimePreloaded.HasValue)
                                    {
                                        fromDate = botChannelSetting.NewestPostTimePreloaded.Value;
                                    }

                                    ulong fromSnowflake = SnowflakeUtils.ToSnowflake(fromDate);

                                    var processResponse = await ProcessLoadedMessages(channel, fromSnowflake, Direction.After, amount);

                                    if (processResponse?.SuccessCount > 0 || processResponse?.DuplicateCount > 0)
                                    {
                                        if (processResponse.SuccessCount > 0)
                                        {
                                            // we synced some successfully
                                            result += $"{channel.Name} synced (new). Msg: {processResponse.SuccessCount}/{processResponse.DuplicateCount} Users: {processResponse.NewUsers} Emotes: {processResponse.EmotesAdded} " +
                                                      $"Time: {processResponse.ElapsedMilliseconds / 1000}s Time: {SnowflakeUtils.FromSnowflake(processResponse.OldestMessageId)}/{SnowflakeUtils.FromSnowflake(processResponse.NewestMessageId)}" + Environment.NewLine;
                                        }
                                        DatabaseManager.Instance().UpdateChannelSetting(botChannelSetting.DiscordChannelId, -1, processResponse.OldestMessageId, processResponse.NewestMessageId);
                                    }
                                    else
                                    {
                                        // error which "hopefully got logged and we just ignore this case xD
                                    }
                                }



                                // read all channels that we can read from the current guild
                                // see preload status
                                // do preload

                                // <- 25k msg at a time
                                // -> from newest to now compare delta
                            }
                            else
                            {
                                //result += $"Ignored {channel?.Name ?? "Channel deleted but has active settings"}" + Environment.NewLine;
                            }
                        }
                        else
                        {
                            //result += $"Ignored {channel?.Name ?? "Channel not found"}" + Environment.NewLine;
                        }
                    }
                    catch (Exception ex)
                    {
                        // contain exception for one channel only
                    }

                    if (result.Length > 1500)
                    {
                        textChannel.SendMessageAsync(result.Substring(0, Math.Min(2000, result.Length)));
                        result = "";
                    }
                }
            }

            if (result.Length > 0)
            {
                textChannel.SendMessageAsync(result.Substring(0, Math.Min(2000, result.Length)));
            }


            // todo if result > 2k chars


            //return Task.CompletedTask;
        }