Fix several database issues
- Specify default value - Cache all guild users on initial download - Fix foreign key constraint issues
This commit is contained in:
parent
da31ce3e0d
commit
6afa6dc2c6
6 changed files with 36 additions and 16 deletions
|
@ -33,6 +33,7 @@ public class BotDatabaseContext : DbContext {
|
|||
modelBuilder.Entity<CachedGuildUser>(entity => {
|
||||
entity.Navigation(e => e.User).AutoInclude();
|
||||
entity.HasKey(e => new { e.UserId, e.GuildId });
|
||||
entity.Property(e => e.FirstSeenTime).HasDefaultValueSql("now()");
|
||||
});
|
||||
modelBuilder.Entity<CachedGuildMessage>(entity => entity.Property(e => e.CreatedAt).HasDefaultValueSql("now()"));
|
||||
}
|
||||
|
|
|
@ -13,8 +13,8 @@ using RegexBot.Data;
|
|||
namespace RegexBot.Data.Migrations
|
||||
{
|
||||
[DbContext(typeof(BotDatabaseContext))]
|
||||
[Migration("20220513061851_InitialEFSetup")]
|
||||
partial class InitialEFSetup
|
||||
[Migration("20220610210059_InitialMigration")]
|
||||
partial class InitialMigration
|
||||
{
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
|
@ -83,8 +83,10 @@ namespace RegexBot.Data.Migrations
|
|||
.HasColumnName("guild_id");
|
||||
|
||||
b.Property<DateTimeOffset>("FirstSeenTime")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("first_seen_time");
|
||||
.HasColumnName("first_seen_time")
|
||||
.HasDefaultValueSql("now()");
|
||||
|
||||
b.Property<DateTimeOffset>("GULastUpdateTime")
|
||||
.HasColumnType("timestamp with time zone")
|
|
@ -7,7 +7,7 @@ using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
|||
|
||||
namespace RegexBot.Data.Migrations
|
||||
{
|
||||
public partial class InitialEFSetup : Migration
|
||||
public partial class InitialMigration : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
|
@ -73,7 +73,7 @@ namespace RegexBot.Data.Migrations
|
|||
user_id = table.Column<long>(type: "bigint", nullable: false),
|
||||
guild_id = table.Column<long>(type: "bigint", nullable: false),
|
||||
gu_last_update_time = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false),
|
||||
first_seen_time = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false),
|
||||
first_seen_time = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false, defaultValueSql: "now()"),
|
||||
nickname = table.Column<string>(type: "text", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
|
@ -81,8 +81,10 @@ namespace RegexBot.Data.Migrations
|
|||
.HasColumnName("guild_id");
|
||||
|
||||
b.Property<DateTimeOffset>("FirstSeenTime")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("first_seen_time");
|
||||
.HasColumnName("first_seen_time")
|
||||
.HasDefaultValueSql("now()");
|
||||
|
||||
b.Property<DateTimeOffset>("GULastUpdateTime")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
|
|
|
@ -29,7 +29,8 @@ class Program {
|
|||
MessageCacheSize = 0, // using our own
|
||||
LogLevel = LogSeverity.Info,
|
||||
GatewayIntents = GatewayIntents.All & ~GatewayIntents.GuildPresences,
|
||||
LogGatewayIntentWarnings = false
|
||||
LogGatewayIntentWarnings = false,
|
||||
AlwaysDownloadUsers = true
|
||||
});
|
||||
|
||||
// Kerobot class initialization - will set up services and modules
|
||||
|
|
|
@ -13,16 +13,35 @@ class UserCachingSubservice {
|
|||
private static Regex DiscriminatorSearch { get; } = new(@"(.+)#(\d{4}(?!\d))", RegexOptions.Compiled);
|
||||
|
||||
internal UserCachingSubservice(RegexbotClient bot) {
|
||||
bot.DiscordClient.GuildMembersDownloaded += DiscordClient_GuildMembersDownloaded;
|
||||
bot.DiscordClient.GuildMemberUpdated += DiscordClient_GuildMemberUpdated;
|
||||
bot.DiscordClient.UserUpdated += DiscordClient_UserUpdated;
|
||||
}
|
||||
|
||||
private async Task DiscordClient_GuildMembersDownloaded(SocketGuild arg) {
|
||||
using var db = new BotDatabaseContext();
|
||||
foreach (var user in arg.Users) {
|
||||
UpdateUser(user, db);
|
||||
UpdateGuildUser(user, db);
|
||||
}
|
||||
await db.SaveChangesAsync();
|
||||
}
|
||||
|
||||
private async Task DiscordClient_GuildMemberUpdated(Discord.Cacheable<SocketGuildUser, ulong> old, SocketGuildUser current) {
|
||||
using var db = new BotDatabaseContext();
|
||||
UpdateUser(current, db); // Update user data first (avoid potential foreign key constraint violation)
|
||||
UpdateGuildUser(current, db);
|
||||
|
||||
await db.SaveChangesAsync();
|
||||
}
|
||||
|
||||
private async Task DiscordClient_UserUpdated(SocketUser old, SocketUser current) {
|
||||
using var db = new BotDatabaseContext();
|
||||
UpdateUser(current, db);
|
||||
await db.SaveChangesAsync();
|
||||
}
|
||||
|
||||
// IMPORTANT: Do NOT forget to save changes in database after calling this!
|
||||
private static void UpdateUser(SocketUser user, BotDatabaseContext db) {
|
||||
CachedUser uinfo;
|
||||
try {
|
||||
|
@ -38,23 +57,18 @@ class UserCachingSubservice {
|
|||
uinfo.ULastUpdateTime = DateTimeOffset.UtcNow;
|
||||
}
|
||||
|
||||
private async Task DiscordClient_GuildMemberUpdated(Discord.Cacheable<SocketGuildUser, ulong> old, SocketGuildUser current) {
|
||||
using var db = new BotDatabaseContext();
|
||||
UpdateUser(current, db); // Update user data too (avoid potential foreign key constraint violation)
|
||||
|
||||
private static void UpdateGuildUser(SocketGuildUser user, BotDatabaseContext db) {
|
||||
CachedGuildUser guinfo;
|
||||
try {
|
||||
guinfo = db.GuildUserCache.Where(c => c.GuildId == (long)current.Guild.Id && c.UserId == (long)current.Id).First();
|
||||
guinfo = db.GuildUserCache.Where(c => c.GuildId == (long)user.Guild.Id && c.UserId == (long)user.Id).First();
|
||||
} catch (InvalidOperationException) {
|
||||
guinfo = new() { GuildId = (long)current.Guild.Id, UserId = (long)current.Id };
|
||||
guinfo = new() { GuildId = (long)user.Guild.Id, UserId = (long)user.Id };
|
||||
db.GuildUserCache.Add(guinfo);
|
||||
}
|
||||
|
||||
guinfo.GULastUpdateTime = DateTimeOffset.UtcNow;
|
||||
guinfo.Nickname = current.Nickname;
|
||||
guinfo.Nickname = user.Nickname;
|
||||
// TODO guild-specific avatar, other details?
|
||||
|
||||
await db.SaveChangesAsync();
|
||||
}
|
||||
|
||||
// Hooked
|
||||
|
|
Loading…
Reference in a new issue