From d99919e841bc237ac9d6f3b2495c570c7d30de22 Mon Sep 17 00:00:00 2001 From: Noi Date: Sat, 3 Sep 2022 18:13:35 -0700 Subject: [PATCH 01/10] Fix incorrect summary field on parameter --- ApplicationCommands/ConfigModule.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ApplicationCommands/ConfigModule.cs b/ApplicationCommands/ConfigModule.cs index 7563d69..d80a9b4 100644 --- a/ApplicationCommands/ConfigModule.cs +++ b/ApplicationCommands/ConfigModule.cs @@ -56,7 +56,7 @@ public class ConfigModule : BotModuleBase { } [SlashCommand("set-channel", HelpPfxModOnly + HelpSubCmdChannel + HelpPofxBlankUnset)] - public async Task CmdSetChannel([Summary(description: HelpOptRole)] SocketTextChannel? channel = null) { + public async Task CmdSetChannel([Summary(description: HelpOptChannel)] SocketTextChannel? channel = null) { await DoDatabaseUpdate(Context, s => s.ChannelAnnounceId = (long?)channel?.Id); await RespondAsync(":white_check_mark: The announcement channel has been " + (channel == null ? "unset." : $"set to **{channel.Name}**.")); From 1f6772d18a2b0f0c5a9ea3439edf2569691c2746 Mon Sep 17 00:00:00 2001 From: Noi Date: Fri, 16 Sep 2022 21:48:46 -0700 Subject: [PATCH 02/10] Fix time zone unset when updating birthday (#26) --- ApplicationCommands/BirthdayModule.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ApplicationCommands/BirthdayModule.cs b/ApplicationCommands/BirthdayModule.cs index 4769182..d4933d0 100644 --- a/ApplicationCommands/BirthdayModule.cs +++ b/ApplicationCommands/BirthdayModule.cs @@ -3,7 +3,6 @@ using Discord.Interactions; using System.Text; namespace BirthdayBot.ApplicationCommands; - [RequireGuildContext] [Group("birthday", HelpCmdBirthday)] public class BirthdayModule : BotModuleBase { @@ -47,7 +46,7 @@ public class BirthdayModule : BotModuleBase { if (user.IsNew) db.UserEntries.Add(user); user.BirthMonth = inmonth; user.BirthDay = inday; - user.TimeZone = inzone; + user.TimeZone = inzone ?? user.TimeZone; try { await db.SaveChangesAsync(); } catch (Microsoft.EntityFrameworkCore.DbUpdateException e) From e265cafd25d4ed6b4b8aefbd096c625186354295 Mon Sep 17 00:00:00 2001 From: Noi Date: Mon, 10 Oct 2022 14:27:54 -0700 Subject: [PATCH 03/10] Fix incorrect value checked for determining moderator The public instance will be updated with this fix immediately. This fixes cases in which those with moderator roles are unable to use mod-only commands as intended. It also fixes a dangerous bug in which users with the birthday role assigned to them have unrestricted access to moderator commands. --- ApplicationCommands/ConfigModule.cs | 19 +++++++++---------- .../Preconditions/RequireBotModerator.cs | 3 +-- BackgroundServices/BirthdayRoleUpdate.cs | 8 ++++---- Data/GuildConfig.cs | 7 +++---- 4 files changed, 17 insertions(+), 20 deletions(-) diff --git a/ApplicationCommands/ConfigModule.cs b/ApplicationCommands/ConfigModule.cs index d80a9b4..d9036fa 100644 --- a/ApplicationCommands/ConfigModule.cs +++ b/ApplicationCommands/ConfigModule.cs @@ -3,7 +3,6 @@ using Discord.Interactions; using System.Text; namespace BirthdayBot.ApplicationCommands; - [RequireBotModerator] [Group("config", HelpCmdConfig)] public class ConfigModule : BotModuleBase { @@ -57,7 +56,7 @@ public class ConfigModule : BotModuleBase { [SlashCommand("set-channel", HelpPfxModOnly + HelpSubCmdChannel + HelpPofxBlankUnset)] public async Task CmdSetChannel([Summary(description: HelpOptChannel)] SocketTextChannel? channel = null) { - await DoDatabaseUpdate(Context, s => s.ChannelAnnounceId = (long?)channel?.Id); + await DoDatabaseUpdate(Context, s => s.AnnouncementChannel = (long?)channel?.Id); await RespondAsync(":white_check_mark: The announcement channel has been " + (channel == null ? "unset." : $"set to **{channel.Name}**.")); } @@ -127,7 +126,7 @@ public class ConfigModule : BotModuleBase { await RespondAsync(":x: This role cannot be used for this setting.", ephemeral: true); return; } - await DoDatabaseUpdate(Context, s => s.RoleId = (long)role.Id); + await DoDatabaseUpdate(Context, s => s.BirthdayRole = (long)role.Id); await RespondAsync($":white_check_mark: The birthday role has been set to **{role.Name}**.").ConfigureAwait(false); } @@ -202,7 +201,7 @@ public class ConfigModule : BotModuleBase { result.AppendLine($"Server ID: `{guild.Id}` | Bot shard ID: `{Shard.ShardId:00}`"); result.AppendLine($"Number of registered birthdays: `{ guildconf.UserEntries.Count }`"); - result.AppendLine($"Server time zone: `{ (guildconf.TimeZone ?? "Not set - using UTC") }`"); + result.AppendLine($"Server time zone: `{ (guildconf.GuildTimeZone ?? "Not set - using UTC") }`"); result.AppendLine(); bool hasMembers = Common.HasMostMembersDownloaded(guild); @@ -212,7 +211,7 @@ public class ConfigModule : BotModuleBase { result.Append(DoTestFor("Birthday processing", delegate { if (!hasMembers) return false; if (guildconf.IsNew) return false; - bdayCount = BackgroundServices.BirthdayRoleUpdate.GetGuildCurrentBirthdays(guildconf.UserEntries, guildconf.TimeZone).Count; + bdayCount = BackgroundServices.BirthdayRoleUpdate.GetGuildCurrentBirthdays(guildconf.UserEntries, guildconf.GuildTimeZone).Count; return true; })); if (!hasMembers) result.AppendLine(" - Previous step failed."); @@ -222,12 +221,12 @@ public class ConfigModule : BotModuleBase { result.AppendLine(DoTestFor("Birthday role set with `/config role set-birthday-role`", delegate { if (guildconf.IsNew) return false; - SocketRole? role = guild.GetRole((ulong)(guildconf.RoleId ?? 0)); + SocketRole? role = guild.GetRole((ulong)(guildconf.BirthdayRole ?? 0)); return role != null; })); result.AppendLine(DoTestFor("Birthday role can be managed by bot", delegate { if (guildconf.IsNew) return false; - SocketRole? role = guild.GetRole((ulong)(guildconf.RoleId ?? 0)); + SocketRole? role = guild.GetRole((ulong)(guildconf.BirthdayRole ?? 0)); if (role == null) return false; return guild.CurrentUser.GuildPermissions.ManageRoles && role.Position < guild.CurrentUser.Hierarchy; })); @@ -236,7 +235,7 @@ public class ConfigModule : BotModuleBase { SocketTextChannel? announcech = null; result.AppendLine(DoTestFor("(Optional) Announcement channel set with `bb.config channel`", delegate { if (guildconf.IsNew) return false; - announcech = guild.GetTextChannel((ulong)(guildconf.ChannelAnnounceId ?? 0)); + announcech = guild.GetTextChannel((ulong)(guildconf.AnnouncementChannel ?? 0)); return announcech != null; })); string disp = announcech == null ? "announcement channel" : $"<#{announcech.Id}>"; @@ -276,7 +275,7 @@ public class ConfigModule : BotModuleBase { const string Response = ":white_check_mark: The server's time zone has been "; if (zone == null) { - await DoDatabaseUpdate(Context, s => s.TimeZone = null); + await DoDatabaseUpdate(Context, s => s.GuildTimeZone = null); await RespondAsync(Response + "unset.").ConfigureAwait(false); } else { string parsedZone; @@ -287,7 +286,7 @@ public class ConfigModule : BotModuleBase { return; } - await DoDatabaseUpdate(Context, s => s.TimeZone = parsedZone); + await DoDatabaseUpdate(Context, s => s.GuildTimeZone = parsedZone); await RespondAsync(Response + $"set to **{parsedZone}**.").ConfigureAwait(false); } } diff --git a/ApplicationCommands/Preconditions/RequireBotModerator.cs b/ApplicationCommands/Preconditions/RequireBotModerator.cs index e458ed9..f62aa07 100644 --- a/ApplicationCommands/Preconditions/RequireBotModerator.cs +++ b/ApplicationCommands/Preconditions/RequireBotModerator.cs @@ -2,7 +2,6 @@ using Discord.Interactions; namespace BirthdayBot.ApplicationCommands; - /// /// Precondition requiring the executing user be recognized as a bot moderator.
/// A bot moderator has either the Manage Server permission or is a member of the designated bot moderator role. @@ -24,7 +23,7 @@ class RequireBotModeratorAttribute : PreconditionAttribute { using var db = new BotDatabaseContext(); var checkRole = (ulong?)db.GuildConfigurations .Where(g => g.GuildId == (long)((SocketGuild)context.Guild).Id) - .Select(g => g.RoleId).FirstOrDefault(); + .Select(g => g.ModeratorRole).FirstOrDefault(); if (checkRole.HasValue && user.Roles.Any(r => r.Id == checkRole.Value)) return Task.FromResult(PreconditionResult.FromSuccess()); diff --git a/BackgroundServices/BirthdayRoleUpdate.cs b/BackgroundServices/BirthdayRoleUpdate.cs index e97906f..48d908b 100644 --- a/BackgroundServices/BirthdayRoleUpdate.cs +++ b/BackgroundServices/BirthdayRoleUpdate.cs @@ -46,13 +46,13 @@ class BirthdayRoleUpdate : BackgroundService { try { // Verify that role settings and permissions are usable - SocketRole? role = guild.GetRole((ulong)(settings.RoleId ?? 0)); + SocketRole? role = guild.GetRole((ulong)(settings.BirthdayRole ?? 0)); if (role == null || !guild.CurrentUser.GuildPermissions.ManageRoles || role.Position >= guild.CurrentUser.Hierarchy) continue; if (role.IsEveryone || role.IsManaged) { // Invalid role was configured. Clear the setting and quit. - settings.RoleId = null; + settings.BirthdayRole = null; db.Update(settings); await db.SaveChangesAsync(CancellationToken.None); continue; @@ -60,7 +60,7 @@ class BirthdayRoleUpdate : BackgroundService { // Load up user configs and begin processing birthdays await db.Entry(settings).Collection(t => t.UserEntries).LoadAsync(CancellationToken.None); - var birthdays = GetGuildCurrentBirthdays(settings.UserEntries, settings.TimeZone); + var birthdays = GetGuildCurrentBirthdays(settings.UserEntries, settings.GuildTimeZone); // Add or remove roles as appropriate var announcementList = await UpdateGuildBirthdayRoles(guild, role, birthdays); @@ -144,7 +144,7 @@ class BirthdayRoleUpdate : BackgroundService { /// Attempts to send an announcement message. ///
internal static async Task AnnounceBirthdaysAsync(GuildConfig settings, SocketGuild g, IEnumerable names) { - var c = g.GetTextChannel((ulong)(settings.ChannelAnnounceId ?? 0)); + var c = g.GetTextChannel((ulong)(settings.AnnouncementChannel ?? 0)); if (c == null) return; if (!c.Guild.CurrentUser.GetPermissions(c).SendMessages) return; diff --git a/Data/GuildConfig.cs b/Data/GuildConfig.cs index e2fa2f6..df66398 100644 --- a/Data/GuildConfig.cs +++ b/Data/GuildConfig.cs @@ -2,7 +2,6 @@ using System.ComponentModel.DataAnnotations.Schema; namespace BirthdayBot.Data; - [Table("settings")] public class GuildConfig { public GuildConfig() { @@ -14,11 +13,11 @@ public class GuildConfig { [Column("guild_id")] public long GuildId { get; set; } [Column("role_id")] - public long? RoleId { get; set; } + public long? BirthdayRole { get; set; } [Column("channel_announce_id")] - public long? ChannelAnnounceId { get; set; } + public long? AnnouncementChannel { get; set; } [Column("time_zone")] - public string? TimeZone { get; set; } + public string? GuildTimeZone { get; set; } [Column("moderated")] public bool Moderated { get; set; } [Column("moderator_role")] From db6c81116941a60eb8f53ed75fa72bc9d1359fe5 Mon Sep 17 00:00:00 2001 From: Noi Date: Mon, 10 Oct 2022 14:42:12 -0700 Subject: [PATCH 04/10] Bump version, update references --- BirthdayBot.csproj | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/BirthdayBot.csproj b/BirthdayBot.csproj index 4359c69..0aef963 100644 --- a/BirthdayBot.csproj +++ b/BirthdayBot.csproj @@ -22,15 +22,15 @@ - + - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + From 236c34b81094e16013d18156335a3a2b95fd98ea Mon Sep 17 00:00:00 2001 From: Noi Date: Mon, 10 Oct 2022 14:42:33 -0700 Subject: [PATCH 05/10] Actually bump version --- BirthdayBot.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BirthdayBot.csproj b/BirthdayBot.csproj index 0aef963..5192d10 100644 --- a/BirthdayBot.csproj +++ b/BirthdayBot.csproj @@ -5,7 +5,7 @@ net6.0 enable enable - 3.4.4 + 3.4.5 NoiTheCat From a9853021f4c03edf9b0d297ed976332adb2b175c Mon Sep 17 00:00:00 2001 From: Noi Date: Mon, 21 Nov 2022 10:45:46 -0800 Subject: [PATCH 06/10] Edit SQL pool config, usage --- Configuration.cs | 2 +- Data/BotDatabaseContext.cs | 7 ++++++- ShardManager.cs | 5 ++--- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/Configuration.cs b/Configuration.cs index 48503a7..aff4457 100644 --- a/Configuration.cs +++ b/Configuration.cs @@ -73,7 +73,7 @@ class Configuration { SqlDatabase = ReadConfKey(jc, nameof(SqlDatabase), false); SqlUsername = ReadConfKey(jc, nameof(SqlUsername), true); SqlPassword = ReadConfKey(jc, nameof(SqlPassword), true); - SqlApplicationName = $"ClientShard{ShardStart}+{ShardAmount}"; + SqlApplicationName = $"Shard{ShardStart:00}-{ShardStart + ShardAmount - 1:00}"; } private static T? ReadConfKey(JObject jc, string key, [DoesNotReturnIf(true)] bool failOnEmpty) { diff --git a/Data/BotDatabaseContext.cs b/Data/BotDatabaseContext.cs index 2fc2616..18e11a9 100644 --- a/Data/BotDatabaseContext.cs +++ b/Data/BotDatabaseContext.cs @@ -15,7 +15,12 @@ public class BotDatabaseContext : DbContext { Username = conf.SqlUsername, Password = conf.SqlPassword, ApplicationName = conf.SqlApplicationName, - MaxPoolSize = Math.Max((int)Math.Ceiling(conf.ShardAmount * 2 * 0.6), 8) + + // Let's see if this works? + ConnectionIdleLifetime = 60, + MaxPoolSize = Math.Max( + (int)Math.Ceiling(conf.ShardAmount * 2 * 0.75), + (int)Math.Ceiling(ShardManager.MaxConcurrentOperations * 2.5)) }.ToString(); } diff --git a/ShardManager.cs b/ShardManager.cs index dda1d6b..cd09a00 100644 --- a/ShardManager.cs +++ b/ShardManager.cs @@ -1,6 +1,5 @@ global using Discord; global using Discord.WebSocket; -using BirthdayBot.BackgroundServices; using Discord.Interactions; using Microsoft.Extensions.DependencyInjection; using System.Text; @@ -23,9 +22,9 @@ class ShardManager : IDisposable { /// /// Number of concurrent shard startups to happen on each check. - /// This value is also used in . + /// This value also determines the maximum amount of concurrent background database operations. /// - public const int MaxConcurrentOperations = 4; + public const int MaxConcurrentOperations = 3; /// /// Amount of time without a completed background service run before a shard instance From e62a89d0a0e44186cd8b653b26f254f41416835f Mon Sep 17 00:00:00 2001 From: Noi Date: Mon, 21 Nov 2022 19:17:07 -0800 Subject: [PATCH 07/10] Use background service semaphore Must have missed it the first time... --- BackgroundServices/AutoUserDownload.cs | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/BackgroundServices/AutoUserDownload.cs b/BackgroundServices/AutoUserDownload.cs index c333c11..229feb0 100644 --- a/BackgroundServices/AutoUserDownload.cs +++ b/BackgroundServices/AutoUserDownload.cs @@ -1,7 +1,7 @@ using BirthdayBot.Data; +using Microsoft.EntityFrameworkCore; namespace BirthdayBot.BackgroundServices; - /// /// Proactively fills the user cache for guilds in which any birthday data already exists. /// @@ -9,14 +9,23 @@ class AutoUserDownload : BackgroundService { public AutoUserDownload(ShardInstance instance) : base(instance) { } public override async Task OnTick(int tickCount, CancellationToken token) { - using var db = new BotDatabaseContext(); - // Take action if a guild's cache is incomplete... var incompleteCaches = ShardInstance.DiscordClient.Guilds.Where(g => !g.HasAllMembers).Select(g => (long)g.Id).ToHashSet(); // ...and if the guild contains any user data - var mustFetch = db.UserEntries.Where(e => incompleteCaches.Contains(e.GuildId)).Select(e => e.GuildId).Distinct(); - - int processed = 0; + IEnumerable mustFetch; + try { + await DbConcurrentOperationsLock.WaitAsync(token); + using var db = new BotDatabaseContext(); + mustFetch = db.UserEntries.AsNoTracking() + .Where(e => incompleteCaches.Contains(e.GuildId)).Select(e => e.GuildId).Distinct() + .ToList(); + } finally { + try { + DbConcurrentOperationsLock.Release(); + } catch (ObjectDisposedException) { } + } + + var processed = 0; foreach (var item in mustFetch) { // May cause a disconnect in certain situations. Cancel all further attempts until the next pass if it happens. if (ShardInstance.DiscordClient.ConnectionState != ConnectionState.Connected) break; @@ -28,6 +37,6 @@ class AutoUserDownload : BackgroundService { processed++; } - if (processed > 100) Log($"Explicit user list request processed for {processed} guild(s)."); + if (processed > 25) Log($"Explicit user list request processed for {processed} guild(s)."); } } From fbd730581896f7be7e466033fae449374d990985 Mon Sep 17 00:00:00 2001 From: Noi Date: Mon, 21 Nov 2022 20:38:06 -0800 Subject: [PATCH 08/10] Revert, unset pool configuration changes --- Data/BotDatabaseContext.cs | 8 +------- ShardManager.cs | 2 +- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/Data/BotDatabaseContext.cs b/Data/BotDatabaseContext.cs index 18e11a9..99c9c07 100644 --- a/Data/BotDatabaseContext.cs +++ b/Data/BotDatabaseContext.cs @@ -14,13 +14,7 @@ public class BotDatabaseContext : DbContext { Database = conf.SqlDatabase, Username = conf.SqlUsername, Password = conf.SqlPassword, - ApplicationName = conf.SqlApplicationName, - - // Let's see if this works? - ConnectionIdleLifetime = 60, - MaxPoolSize = Math.Max( - (int)Math.Ceiling(conf.ShardAmount * 2 * 0.75), - (int)Math.Ceiling(ShardManager.MaxConcurrentOperations * 2.5)) + ApplicationName = conf.SqlApplicationName }.ToString(); } diff --git a/ShardManager.cs b/ShardManager.cs index cd09a00..cbaab4f 100644 --- a/ShardManager.cs +++ b/ShardManager.cs @@ -24,7 +24,7 @@ class ShardManager : IDisposable { /// Number of concurrent shard startups to happen on each check. /// This value also determines the maximum amount of concurrent background database operations. /// - public const int MaxConcurrentOperations = 3; + public const int MaxConcurrentOperations = 4; /// /// Amount of time without a completed background service run before a shard instance From 2c920e9794f8bc7d2bdd0b887e70567fd67592b2 Mon Sep 17 00:00:00 2001 From: Noi Date: Mon, 21 Nov 2022 21:20:48 -0800 Subject: [PATCH 09/10] Upgrade EFCore, switch to bulk operations --- BackgroundServices/DataRetention.cs | 43 ++++++++++++++--------------- BirthdayBot.csproj | 12 ++++---- 2 files changed, 27 insertions(+), 28 deletions(-) diff --git a/BackgroundServices/DataRetention.cs b/BackgroundServices/DataRetention.cs index 2caa3e8..ee5f942 100644 --- a/BackgroundServices/DataRetention.cs +++ b/BackgroundServices/DataRetention.cs @@ -1,4 +1,5 @@ using BirthdayBot.Data; +using Microsoft.EntityFrameworkCore; using System.Text; namespace BirthdayBot.BackgroundServices; @@ -31,34 +32,32 @@ class DataRetention : BackgroundService { private async Task RemoveStaleEntriesAsync() { using var db = new BotDatabaseContext(); var now = DateTimeOffset.UtcNow; - int updatedGuilds = 0, updatedUsers = 0; + // Update guilds + var localGuilds = ShardInstance.DiscordClient.Guilds.Select(g => (long)g.Id).ToList(); + var updatedGuilds = await db.GuildConfigurations + .Where(g => localGuilds.Contains(g.GuildId)) + .ExecuteUpdateAsync(upd => upd.SetProperty(p => p.LastSeen, now)); + + // Update guild users + var updatedUsers = 0; foreach (var guild in ShardInstance.DiscordClient.Guilds) { - // Update guild, fetch users from database - var dbGuild = db.GuildConfigurations.Where(s => s.GuildId == (long)guild.Id).FirstOrDefault(); - if (dbGuild == null) continue; - dbGuild.LastSeen = now; - updatedGuilds++; - - // Update users - var localIds = guild.Users.Select(u => (long)u.Id); - var dbSavedIds = db.UserEntries.Where(e => e.GuildId == (long)guild.Id).Select(e => e.UserId); - var usersToUpdate = localIds.Intersect(dbSavedIds).ToHashSet(); - foreach (var user in db.UserEntries.Where(e => e.GuildId == (long)guild.Id && usersToUpdate.Contains(e.UserId))) { - user.LastSeen = now; - updatedUsers++; - } + var localUsers = guild.Users.Select(u => (long)u.Id).ToList(); + updatedUsers += await db.UserEntries + .Where(gu => gu.GuildId == (long)guild.Id) + .Where(gu => localUsers.Contains(gu.UserId)) + .ExecuteUpdateAsync(upd => upd.SetProperty(p => p.LastSeen, now)); } // And let go of old data - var staleGuilds = db.GuildConfigurations.Where(s => now - TimeSpan.FromDays(StaleGuildThreshold) > s.LastSeen); - var staleUsers = db.UserEntries.Where(e => now - TimeSpan.FromDays(StaleUserThreashold) > e.LastSeen); - int staleGuildCount = staleGuilds.Count(), staleUserCount = staleUsers.Count(); - db.GuildConfigurations.RemoveRange(staleGuilds); - db.UserEntries.RemoveRange(staleUsers); - - await db.SaveChangesAsync(CancellationToken.None); + var staleGuildCount = await db.GuildConfigurations + .Where(g => now - TimeSpan.FromDays(StaleGuildThreshold) > g.LastSeen) + .ExecuteDeleteAsync(); + var staleUserCount = await db.UserEntries + .Where(gu => now - TimeSpan.FromDays(StaleUserThreashold) > gu.LastSeen) + .ExecuteDeleteAsync(); + // Build report var resultText = new StringBuilder(); resultText.Append($"Updated {updatedGuilds} guilds, {updatedUsers} users."); if (staleGuildCount != 0 || staleUserCount != 0) { diff --git a/BirthdayBot.csproj b/BirthdayBot.csproj index 5192d10..d8150f9 100644 --- a/BirthdayBot.csproj +++ b/BirthdayBot.csproj @@ -5,7 +5,7 @@ net6.0 enable enable - 3.4.5 + 3.4.6 NoiTheCat @@ -23,16 +23,16 @@ - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive - + - - + + From a3ac5d6eded52778bc0fd7b8bca8166eae5c0135 Mon Sep 17 00:00:00 2001 From: Noi Date: Tue, 22 Nov 2022 23:19:37 -0800 Subject: [PATCH 10/10] Change data types from long to ulong --- ApplicationCommands/BirthdayModule.cs | 4 +- ApplicationCommands/ConfigModule.cs | 10 +- .../Preconditions/EnforceBlocking.cs | 6 +- .../Preconditions/RequireBotModerator.cs | 2 +- BackgroundServices/AutoUserDownload.cs | 4 +- BackgroundServices/BirthdayRoleUpdate.cs | 4 +- BackgroundServices/DataRetention.cs | 6 +- Data/BlocklistEntry.cs | 6 +- Data/Extensions.cs | 8 +- Data/GuildConfig.cs | 24 +-- .../20221123062847_LongToUlong.Designer.cs | 161 ++++++++++++++++ Data/Migrations/20221123062847_LongToUlong.cs | 177 ++++++++++++++++++ .../BotDatabaseContextModelSnapshot.cs | 46 ++--- Data/UserEntry.cs | 14 +- 14 files changed, 404 insertions(+), 68 deletions(-) create mode 100644 Data/Migrations/20221123062847_LongToUlong.Designer.cs create mode 100644 Data/Migrations/20221123062847_LongToUlong.cs diff --git a/ApplicationCommands/BirthdayModule.cs b/ApplicationCommands/BirthdayModule.cs index d4933d0..4d4991a 100644 --- a/ApplicationCommands/BirthdayModule.cs +++ b/ApplicationCommands/BirthdayModule.cs @@ -222,10 +222,10 @@ public class BirthdayModule : BotModuleBase { private static List GetSortedUserList(SocketGuild guild) { using var db = new BotDatabaseContext(); var query = from row in db.UserEntries - where row.GuildId == (long)guild.Id + where row.GuildId == guild.Id orderby row.BirthMonth, row.BirthDay select new { - UserId = (ulong)row.UserId, + row.UserId, Month = row.BirthMonth, Day = row.BirthDay, Zone = row.TimeZone diff --git a/ApplicationCommands/ConfigModule.cs b/ApplicationCommands/ConfigModule.cs index d9036fa..10fed49 100644 --- a/ApplicationCommands/ConfigModule.cs +++ b/ApplicationCommands/ConfigModule.cs @@ -56,7 +56,7 @@ public class ConfigModule : BotModuleBase { [SlashCommand("set-channel", HelpPfxModOnly + HelpSubCmdChannel + HelpPofxBlankUnset)] public async Task CmdSetChannel([Summary(description: HelpOptChannel)] SocketTextChannel? channel = null) { - await DoDatabaseUpdate(Context, s => s.AnnouncementChannel = (long?)channel?.Id); + await DoDatabaseUpdate(Context, s => s.AnnouncementChannel = channel?.Id); await RespondAsync(":white_check_mark: The announcement channel has been " + (channel == null ? "unset." : $"set to **{channel.Name}**.")); } @@ -126,7 +126,7 @@ public class ConfigModule : BotModuleBase { await RespondAsync(":x: This role cannot be used for this setting.", ephemeral: true); return; } - await DoDatabaseUpdate(Context, s => s.BirthdayRole = (long)role.Id); + await DoDatabaseUpdate(Context, s => s.BirthdayRole = role.Id); await RespondAsync($":white_check_mark: The birthday role has been set to **{role.Name}**.").ConfigureAwait(false); } @@ -136,7 +136,7 @@ public class ConfigModule : BotModuleBase { await RespondAsync(":x: This role cannot be used for this setting.", ephemeral: true); return; } - await DoDatabaseUpdate(Context, s => s.ModeratorRole = (long?)role?.Id); + await DoDatabaseUpdate(Context, s => s.ModeratorRole = role?.Id); await RespondAsync(":white_check_mark: The moderator role has been " + (role == null ? "unset." : $"set to **{role.Name}**.")); } @@ -154,7 +154,7 @@ public class ConfigModule : BotModuleBase { // setting: true to add (set), false to remove (unset) using var db = new BotDatabaseContext(); var existing = db.BlocklistEntries - .Where(bl => bl.GuildId == (long)user.Guild.Id && bl.UserId == (long)user.Id).FirstOrDefault(); + .Where(bl => bl.GuildId == user.Guild.Id && bl.UserId == user.Id).FirstOrDefault(); bool already = (existing != null) == setting; if (already) { @@ -162,7 +162,7 @@ public class ConfigModule : BotModuleBase { return; } - if (setting) db.BlocklistEntries.Add(new BlocklistEntry() { GuildId = (long)user.Guild.Id, UserId = (long)user.Id }); + if (setting) db.BlocklistEntries.Add(new BlocklistEntry() { GuildId = user.Guild.Id, UserId = user.Id }); else db.Remove(existing!); await db.SaveChangesAsync(); diff --git a/ApplicationCommands/Preconditions/EnforceBlocking.cs b/ApplicationCommands/Preconditions/EnforceBlocking.cs index 9ed68a5..2bf692e 100644 --- a/ApplicationCommands/Preconditions/EnforceBlocking.cs +++ b/ApplicationCommands/Preconditions/EnforceBlocking.cs @@ -24,8 +24,8 @@ class EnforceBlockingAttribute : PreconditionAttribute { using var db = new BotDatabaseContext(); var settings = (from row in db.GuildConfigurations - where row.GuildId == (long)guild.Id - select new { ModRole = (ulong?)row.ModeratorRole, ModMode = row.Moderated }).FirstOrDefault(); + where row.GuildId == guild.Id + select new { ModRole = row.ModeratorRole, ModMode = row.Moderated }).FirstOrDefault(); if (settings != null) { // Bot moderators override all blocking measures in place if (user.Roles.Any(r => r.Id == settings.ModRole)) return Task.FromResult(PreconditionResult.FromSuccess()); @@ -34,7 +34,7 @@ class EnforceBlockingAttribute : PreconditionAttribute { if (settings.ModMode) return Task.FromResult(PreconditionResult.FromError(FailModerated)); // Check if user exists in blocklist - if (db.BlocklistEntries.Where(row => row.GuildId == (long)guild.Id && row.UserId == (long)user.Id).Any()) + if (db.BlocklistEntries.Where(row => row.GuildId == guild.Id && row.UserId == user.Id).Any()) return Task.FromResult(PreconditionResult.FromError(FailBlocked)); } diff --git a/ApplicationCommands/Preconditions/RequireBotModerator.cs b/ApplicationCommands/Preconditions/RequireBotModerator.cs index f62aa07..74aaf3b 100644 --- a/ApplicationCommands/Preconditions/RequireBotModerator.cs +++ b/ApplicationCommands/Preconditions/RequireBotModerator.cs @@ -22,7 +22,7 @@ class RequireBotModeratorAttribute : PreconditionAttribute { if (user.GuildPermissions.ManageGuild) return Task.FromResult(PreconditionResult.FromSuccess()); using var db = new BotDatabaseContext(); var checkRole = (ulong?)db.GuildConfigurations - .Where(g => g.GuildId == (long)((SocketGuild)context.Guild).Id) + .Where(g => g.GuildId == ((SocketGuild)context.Guild).Id) .Select(g => g.ModeratorRole).FirstOrDefault(); if (checkRole.HasValue && user.Roles.Any(r => r.Id == checkRole.Value)) return Task.FromResult(PreconditionResult.FromSuccess()); diff --git a/BackgroundServices/AutoUserDownload.cs b/BackgroundServices/AutoUserDownload.cs index 229feb0..dffcd6f 100644 --- a/BackgroundServices/AutoUserDownload.cs +++ b/BackgroundServices/AutoUserDownload.cs @@ -10,9 +10,9 @@ class AutoUserDownload : BackgroundService { public override async Task OnTick(int tickCount, CancellationToken token) { // Take action if a guild's cache is incomplete... - var incompleteCaches = ShardInstance.DiscordClient.Guilds.Where(g => !g.HasAllMembers).Select(g => (long)g.Id).ToHashSet(); + var incompleteCaches = ShardInstance.DiscordClient.Guilds.Where(g => !g.HasAllMembers).Select(g => g.Id).ToHashSet(); // ...and if the guild contains any user data - IEnumerable mustFetch; + IEnumerable mustFetch; try { await DbConcurrentOperationsLock.WaitAsync(token); using var db = new BotDatabaseContext(); diff --git a/BackgroundServices/BirthdayRoleUpdate.cs b/BackgroundServices/BirthdayRoleUpdate.cs index 48d908b..5a3d519 100644 --- a/BackgroundServices/BirthdayRoleUpdate.cs +++ b/BackgroundServices/BirthdayRoleUpdate.cs @@ -27,9 +27,9 @@ class BirthdayRoleUpdate : BackgroundService { private async Task ProcessBirthdaysAsync(CancellationToken token) { // For database efficiency, fetch all database information at once before proceeding using var db = new BotDatabaseContext(); - var shardGuilds = ShardInstance.DiscordClient.Guilds.Select(g => (long)g.Id).ToHashSet(); + var shardGuilds = ShardInstance.DiscordClient.Guilds.Select(g => g.Id).ToHashSet(); var presentGuildSettings = db.GuildConfigurations.Where(s => shardGuilds.Contains(s.GuildId)); - var guildChecks = presentGuildSettings.ToList().Select(s => Tuple.Create((ulong)s.GuildId, s)); + var guildChecks = presentGuildSettings.ToList().Select(s => Tuple.Create(s.GuildId, s)); var exceptions = new List(); foreach (var (guildId, settings) in guildChecks) { diff --git a/BackgroundServices/DataRetention.cs b/BackgroundServices/DataRetention.cs index ee5f942..6f0a0e6 100644 --- a/BackgroundServices/DataRetention.cs +++ b/BackgroundServices/DataRetention.cs @@ -34,7 +34,7 @@ class DataRetention : BackgroundService { var now = DateTimeOffset.UtcNow; // Update guilds - var localGuilds = ShardInstance.DiscordClient.Guilds.Select(g => (long)g.Id).ToList(); + var localGuilds = ShardInstance.DiscordClient.Guilds.Select(g => g.Id).ToList(); var updatedGuilds = await db.GuildConfigurations .Where(g => localGuilds.Contains(g.GuildId)) .ExecuteUpdateAsync(upd => upd.SetProperty(p => p.LastSeen, now)); @@ -42,9 +42,9 @@ class DataRetention : BackgroundService { // Update guild users var updatedUsers = 0; foreach (var guild in ShardInstance.DiscordClient.Guilds) { - var localUsers = guild.Users.Select(u => (long)u.Id).ToList(); + var localUsers = guild.Users.Select(u => u.Id).ToList(); updatedUsers += await db.UserEntries - .Where(gu => gu.GuildId == (long)guild.Id) + .Where(gu => gu.GuildId == guild.Id) .Where(gu => localUsers.Contains(gu.UserId)) .ExecuteUpdateAsync(upd => upd.SetProperty(p => p.LastSeen, now)); } diff --git a/Data/BlocklistEntry.cs b/Data/BlocklistEntry.cs index 34829cc..b9b30e4 100644 --- a/Data/BlocklistEntry.cs +++ b/Data/BlocklistEntry.cs @@ -6,11 +6,9 @@ namespace BirthdayBot.Data; [Table("banned_users")] public class BlocklistEntry { [Key] - [Column("guild_id")] - public long GuildId { get; set; } + public ulong GuildId { get; set; } [Key] - [Column("user_id")] - public long UserId { get; set; } + public ulong UserId { get; set; } [ForeignKey(nameof(GuildConfig.GuildId))] [InverseProperty(nameof(GuildConfig.BlockedUsers))] diff --git a/Data/Extensions.cs b/Data/Extensions.cs index 1b48e66..ace30ac 100644 --- a/Data/Extensions.cs +++ b/Data/Extensions.cs @@ -6,14 +6,14 @@ internal static class Extensions { /// If it doesn't exist in the database, returns true. /// public static GuildConfig GetConfigOrNew(this SocketGuild guild, BotDatabaseContext db) - => db.GuildConfigurations.Where(g => g.GuildId == (long)guild.Id).FirstOrDefault() - ?? new GuildConfig() { IsNew = true, GuildId = (long)guild.Id }; + => db.GuildConfigurations.Where(g => g.GuildId == guild.Id).FirstOrDefault() + ?? new GuildConfig() { IsNew = true, GuildId = guild.Id }; /// /// Gets the corresponding for this user in this guild, or a new one if one does not exist. /// If it doesn't exist in the database, returns true. /// public static UserEntry GetUserEntryOrNew(this SocketGuildUser user, BotDatabaseContext db) - => db.UserEntries.Where(u => u.GuildId == (long)user.Guild.Id && u.UserId == (long)user.Id).FirstOrDefault() - ?? new UserEntry() { IsNew = true, GuildId = (long)user.Guild.Id, UserId = (long)user.Id }; + => db.UserEntries.Where(u => u.GuildId == user.Guild.Id && u.UserId == user.Id).FirstOrDefault() + ?? new UserEntry() { IsNew = true, GuildId = user.Guild.Id, UserId = user.Id }; } \ No newline at end of file diff --git a/Data/GuildConfig.cs b/Data/GuildConfig.cs index df66398..2b3c009 100644 --- a/Data/GuildConfig.cs +++ b/Data/GuildConfig.cs @@ -10,25 +10,27 @@ public class GuildConfig { } [Key] - [Column("guild_id")] - public long GuildId { get; set; } + public ulong GuildId { get; set; } + [Column("role_id")] - public long? BirthdayRole { get; set; } + public ulong? BirthdayRole { get; set; } + [Column("channel_announce_id")] - public long? AnnouncementChannel { get; set; } + public ulong? AnnouncementChannel { get; set; } + [Column("time_zone")] public string? GuildTimeZone { get; set; } - [Column("moderated")] + public bool Moderated { get; set; } - [Column("moderator_role")] - public long? ModeratorRole { get; set; } - [Column("announce_message")] + + public ulong? ModeratorRole { get; set; } + public string? AnnounceMessage { get; set; } - [Column("announce_message_pl")] + public string? AnnounceMessagePl { get; set; } - [Column("announce_ping")] + public bool AnnouncePing { get; set; } - [Column("last_seen")] + public DateTimeOffset LastSeen { get; set; } [InverseProperty(nameof(BlocklistEntry.Guild))] diff --git a/Data/Migrations/20221123062847_LongToUlong.Designer.cs b/Data/Migrations/20221123062847_LongToUlong.Designer.cs new file mode 100644 index 0000000..ea9e8c0 --- /dev/null +++ b/Data/Migrations/20221123062847_LongToUlong.Designer.cs @@ -0,0 +1,161 @@ +// +using System; +using BirthdayBot.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace BirthdayBot.Data.Migrations +{ + [DbContext(typeof(BotDatabaseContext))] + [Migration("20221123062847_LongToUlong")] + partial class LongToUlong + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "7.0.0") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("BirthdayBot.Data.BlocklistEntry", b => + { + b.Property("GuildId") + .HasColumnType("numeric(20,0)") + .HasColumnName("guild_id"); + + b.Property("UserId") + .HasColumnType("numeric(20,0)") + .HasColumnName("user_id"); + + b.HasKey("GuildId", "UserId") + .HasName("banned_users_pkey"); + + b.ToTable("banned_users", (string)null); + }); + + modelBuilder.Entity("BirthdayBot.Data.GuildConfig", b => + { + b.Property("GuildId") + .HasColumnType("numeric(20,0)") + .HasColumnName("guild_id"); + + b.Property("AnnounceMessage") + .HasColumnType("text") + .HasColumnName("announce_message"); + + b.Property("AnnounceMessagePl") + .HasColumnType("text") + .HasColumnName("announce_message_pl"); + + b.Property("AnnouncePing") + .HasColumnType("boolean") + .HasColumnName("announce_ping"); + + b.Property("AnnouncementChannel") + .HasColumnType("numeric(20,0)") + .HasColumnName("channel_announce_id"); + + b.Property("BirthdayRole") + .HasColumnType("numeric(20,0)") + .HasColumnName("role_id"); + + b.Property("GuildTimeZone") + .HasColumnType("text") + .HasColumnName("time_zone"); + + b.Property("LastSeen") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("last_seen") + .HasDefaultValueSql("now()"); + + b.Property("Moderated") + .HasColumnType("boolean") + .HasColumnName("moderated"); + + b.Property("ModeratorRole") + .HasColumnType("numeric(20,0)") + .HasColumnName("moderator_role"); + + b.HasKey("GuildId") + .HasName("settings_pkey"); + + b.ToTable("settings", (string)null); + }); + + modelBuilder.Entity("BirthdayBot.Data.UserEntry", b => + { + b.Property("GuildId") + .HasColumnType("numeric(20,0)") + .HasColumnName("guild_id"); + + b.Property("UserId") + .HasColumnType("numeric(20,0)") + .HasColumnName("user_id"); + + b.Property("BirthDay") + .HasColumnType("integer") + .HasColumnName("birth_day"); + + b.Property("BirthMonth") + .HasColumnType("integer") + .HasColumnName("birth_month"); + + b.Property("LastSeen") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("last_seen") + .HasDefaultValueSql("now()"); + + b.Property("TimeZone") + .HasColumnType("text") + .HasColumnName("time_zone"); + + b.HasKey("GuildId", "UserId") + .HasName("user_birthdays_pkey"); + + b.ToTable("user_birthdays", (string)null); + }); + + modelBuilder.Entity("BirthdayBot.Data.BlocklistEntry", b => + { + b.HasOne("BirthdayBot.Data.GuildConfig", "Guild") + .WithMany("BlockedUsers") + .HasForeignKey("GuildId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("banned_users_guild_id_fkey"); + + b.Navigation("Guild"); + }); + + modelBuilder.Entity("BirthdayBot.Data.UserEntry", b => + { + b.HasOne("BirthdayBot.Data.GuildConfig", "Guild") + .WithMany("UserEntries") + .HasForeignKey("GuildId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("user_birthdays_guild_id_fkey"); + + b.Navigation("Guild"); + }); + + modelBuilder.Entity("BirthdayBot.Data.GuildConfig", b => + { + b.Navigation("BlockedUsers"); + + b.Navigation("UserEntries"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Data/Migrations/20221123062847_LongToUlong.cs b/Data/Migrations/20221123062847_LongToUlong.cs new file mode 100644 index 0000000..cf6e301 --- /dev/null +++ b/Data/Migrations/20221123062847_LongToUlong.cs @@ -0,0 +1,177 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace BirthdayBot.Data.Migrations +{ + /// + public partial class LongToUlong : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + // NOTE: manually edited - must drop and re-add foreign key due to altered types + migrationBuilder.DropForeignKey( + name: "user_birthdays_guild_id_fkey", + table: "user_birthdays"); + + migrationBuilder.AlterColumn( + name: "user_id", + table: "user_birthdays", + type: "numeric(20,0)", + nullable: false, + oldClrType: typeof(long), + oldType: "bigint"); + + migrationBuilder.AlterColumn( + name: "guild_id", + table: "user_birthdays", + type: "numeric(20,0)", + nullable: false, + oldClrType: typeof(long), + oldType: "bigint"); + + migrationBuilder.AlterColumn( + name: "role_id", + table: "settings", + type: "numeric(20,0)", + nullable: true, + oldClrType: typeof(long), + oldType: "bigint", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "moderator_role", + table: "settings", + type: "numeric(20,0)", + nullable: true, + oldClrType: typeof(long), + oldType: "bigint", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "channel_announce_id", + table: "settings", + type: "numeric(20,0)", + nullable: true, + oldClrType: typeof(long), + oldType: "bigint", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "guild_id", + table: "settings", + type: "numeric(20,0)", + nullable: false, + oldClrType: typeof(long), + oldType: "bigint"); + + migrationBuilder.AlterColumn( + name: "user_id", + table: "banned_users", + type: "numeric(20,0)", + nullable: false, + oldClrType: typeof(long), + oldType: "bigint"); + + migrationBuilder.AlterColumn( + name: "guild_id", + table: "banned_users", + type: "numeric(20,0)", + nullable: false, + oldClrType: typeof(long), + oldType: "bigint"); + + migrationBuilder.AddForeignKey( + name: "user_birthdays_guild_id_fkey", + table: "user_birthdays", + column: "guild_id", + principalTable: "settings", + principalColumn: "guild_id", + onDelete: ReferentialAction.Cascade); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "user_birthdays_guild_id_fkey", + table: "user_birthdays"); + + migrationBuilder.AlterColumn( + name: "user_id", + table: "user_birthdays", + type: "bigint", + nullable: false, + oldClrType: typeof(decimal), + oldType: "numeric(20,0)"); + + migrationBuilder.AlterColumn( + name: "guild_id", + table: "user_birthdays", + type: "bigint", + nullable: false, + oldClrType: typeof(decimal), + oldType: "numeric(20,0)"); + + migrationBuilder.AlterColumn( + name: "role_id", + table: "settings", + type: "bigint", + nullable: true, + oldClrType: typeof(decimal), + oldType: "numeric(20,0)", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "moderator_role", + table: "settings", + type: "bigint", + nullable: true, + oldClrType: typeof(decimal), + oldType: "numeric(20,0)", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "channel_announce_id", + table: "settings", + type: "bigint", + nullable: true, + oldClrType: typeof(decimal), + oldType: "numeric(20,0)", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "guild_id", + table: "settings", + type: "bigint", + nullable: false, + oldClrType: typeof(decimal), + oldType: "numeric(20,0)"); + + migrationBuilder.AlterColumn( + name: "user_id", + table: "banned_users", + type: "bigint", + nullable: false, + oldClrType: typeof(decimal), + oldType: "numeric(20,0)"); + + migrationBuilder.AlterColumn( + name: "guild_id", + table: "banned_users", + type: "bigint", + nullable: false, + oldClrType: typeof(decimal), + oldType: "numeric(20,0)"); + + migrationBuilder.AddForeignKey( + name: "user_birthdays_guild_id_fkey", + table: "user_birthdays", + column: "guild_id", + principalTable: "settings", + principalColumn: "guild_id", + onDelete: ReferentialAction.Cascade); + } + } +} diff --git a/Data/Migrations/BotDatabaseContextModelSnapshot.cs b/Data/Migrations/BotDatabaseContextModelSnapshot.cs index 837075b..98f9f26 100644 --- a/Data/Migrations/BotDatabaseContextModelSnapshot.cs +++ b/Data/Migrations/BotDatabaseContextModelSnapshot.cs @@ -17,19 +17,19 @@ namespace BirthdayBot.Data.Migrations { #pragma warning disable 612, 618 modelBuilder - .HasAnnotation("ProductVersion", "6.0.3") + .HasAnnotation("ProductVersion", "7.0.0") .HasAnnotation("Relational:MaxIdentifierLength", 63); NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); modelBuilder.Entity("BirthdayBot.Data.BlocklistEntry", b => { - b.Property("GuildId") - .HasColumnType("bigint") + b.Property("GuildId") + .HasColumnType("numeric(20,0)") .HasColumnName("guild_id"); - b.Property("UserId") - .HasColumnType("bigint") + b.Property("UserId") + .HasColumnType("numeric(20,0)") .HasColumnName("user_id"); b.HasKey("GuildId", "UserId") @@ -40,8 +40,8 @@ namespace BirthdayBot.Data.Migrations modelBuilder.Entity("BirthdayBot.Data.GuildConfig", b => { - b.Property("GuildId") - .HasColumnType("bigint") + b.Property("GuildId") + .HasColumnType("numeric(20,0)") .HasColumnName("guild_id"); b.Property("AnnounceMessage") @@ -56,10 +56,18 @@ namespace BirthdayBot.Data.Migrations .HasColumnType("boolean") .HasColumnName("announce_ping"); - b.Property("ChannelAnnounceId") - .HasColumnType("bigint") + b.Property("AnnouncementChannel") + .HasColumnType("numeric(20,0)") .HasColumnName("channel_announce_id"); + b.Property("BirthdayRole") + .HasColumnType("numeric(20,0)") + .HasColumnName("role_id"); + + b.Property("GuildTimeZone") + .HasColumnType("text") + .HasColumnName("time_zone"); + b.Property("LastSeen") .ValueGeneratedOnAdd() .HasColumnType("timestamp with time zone") @@ -70,18 +78,10 @@ namespace BirthdayBot.Data.Migrations .HasColumnType("boolean") .HasColumnName("moderated"); - b.Property("ModeratorRole") - .HasColumnType("bigint") + b.Property("ModeratorRole") + .HasColumnType("numeric(20,0)") .HasColumnName("moderator_role"); - b.Property("RoleId") - .HasColumnType("bigint") - .HasColumnName("role_id"); - - b.Property("TimeZone") - .HasColumnType("text") - .HasColumnName("time_zone"); - b.HasKey("GuildId") .HasName("settings_pkey"); @@ -90,12 +90,12 @@ namespace BirthdayBot.Data.Migrations modelBuilder.Entity("BirthdayBot.Data.UserEntry", b => { - b.Property("GuildId") - .HasColumnType("bigint") + b.Property("GuildId") + .HasColumnType("numeric(20,0)") .HasColumnName("guild_id"); - b.Property("UserId") - .HasColumnType("bigint") + b.Property("UserId") + .HasColumnType("numeric(20,0)") .HasColumnName("user_id"); b.Property("BirthDay") diff --git a/Data/UserEntry.cs b/Data/UserEntry.cs index dc2e74f..49dc58e 100644 --- a/Data/UserEntry.cs +++ b/Data/UserEntry.cs @@ -6,18 +6,16 @@ namespace BirthdayBot.Data; [Table("user_birthdays")] public class UserEntry { [Key] - [Column("guild_id")] - public long GuildId { get; set; } + public ulong GuildId { get; set; } [Key] - [Column("user_id")] - public long UserId { get; set; } - [Column("birth_month")] + public ulong UserId { get; set; } + public int BirthMonth { get; set; } - [Column("birth_day")] + public int BirthDay { get; set; } - [Column("time_zone")] + public string? TimeZone { get; set; } - [Column("last_seen")] + public DateTimeOffset LastSeen { get; set; } [ForeignKey(nameof(GuildConfig.GuildId))]