private string BuildHostName(string account, string region) { if (string.IsNullOrEmpty(account)) { throw new ArgumentException("Account name cannot be empty."); } var hostname = $"{ReplaceUnderscores(account)}."; if (!string.IsNullOrEmpty(region) && region.ToLower() != "us-west-2") { hostname += $"{region}."; } var cloudTag = SnowflakeUtils.GetCloudTagByRegion(region); if (!string.IsNullOrEmpty(cloudTag)) { hostname += $"{cloudTag}."; } hostname += "snowflakecomputing.com"; return(hostname.ToLower()); }
internal RestInteraction(BaseDiscordClient discord, ulong id) : base(discord, id) { CreatedAt = discord.UseInteractionSnowflakeDate ? SnowflakeUtils.FromSnowflake(Id) : DateTime.UtcNow; }
/// <summary> /// Execute parameterized SQL. /// </summary> /// <param name="sql">The SQL to execute for this query.</param> /// <param name="sqlParams">The parameters to use for this query.</param> /// <returns>The number of rows affected.</returns> public async Task <long> ExecuteAsync(string sql, object sqlParams = null) { var response = await QueryInternalAsync(sql, sqlParams).ConfigureAwait(false); long affectedRows = SnowflakeUtils.GetAffectedRowsCount(response); return(affectedRows); }
public Task <ActionResult> SnowflakeAsync(ulong id) { var date = SnowflakeUtils.FromSnowflake(id); return(Ok(new StringBuilder() .AppendLine($"**Date:** {date.FormatDate()}") .AppendLine($"**Time**: {date.FormatFullTime()}") .ToString())); }
internal SocketInteraction(DiscordSocketClient client, ulong id, ISocketMessageChannel channel) : base(client, id) { Channel = channel; CreatedAt = client.UseInteractionSnowflakeDate ? SnowflakeUtils.FromSnowflake(Id) : DateTime.UtcNow; }
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(); }
public static bool IsValidSnowflake(ulong snowflake) { // Jan 1, 2015 var discordEpoch = SnowflakeUtils.FromSnowflake(0); // The supposed timestamp var snowflakeDateTime = SnowflakeUtils.FromSnowflake(snowflake); return(snowflakeDateTime > discordEpoch && snowflakeDateTime < DateTimeOffset.UtcNow); }
public async void RemovePingHell() { var guild = Program.Client.GetGuild(747752542741725244); var textChannel = guild.GetTextChannel(768600365602963496); // Get users that havent pinged the role in the last 72h var sqlQuery = @" SELECT PH.FromDiscordUserID, MAX(PH.DiscordMessageId) FROM PingHistory PH LEFT JOIN DiscordUsers DU ON PH.FromDiscordUserId = DU.DiscordUserId WHERE PH.DiscordRoleId = 895231323034222593 GROUP BY PH.FromDiscordUserId ORDER BY MAX(PH.DiscordMessageId)"; var queryResult = await SQLHelper.GetQueryResults(null, sqlQuery, true, 50, true); var utcNow = DateTime.UtcNow; ulong pingHellRoleId = 895231323034222593; var rolePingHell = guild.Roles.FirstOrDefault(i => i.Id == pingHellRoleId); foreach (var row in queryResult.Data) { try { var dateTimeLastPing = SnowflakeUtils.FromSnowflake(Convert.ToUInt64(row[1])); if ((utcNow - dateTimeLastPing).TotalHours >= 72) { ulong userId = Convert.ToUInt64(row[0]); // last ping is over 72h var guildUser = guild.GetUser(userId); if (guildUser.Roles.Any(i => i.Id == pingHellRoleId)) { // remove the role from user await guildUser.RemoveRoleAsync(rolePingHell); // send in spam that they are free await textChannel.SendMessageAsync($"<@{userId}> finally escaped PingHell May you never ping it ever again."); } } } catch (Exception ex) { await textChannel.SendMessageAsync($"Failed to remove pinghell: {ex.ToString()}"); } } }
// This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { //IConfiguration c = new ConfigurationBuilder().Build(); services.AddControllers().AddNewtonsoftJson().AddControllersAsServices(); SnowflakeUtils.Initialization(1, 1); #region Add Dapper //services.AddDapperForSQLite(); //services.AddDapperForPostgreSQL(); //services.AddDapperForODBC(); services.AddDapperForMySQL(); //services.AddDapperForMSSQL(); //services.AddDapperConnectionStringProvider<CustomConnectionStringProvider>(); #endregion #region Enable Caching //services.AddDapperCachingInRedis(new RedisConfiguration //{ // AllMethodsEnableCache = false, // ConnectionString = "localhost:6379,password=nihao123#@!" //}); //services.AddDapperCachingInPartitionRedis(new PartitionRedisConfiguration //{ // AllMethodsEnableCache = false, // Connections = new[] { "localhost:6379,password=nihao123#@!,defaultDatabase=1", "localhost:6379,password=nihao123#@!,defaultDatabase=2" } //}); //services.AddDapperCachingInMemory(new MemoryConfiguration //{ // AllMethodsEnableCache = false, // Expire = TimeSpan.FromHours(1) //}); #endregion services.AddMemoryCache(); //Manage home url:/profiler/results-index //Enable MiniProfiler //services.AddMiniProfiler(options => //{ // options.RouteBasePath = "/profiler"; // options.Storage = new RedisStorage("localhost:6379,password=nihao123#@!") // { // CacheDuration = TimeSpan.FromMinutes(5) // }; //}); services.AddScoped <DITest>(); }
public Embed CreateLoggedMessageEmbed(PKSystem system, PKMember member, ulong messageId, ulong originalMsgId, IUser sender, string content, IGuildChannel channel) { // TODO: pronouns in ?-reacted response using this card var timestamp = SnowflakeUtils.FromSnowflake(messageId); return(new EmbedBuilder() .WithAuthor($"#{channel.Name}: {member.Name}", member.AvatarUrl) .WithDescription(content) .WithFooter($"System ID: {system.Hid} | Member ID: {member.Hid} | Sender: {sender.Username}#{sender.Discriminator} ({sender.Id}) | Message ID: {messageId} | Original Message ID: {originalMsgId}") .WithTimestamp(timestamp) .Build()); }
string formatSimple(IEnumerable <MsgModel> models, LogContext db) { var sb = new StringBuilder(); foreach (var msg in models) { var content = msg.ContentId.HasValue ? db.Contents.FirstOrDefault(x => x.Id == msg.ContentId.Value).Content : "<no content available>"; content = (content ?? "<null>").Replace("\n", "\\n"); sb.Append($"{SnowflakeUtils.FromSnowflake(msg.Message):HH:mm} {msg.Author}: {content}\r\n"); } return(sb.ToString()); }
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(); }
private IUserMessage GetPreviousMessage(IUser user) { foreach (var message in Context.Channel.CachedMessages .OrderByDescending(w => SnowflakeUtils.FromSnowflake(w.Id)).Take(20)) { if (message.Author.Id == user.Id && message.Id != Context.Message.Id) { return(message as IUserMessage); } } return(null); }
public async Task <Embed> CreateMessageInfoEmbed(FullMessage msg) { var channel = await _client.GetChannelAsync(msg.Message.Channel) as ITextChannel; var serverMsg = channel != null ? await channel.GetMessageAsync(msg.Message.Mid) : null; var memberStr = $"{msg.Member.Name} (`{msg.Member.Hid}`)"; var userStr = $"*(deleted user {msg.Message.Sender})*"; ICollection <IRole> roles = null; if (channel != null) { // Look up the user with the REST client // this ensures we'll still get the information even if the user's not cached, // even if this means an extra API request (meh, it'll be fine) var shard = ((DiscordShardedClient)_client).GetShardFor(channel.Guild); var guildUser = await shard.Rest.GetGuildUserAsync(channel.Guild.Id, msg.Message.Sender); if (guildUser != null) { if (guildUser.RoleIds.Count > 0) { roles = guildUser.RoleIds .Select(roleId => channel.Guild.GetRole(roleId)) .Where(role => role.Name != "@everyone") .OrderByDescending(role => role.Position) .ToList(); } userStr = guildUser.Nickname != null ? $"**Username:** {guildUser?.NameAndMention()}\n**Nickname:** {guildUser.Nickname}" : guildUser?.NameAndMention(); } } var eb = new EmbedBuilder() .WithAuthor(msg.Member.Name, msg.Member.AvatarUrl) .WithDescription(serverMsg?.Content ?? "*(message contents deleted or inaccessible)*") .WithImageUrl(serverMsg?.Attachments?.FirstOrDefault()?.Url) .AddField("System", msg.System.Name != null ? $"{msg.System.Name} (`{msg.System.Hid}`)" : $"`{msg.System.Hid}`", true) .AddField("Member", memberStr, true) .AddField("Sent by", userStr, inline: true) .WithTimestamp(SnowflakeUtils.FromSnowflake(msg.Message.Mid)); if (roles != null && roles.Count > 0) { eb.AddField($"Account roles ({roles.Count})", string.Join(", ", roles.Select(role => role.Name))); } return(eb.Build()); }
// This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { //IConfiguration c = new ConfigurationBuilder().Build(); services.AddControllers().AddNewtonsoftJson().AddControllersAsServices(); SnowflakeUtils.Initialization(1, 1); #region Add Dapper //services.AddDapperForSQLite(); //services.AddDapperForPostgreSQL(); //services.AddDapperForODBC(); //services.AddDapperForMySQL(); //services.AddDapperForMSSQL(); #endregion #region Enable Caching //services.AddDapperCachingInRedis(new RedisConfiguration //{ // AllMethodsEnableCache = false, // ConnectionString = "localhost:6379,password=nihao123#@!" //}); //services.AddDapperCachingInPartitionRedis(new PartitionRedisConfiguration //{ // AllMethodsEnableCache = false, // Connections = new[] { "localhost:6379,password=nihao123#@!,defaultDatabase=1", "localhost:6379,password=nihao123#@!,defaultDatabase=2" } //}); //services.AddDapperCachingInMemory(new MemoryConfiguration //{ // AllMethodsEnableCache = false, // Expire = TimeSpan.FromHours(1) //}); #endregion services.AddMemoryCache(); //Enable MiniProfiler services.AddMiniProfiler(options => { var storage = new RedisStorage("localhost:6379,password=nihao123#@!") { CacheDuration = TimeSpan.FromMinutes(5) }; options.RouteBasePath = "/profiler"; options.SqlFormatter = new StackExchange.Profiling.SqlFormatters.InlineFormatter(); options.Storage = storage; }); }
private static List <GraphEntryInfo> GetUserMessageInfos(ulong?fromSnowflakeId = null) { List <GraphEntryInfo> messageTimes = new List <GraphEntryInfo>(); using (ETHBotDBContext context = new ETHBotDBContext()) messageTimes = context.DiscordMessages.AsQueryable() .Where(i => fromSnowflakeId == null || (fromSnowflakeId != null && i.DiscordMessageId > fromSnowflakeId)) .Select(i => new GraphEntryInfo() { KeyId = i.DiscordUserId, DateTime = SnowflakeUtils.FromSnowflake(i.DiscordMessageId) }) .ToList(); return(messageTimes); }
private bool GetAuditLogEntry(IGuild guild, out IAuditLogEntry auditLog, Discord.ActionType type) { auditLog = guild.GetAuditLogsAsync(5).GetAwaiter().GetResult().FirstOrDefault(x => x.Action == type); if (auditLog == null) { return(false); } var timeStamp = SnowflakeUtils.FromSnowflake(auditLog.Id); if (timeStamp > DateTimeOffset.Now - TimeSpan.FromSeconds(5)) { return(false); } return(auditLog.User.Id != _client.CurrentUser.Id); }
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); } }
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); }
private void OnTimerFired(object state) { // Get all messages where the timestamp is older than the specified max message longevity, then convert it to a list. The result of where merely contains references to the original // collection, so iterating and removing will throw an exception. Converting it to a list first avoids this. var toPurge = _cache.Where(p => { TimeSpan difference = DateTimeOffset.UtcNow - SnowflakeUtils.FromSnowflake(p.Key); return(difference.TotalHours >= _maxMessageTime); }).ToList(); int removed = toPurge.Count(p => TryRemove(p.Key)); UpdateCount(); _logger(new LogMessage(LogSeverity.Verbose, "CmdCache", $"Cleaned {removed} item(s) from the cache.")); }
public static EmbedBuilder GetEmbedForPingHistory(List <PingHistory> pingHistory, SocketGuildUser user) { var dbManager = DatabaseManager.Instance(); string messageText = ""; string currentBuilder = ""; int count = 1; EmbedBuilder builder = new EmbedBuilder(); builder.WithTitle($"{user.Nickname ?? user.Username} last 10 pings"); foreach (var item in pingHistory) { //if (item.DiscordMessageId == null) // continue; var dbMessage = dbManager.GetDiscordMessageById(item.DiscordMessageId); var dbChannel = dbManager.GetDiscordChannel(dbMessage?.DiscordChannelId); var dateTime = SnowflakeUtils.FromSnowflake(item.DiscordMessageId ?? 0); // TODO maybe track time in the ping history var dateTimeCET = dateTime.Add(Program.TimeZoneInfo.GetUtcOffset(DateTime.Now)); // CEST CONVERSION string link = null; if (dbChannel != null) { link = $"https://discord.com/channels/{dbChannel.DiscordServerId}/{dbMessage.DiscordChannelId}/{dbMessage.DiscordMessageId}"; } var channel = "unknown"; if (dbMessage?.DiscordChannelId != null) { channel = $"<#{dbMessage?.DiscordChannelId}>"; } string line = ""; // RoleIds smaller than 100 cant exist due to the Id size, so they are reserved for internal code if (item.DiscordRoleId.HasValue && item.DiscordRoleId.Value >= 100) { line += $"<@{item.FromDiscordUserId}> {(link == null ? "pinged" : $"[pinged]({link})")} <@&{item.DiscordRoleId}> at {dateTimeCET.ToString("dd.MM HH:mm")} in {channel} {Environment.NewLine}"; // todo check for everyone or here
private static Embed GetEmbed(string title, Color color, IUser user, IMessageChannel channel, string diff, string attachment, ulong?messageId) { var addId = messageId == null ? "" : " (" + messageId + ")"; var builder = new EmbedBuilder() .WithAuthor(author => author .WithIconUrl(user?.GetAvatarUrlOrDefault()) .WithName(user?.Username.DiscordEscape() + "#" + (user?.Discriminator ?? "@" + user.Id) + " " + title + ":")) .WithColor(color) .WithDescription(diff); if (messageId.HasValue) { builder.WithTimestamp(SnowflakeUtils.FromSnowflake(messageId.Value)); } if (channel != null) { builder.WithFooter(footer => footer .WithText($"In #{channel}" + addId)); } if (attachment != null) { var host = new Uri(attachment).Host; if (host == "images.discordapp.net") { builder.WithImageUrl(attachment); } else { builder.AddField(field => field .WithName("Attachment") .WithValue(attachment)); } } return(builder.Build()); }
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()); } }
private string MoveEmoteToDisk(DiscordEmote emote, byte[] imageData) { var emojiDate = SnowflakeUtils.FromSnowflake(emote.DiscordEmoteId); string additionalFolder = $"{emojiDate.Year}-{emojiDate.Month:00}"; string path = Path.Combine(Program.ApplicationSetting.BasePath, "Emotes", additionalFolder); if (!Directory.Exists(path)) { Directory.CreateDirectory(path); } int i = emote.Url.LastIndexOf("."); string fileEnding = emote.Url.Substring(i, emote.Url.Length - i); string filePath = Path.Combine(path, $"{emote.DiscordEmoteId}{fileEnding}"); File.WriteAllBytes(filePath, imageData); return(filePath); }
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}"); } } } }
string formatCSV(IEnumerable <MsgModel> messages, LogContext db) { var sb = new StringBuilder(); sb.Append($"Id,AuthorId,Timestamp,Content\r\n"); foreach (var msg in messages) { sb.Append($"\"{msg.Message}\","); sb.Append($"\"{msg.Author}\","); sb.Append($"\"{SnowflakeUtils.FromSnowflake(msg.Message):HH:mm:ss.fff}\","); if (msg.ContentId.HasValue) { var content = db.Contents.FirstOrDefault(x => x.Id == msg.ContentId.Value); sb.Append($"\"{content.Content.Replace("\n", "\\n")}\""); } else { sb.Append("\"<no content available>\""); } sb.Append("\r\n"); } return(sb.ToString()); }
public override async Task <TypeReaderResult> ReadAsync(ICommandContext context, string input, IServiceProvider services) { // Try to get the result from the base user reader. // If that fails, try to solely parse the ID. TypeReaderResult result = await base.ReadAsync(context, input, services); if (result.IsSuccess) { IGuildUser user = result.BestMatch as IGuildUser; GuildUserProxy proxy = new GuildUserProxy { GuildUser = user, ID = user.Id }; return(TypeReaderResult.FromSuccess(proxy)); } else { bool validSnowFlake = false; ulong userId = 0; if (ulong.TryParse(input, out userId)) { validSnowFlake = SnowflakeUtils.FromSnowflake(userId).ToUnixTimeSeconds() > DISCORD_START_UNIX; } if (validSnowFlake || MentionUtils.TryParseUser(input, out userId)) { return(TypeReaderResult.FromSuccess(new GuildUserProxy { ID = userId })); } } return(TypeReaderResult.FromError(CommandError.ObjectNotFound, "User not found.")); }
internal void Update(Model model) { Id = model.Id; CreatedAt = SnowflakeUtils.FromSnowflake(Id); if (model.IsTextToSpeech.IsSpecified) { IsTTS = model.IsTextToSpeech.Value; } if (model.Pinned.IsSpecified) { IsPinned = model.Pinned.Value; } if (model.EditedTimestamp.IsSpecified) { EditedTimestamp = model.EditedTimestamp.Value; } if (model.MentionEveryone.IsSpecified) { MentionedEveryone = model.MentionEveryone.Value; } if (model.RoleMentions.IsSpecified) { MentionedRoleIds = model.RoleMentions.Value.ToImmutableArray(); } MentionedUserIds = new List <ulong>(); MentionedChannelIds = new List <ulong>(); if (model.Attachments.IsSpecified) { var value = model.Attachments.Value; if (value.Length > 0) { var attachments = ImmutableArray.CreateBuilder <Attachment>(value.Length); for (int i = 0; i < value.Length; i++) { attachments.Add(Attachment.Create(value[i])); } Attachments = attachments.ToImmutable(); } else { Attachments = ImmutableArray.Create <Attachment>(); } } if (model.Embeds.IsSpecified) { var value = model.Embeds.Value; if (value.Length > 0) { var embeds = ImmutableArray.CreateBuilder <Embed>(value.Length); for (int i = 0; i < value.Length; i++) { embeds.Add(value[i].ToEntity()); } Embeds = embeds.ToImmutable(); } else { Embeds = ImmutableArray.Create <Embed>(); } } if (model.UserMentions.IsSpecified) { var value = model.UserMentions.Value; if (value.Length > 0) { var newMentions = ImmutableArray.CreateBuilder <ulong>(value.Length); for (int i = 0; i < value.Length; i++) { var val = value[i]; if (val.Object != null) { newMentions.Add(val.Object.Id); } } MentionedUserIds = newMentions.ToReadOnlyCollection(); } } if (model.Content.IsSpecified) { var text = model.Content.Value; model.Content = text; } }
public IActionResult GenerateId() { return(Ok(SnowflakeUtils.GenerateId())); }
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 }