Compare commits

...

4 commits

Author SHA1 Message Date
Noi
de7e83ee50 Modify database context and navigation
Creating a migration as-is creates an extraneous column. Need to figure
out what the problem is.
2022-12-03 19:35:42 -08:00
Noi
b76d45a271 Update EF Core; create migration for previous commit 2022-12-03 18:09:48 -08:00
Noi
3dd252c353 Merge branch 'dev' into sql-updates 2022-12-03 17:47:57 -08:00
Noi
ebe3a403f3 Remove ulong->long casts 2022-12-03 17:46:26 -08:00
15 changed files with 521 additions and 71 deletions

View file

@ -54,6 +54,10 @@ public class BotDatabaseContext : DbContext {
modelBuilder.Entity<CachedGuildUser>(e => { modelBuilder.Entity<CachedGuildUser>(e => {
e.HasKey(p => new { p.GuildId, p.UserId }); e.HasKey(p => new { p.GuildId, p.UserId });
e.Property(p => p.FirstSeenTime).HasDefaultValueSql("now()"); e.Property(p => p.FirstSeenTime).HasDefaultValueSql("now()");
e.HasOne(entry => entry.User)
.WithMany(u => u.Guilds)
.HasForeignKey(entry => entry.UserId);
e.Navigation(entry => entry.User).AutoInclude();
}); });
modelBuilder.Entity<CachedGuildMessage>(e => e.Property(p => p.CreatedAt).HasDefaultValueSql("now()")); modelBuilder.Entity<CachedGuildMessage>(e => e.Property(p => p.CreatedAt).HasDefaultValueSql("now()"));
modelBuilder.HasPostgresEnum<ModLogType>(); modelBuilder.HasPostgresEnum<ModLogType>();
@ -62,6 +66,14 @@ public class BotDatabaseContext : DbContext {
e.HasOne(entry => entry.User) e.HasOne(entry => entry.User)
.WithMany(gu => gu.Logs) .WithMany(gu => gu.Logs)
.HasForeignKey(entry => new { entry.GuildId, entry.UserId }); .HasForeignKey(entry => new { entry.GuildId, entry.UserId });
e.Navigation(entry => entry.User).AutoInclude();
});
modelBuilder.Entity<CachedGuildMessage>(e => {
e.HasOne(entry => entry.Author)
.WithMany(gu => gu.Messages)
.HasForeignKey(cgm => new { cgm.GuildId, cgm.AuthorId })
.HasPrincipalKey(cgu => new { cgu.GuildId, cgu.UserId });
e.Navigation(entry => entry.Author).AutoInclude();
}); });
} }
} }

View file

@ -12,22 +12,22 @@ public class CachedGuildMessage {
/// </summary> /// </summary>
[Key] [Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)] [DatabaseGenerated(DatabaseGeneratedOption.None)]
public long MessageId { get; set; } public ulong MessageId { get; set; }
/// <summary> /// <summary>
/// Gets the message author's snowflake ID. /// Gets the message author's snowflake ID.
/// </summary> /// </summary>
public long AuthorId { get; set; } public ulong AuthorId { get; set; }
/// <summary> /// <summary>
/// Gets the associated guild's snowflake ID. /// Gets the associated guild's snowflake ID.
/// </summary> /// </summary>
public long GuildId { get; set; } public ulong GuildId { get; set; }
/// <summary> /// <summary>
/// Gets the corresponding channel's snowflake ID. /// Gets the corresponding channel's snowflake ID.
/// </summary> /// </summary>
public long ChannelId { get; set; } public ulong ChannelId { get; set; }
/// <summary> /// <summary>
/// Gets the timestamp showing when this message was originally created. /// Gets the timestamp showing when this message was originally created.
@ -53,11 +53,8 @@ public class CachedGuildMessage {
/// </summary> /// </summary>
public string? Content { get; set; } = null!; public string? Content { get; set; } = null!;
/// <inheritdoc cref="CachedGuildUser.User" /> /// <inheritdoc cref="ModLogEntry.User"/>
[ForeignKey(nameof(AuthorId))] public CachedGuildUser Author { get; set; } = null!;
[InverseProperty(nameof(CachedUser.GuildMessages))]
public CachedUser Author { get; set; } = null!;
// TODO set up composite foreign key. will require rewriting some parts in modules...
// Used by MessageCachingSubservice // Used by MessageCachingSubservice
internal static CachedGuildMessage? Clone(CachedGuildMessage? original) { internal static CachedGuildMessage? Clone(CachedGuildMessage? original) {

View file

@ -9,10 +9,10 @@ public class CachedGuildUser {
/// <summary> /// <summary>
/// Gets the associated guild's snowflake ID. /// Gets the associated guild's snowflake ID.
/// </summary> /// </summary>
public long GuildId { get; set; } public ulong GuildId { get; set; }
/// <inheritdoc cref="CachedUser.UserId"/> /// <inheritdoc cref="CachedUser.UserId"/>
public long UserId { get; set; } public ulong UserId { get; set; }
/// <inheritdoc cref="CachedUser.ULastUpdateTime"/> /// <inheritdoc cref="CachedUser.ULastUpdateTime"/>
public DateTimeOffset GULastUpdateTime { get; set; } public DateTimeOffset GULastUpdateTime { get; set; }
@ -28,14 +28,17 @@ public class CachedGuildUser {
public string? Nickname { get; set; } public string? Nickname { get; set; }
/// <summary> /// <summary>
/// If included in the query, references the associated <seealso cref="CachedUser"/> for this entry. /// Gets the associated <seealso cref="CachedUser"/> for this entry. This entity is auto-included.
/// </summary> /// </summary>
[ForeignKey(nameof(UserId))]
[InverseProperty(nameof(CachedUser.Guilds))]
public CachedUser User { get; set; } = null!; public CachedUser User { get; set; } = null!;
/// <summary> /// <summary>
/// If included in the query, references all <seealso cref="ModLogEntry"/> items associated with this entry. /// If included in the query, references all <seealso cref="ModLogEntry"/> items associated with this entry.
/// </summary> /// </summary>
public ICollection<ModLogEntry> Logs { get; set; } = null!; public ICollection<ModLogEntry> Logs { get; set; } = null!;
/// <summary>
/// If included in the query, references all <seealso cref="CachedGuildMessage"/> items associated with this entry.
/// </summary>
public ICollection<CachedGuildMessage> Messages { get; set; } = null!;
} }

View file

@ -12,7 +12,7 @@ public class CachedUser {
/// </summary> /// </summary>
[Key] [Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)] [DatabaseGenerated(DatabaseGeneratedOption.None)]
public long UserId { get; set; } public ulong UserId { get; set; }
/// <summary> /// <summary>
/// Gets the timestamp showing when this cache entry was last updated. /// Gets the timestamp showing when this cache entry was last updated.
@ -37,12 +37,10 @@ public class CachedUser {
/// <summary> /// <summary>
/// If included in the query, gets the list of associated <seealso cref="CachedGuildUser"/> entries for this entry. /// If included in the query, gets the list of associated <seealso cref="CachedGuildUser"/> entries for this entry.
/// </summary> /// </summary>
[InverseProperty(nameof(CachedGuildUser.User))]
public ICollection<CachedGuildUser> Guilds { get; set; } = null!; public ICollection<CachedGuildUser> Guilds { get; set; } = null!;
/// <summary> /// <summary>
/// If included in the query, gets the list of associated <seealso cref="CachedGuildMessage"/> entries for this entry. /// If included in the query, gets the list of associated <seealso cref="CachedGuildMessage"/> entries for this entry.
/// </summary> /// </summary>
[InverseProperty(nameof(CachedGuildMessage.Author))]
public ICollection<CachedGuildMessage> GuildMessages { get; set; } = null!; public ICollection<CachedGuildMessage> GuildMessages { get; set; } = null!;
} }

View file

@ -0,0 +1,236 @@
// <auto-generated />
using System;
using System.Collections.Generic;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
using RegexBot.Data;
#nullable disable
namespace RegexBot.Data.Migrations
{
[DbContext(typeof(BotDatabaseContext))]
[Migration("20221204014949_LongToUlong")]
partial class LongToUlong
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "7.0.0")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "mod_log_type", new[] { "other", "note", "warn", "timeout", "kick", "ban" });
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("RegexBot.Data.CachedGuildMessage", b =>
{
b.Property<decimal>("MessageId")
.HasColumnType("numeric(20,0)")
.HasColumnName("message_id");
b.Property<List<string>>("AttachmentNames")
.IsRequired()
.HasColumnType("text[]")
.HasColumnName("attachment_names");
b.Property<decimal>("AuthorId")
.HasColumnType("numeric(20,0)")
.HasColumnName("author_id");
b.Property<decimal>("ChannelId")
.HasColumnType("numeric(20,0)")
.HasColumnName("channel_id");
b.Property<string>("Content")
.HasColumnType("text")
.HasColumnName("content");
b.Property<DateTimeOffset>("CreatedAt")
.ValueGeneratedOnAdd()
.HasColumnType("timestamp with time zone")
.HasColumnName("created_at")
.HasDefaultValueSql("now()");
b.Property<DateTimeOffset?>("EditedAt")
.HasColumnType("timestamp with time zone")
.HasColumnName("edited_at");
b.Property<decimal>("GuildId")
.HasColumnType("numeric(20,0)")
.HasColumnName("guild_id");
b.HasKey("MessageId")
.HasName("pk_cache_guildmessages");
b.HasIndex("AuthorId")
.HasDatabaseName("ix_cache_guildmessages_author_id");
b.ToTable("cache_guildmessages", (string)null);
});
modelBuilder.Entity("RegexBot.Data.CachedGuildUser", b =>
{
b.Property<decimal>("GuildId")
.HasColumnType("numeric(20,0)")
.HasColumnName("guild_id");
b.Property<decimal>("UserId")
.HasColumnType("numeric(20,0)")
.HasColumnName("user_id");
b.Property<DateTimeOffset>("FirstSeenTime")
.ValueGeneratedOnAdd()
.HasColumnType("timestamp with time zone")
.HasColumnName("first_seen_time")
.HasDefaultValueSql("now()");
b.Property<DateTimeOffset>("GULastUpdateTime")
.HasColumnType("timestamp with time zone")
.HasColumnName("gu_last_update_time");
b.Property<string>("Nickname")
.HasColumnType("text")
.HasColumnName("nickname");
b.HasKey("GuildId", "UserId")
.HasName("pk_cache_usersinguild");
b.HasIndex("UserId")
.HasDatabaseName("ix_cache_usersinguild_user_id");
b.ToTable("cache_usersinguild", (string)null);
});
modelBuilder.Entity("RegexBot.Data.CachedUser", b =>
{
b.Property<decimal>("UserId")
.HasColumnType("numeric(20,0)")
.HasColumnName("user_id");
b.Property<string>("AvatarUrl")
.HasColumnType("text")
.HasColumnName("avatar_url");
b.Property<string>("Discriminator")
.IsRequired()
.HasMaxLength(4)
.HasColumnType("character(4)")
.HasColumnName("discriminator")
.IsFixedLength();
b.Property<DateTimeOffset>("ULastUpdateTime")
.HasColumnType("timestamp with time zone")
.HasColumnName("u_last_update_time");
b.Property<string>("Username")
.IsRequired()
.HasColumnType("text")
.HasColumnName("username");
b.HasKey("UserId")
.HasName("pk_cache_users");
b.ToTable("cache_users", (string)null);
});
modelBuilder.Entity("RegexBot.Data.ModLogEntry", b =>
{
b.Property<int>("LogId")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasColumnName("log_id");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("LogId"));
b.Property<decimal>("GuildId")
.HasColumnType("numeric(20,0)")
.HasColumnName("guild_id");
b.Property<string>("IssuedBy")
.IsRequired()
.HasColumnType("text")
.HasColumnName("issued_by");
b.Property<int>("LogType")
.HasColumnType("integer")
.HasColumnName("log_type");
b.Property<string>("Message")
.HasColumnType("text")
.HasColumnName("message");
b.Property<DateTimeOffset>("Timestamp")
.ValueGeneratedOnAdd()
.HasColumnType("timestamp with time zone")
.HasColumnName("timestamp")
.HasDefaultValueSql("now()");
b.Property<decimal>("UserId")
.HasColumnType("numeric(20,0)")
.HasColumnName("user_id");
b.HasKey("LogId")
.HasName("pk_modlogs");
b.HasIndex("GuildId", "UserId")
.HasDatabaseName("ix_modlogs_guild_id_user_id");
b.ToTable("modlogs", (string)null);
});
modelBuilder.Entity("RegexBot.Data.CachedGuildMessage", b =>
{
b.HasOne("RegexBot.Data.CachedUser", "Author")
.WithMany("GuildMessages")
.HasForeignKey("AuthorId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired()
.HasConstraintName("fk_cache_guildmessages_cache_users_author_id");
b.Navigation("Author");
});
modelBuilder.Entity("RegexBot.Data.CachedGuildUser", b =>
{
b.HasOne("RegexBot.Data.CachedUser", "User")
.WithMany("Guilds")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired()
.HasConstraintName("fk_cache_usersinguild_cache_users_user_id");
b.Navigation("User");
});
modelBuilder.Entity("RegexBot.Data.ModLogEntry", b =>
{
b.HasOne("RegexBot.Data.CachedGuildUser", "User")
.WithMany("Logs")
.HasForeignKey("GuildId", "UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired()
.HasConstraintName("fk_modlogs_cache_usersinguild_user_temp_id");
b.Navigation("User");
});
modelBuilder.Entity("RegexBot.Data.CachedGuildUser", b =>
{
b.Navigation("Logs");
});
modelBuilder.Entity("RegexBot.Data.CachedUser", b =>
{
b.Navigation("GuildMessages");
b.Navigation("Guilds");
});
#pragma warning restore 612, 618
}
}
}

View file

@ -0,0 +1,207 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace RegexBot.Data.Migrations
{
/// <inheritdoc />
public partial class LongToUlong : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
// NOTE: manually edited Up and Down - must drop and re-add foreign keys due to altered types
migrationBuilder.DropForeignKey(
name: "fk_modlogs_cache_usersinguild_user_temp_id",
table: "modlogs");
migrationBuilder.DropForeignKey(
name: "fk_cache_usersinguild_cache_users_user_id",
table: "cache_usersinguild");
migrationBuilder.AlterColumn<decimal>(
name: "user_id",
table: "modlogs",
type: "numeric(20,0)",
nullable: false,
oldClrType: typeof(long),
oldType: "bigint");
migrationBuilder.AlterColumn<decimal>(
name: "guild_id",
table: "modlogs",
type: "numeric(20,0)",
nullable: false,
oldClrType: typeof(long),
oldType: "bigint");
migrationBuilder.AlterColumn<decimal>(
name: "user_id",
table: "cache_usersinguild",
type: "numeric(20,0)",
nullable: false,
oldClrType: typeof(long),
oldType: "bigint");
migrationBuilder.AlterColumn<decimal>(
name: "guild_id",
table: "cache_usersinguild",
type: "numeric(20,0)",
nullable: false,
oldClrType: typeof(long),
oldType: "bigint");
migrationBuilder.AlterColumn<decimal>(
name: "user_id",
table: "cache_users",
type: "numeric(20,0)",
nullable: false,
oldClrType: typeof(long),
oldType: "bigint");
migrationBuilder.AlterColumn<decimal>(
name: "guild_id",
table: "cache_guildmessages",
type: "numeric(20,0)",
nullable: false,
oldClrType: typeof(long),
oldType: "bigint");
migrationBuilder.AlterColumn<decimal>(
name: "channel_id",
table: "cache_guildmessages",
type: "numeric(20,0)",
nullable: false,
oldClrType: typeof(long),
oldType: "bigint");
migrationBuilder.AlterColumn<decimal>(
name: "author_id",
table: "cache_guildmessages",
type: "numeric(20,0)",
nullable: false,
oldClrType: typeof(long),
oldType: "bigint");
migrationBuilder.AlterColumn<decimal>(
name: "message_id",
table: "cache_guildmessages",
type: "numeric(20,0)",
nullable: false,
oldClrType: typeof(long),
oldType: "bigint");
migrationBuilder.AddForeignKey(
name: "fk_modlogs_cache_usersinguild_user_temp_id",
table: "modlogs",
columns: new[] { "guild_id", "user_id" },
principalTable: "cache_usersinguild",
principalColumns: new[] { "guild_id", "user_id" },
onDelete: ReferentialAction.Cascade);
migrationBuilder.AddForeignKey(
name: "fk_cache_usersinguild_cache_users_user_id",
table: "cache_usersinguild",
column: "user_id",
principalTable: "cache_users",
principalColumn: "user_id",
onDelete: ReferentialAction.Cascade);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "fk_modlogs_cache_usersinguild_user_temp_id",
table: "modlogs");
migrationBuilder.DropForeignKey(
name: "fk_cache_usersinguild_cache_users_user_id",
table: "cache_usersinguild");
migrationBuilder.AlterColumn<long>(
name: "user_id",
table: "modlogs",
type: "bigint",
nullable: false,
oldClrType: typeof(decimal),
oldType: "numeric(20,0)");
migrationBuilder.AlterColumn<long>(
name: "guild_id",
table: "modlogs",
type: "bigint",
nullable: false,
oldClrType: typeof(decimal),
oldType: "numeric(20,0)");
migrationBuilder.AlterColumn<long>(
name: "user_id",
table: "cache_usersinguild",
type: "bigint",
nullable: false,
oldClrType: typeof(decimal),
oldType: "numeric(20,0)");
migrationBuilder.AlterColumn<long>(
name: "guild_id",
table: "cache_usersinguild",
type: "bigint",
nullable: false,
oldClrType: typeof(decimal),
oldType: "numeric(20,0)");
migrationBuilder.AlterColumn<long>(
name: "user_id",
table: "cache_users",
type: "bigint",
nullable: false,
oldClrType: typeof(decimal),
oldType: "numeric(20,0)");
migrationBuilder.AlterColumn<long>(
name: "guild_id",
table: "cache_guildmessages",
type: "bigint",
nullable: false,
oldClrType: typeof(decimal),
oldType: "numeric(20,0)");
migrationBuilder.AlterColumn<long>(
name: "channel_id",
table: "cache_guildmessages",
type: "bigint",
nullable: false,
oldClrType: typeof(decimal),
oldType: "numeric(20,0)");
migrationBuilder.AlterColumn<long>(
name: "author_id",
table: "cache_guildmessages",
type: "bigint",
nullable: false,
oldClrType: typeof(decimal),
oldType: "numeric(20,0)");
migrationBuilder.AlterColumn<long>(
name: "message_id",
table: "cache_guildmessages",
type: "bigint",
nullable: false,
oldClrType: typeof(decimal),
oldType: "numeric(20,0)");
migrationBuilder.AddForeignKey(
name: "fk_modlogs_cache_usersinguild_user_temp_id",
table: "modlogs",
columns: new[] { "guild_id", "user_id" },
principalTable: "cache_usersinguild",
principalColumns: new[] { "guild_id", "user_id" },
onDelete: ReferentialAction.Cascade);
migrationBuilder.AddForeignKey(
name: "fk_cache_usersinguild_cache_users_user_id",
table: "cache_usersinguild",
column: "user_id",
principalTable: "cache_users",
principalColumn: "user_id",
onDelete: ReferentialAction.Cascade);
}
}
}

View file

@ -18,7 +18,7 @@ namespace RegexBot.Data.Migrations
{ {
#pragma warning disable 612, 618 #pragma warning disable 612, 618
modelBuilder modelBuilder
.HasAnnotation("ProductVersion", "6.0.7") .HasAnnotation("ProductVersion", "7.0.0")
.HasAnnotation("Relational:MaxIdentifierLength", 63); .HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "mod_log_type", new[] { "other", "note", "warn", "timeout", "kick", "ban" }); NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "mod_log_type", new[] { "other", "note", "warn", "timeout", "kick", "ban" });
@ -26,8 +26,8 @@ namespace RegexBot.Data.Migrations
modelBuilder.Entity("RegexBot.Data.CachedGuildMessage", b => modelBuilder.Entity("RegexBot.Data.CachedGuildMessage", b =>
{ {
b.Property<long>("MessageId") b.Property<decimal>("MessageId")
.HasColumnType("bigint") .HasColumnType("numeric(20,0)")
.HasColumnName("message_id"); .HasColumnName("message_id");
b.Property<List<string>>("AttachmentNames") b.Property<List<string>>("AttachmentNames")
@ -35,12 +35,12 @@ namespace RegexBot.Data.Migrations
.HasColumnType("text[]") .HasColumnType("text[]")
.HasColumnName("attachment_names"); .HasColumnName("attachment_names");
b.Property<long>("AuthorId") b.Property<decimal>("AuthorId")
.HasColumnType("bigint") .HasColumnType("numeric(20,0)")
.HasColumnName("author_id"); .HasColumnName("author_id");
b.Property<long>("ChannelId") b.Property<decimal>("ChannelId")
.HasColumnType("bigint") .HasColumnType("numeric(20,0)")
.HasColumnName("channel_id"); .HasColumnName("channel_id");
b.Property<string>("Content") b.Property<string>("Content")
@ -57,8 +57,8 @@ namespace RegexBot.Data.Migrations
.HasColumnType("timestamp with time zone") .HasColumnType("timestamp with time zone")
.HasColumnName("edited_at"); .HasColumnName("edited_at");
b.Property<long>("GuildId") b.Property<decimal>("GuildId")
.HasColumnType("bigint") .HasColumnType("numeric(20,0)")
.HasColumnName("guild_id"); .HasColumnName("guild_id");
b.HasKey("MessageId") b.HasKey("MessageId")
@ -72,12 +72,12 @@ namespace RegexBot.Data.Migrations
modelBuilder.Entity("RegexBot.Data.CachedGuildUser", b => modelBuilder.Entity("RegexBot.Data.CachedGuildUser", b =>
{ {
b.Property<long>("GuildId") b.Property<decimal>("GuildId")
.HasColumnType("bigint") .HasColumnType("numeric(20,0)")
.HasColumnName("guild_id"); .HasColumnName("guild_id");
b.Property<long>("UserId") b.Property<decimal>("UserId")
.HasColumnType("bigint") .HasColumnType("numeric(20,0)")
.HasColumnName("user_id"); .HasColumnName("user_id");
b.Property<DateTimeOffset>("FirstSeenTime") b.Property<DateTimeOffset>("FirstSeenTime")
@ -105,8 +105,8 @@ namespace RegexBot.Data.Migrations
modelBuilder.Entity("RegexBot.Data.CachedUser", b => modelBuilder.Entity("RegexBot.Data.CachedUser", b =>
{ {
b.Property<long>("UserId") b.Property<decimal>("UserId")
.HasColumnType("bigint") .HasColumnType("numeric(20,0)")
.HasColumnName("user_id"); .HasColumnName("user_id");
b.Property<string>("AvatarUrl") b.Property<string>("AvatarUrl")
@ -144,8 +144,8 @@ namespace RegexBot.Data.Migrations
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("LogId")); NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("LogId"));
b.Property<long>("GuildId") b.Property<decimal>("GuildId")
.HasColumnType("bigint") .HasColumnType("numeric(20,0)")
.HasColumnName("guild_id"); .HasColumnName("guild_id");
b.Property<string>("IssuedBy") b.Property<string>("IssuedBy")
@ -167,8 +167,8 @@ namespace RegexBot.Data.Migrations
.HasColumnName("timestamp") .HasColumnName("timestamp")
.HasDefaultValueSql("now()"); .HasDefaultValueSql("now()");
b.Property<long>("UserId") b.Property<decimal>("UserId")
.HasColumnType("bigint") .HasColumnType("numeric(20,0)")
.HasColumnName("user_id"); .HasColumnName("user_id");
b.HasKey("LogId") b.HasKey("LogId")

View file

@ -20,12 +20,12 @@ public class ModLogEntry : ISharedEvent {
public DateTimeOffset Timestamp { get; set; } public DateTimeOffset Timestamp { get; set; }
/// <inheritdoc cref="CachedGuildUser.GuildId"/> /// <inheritdoc cref="CachedGuildUser.GuildId"/>
public long GuildId { get; set; } public ulong GuildId { get; set; }
/// <summary> /// <summary>
/// Gets the ID of the users for which this log entry pertains. /// Gets the ID of the users for which this log entry pertains.
/// </summary> /// </summary>
public long UserId { get; set; } public ulong UserId { get; set; }
/// <summary> /// <summary>
/// Gets the type of log message this represents. /// Gets the type of log message this represents.
@ -44,7 +44,7 @@ public class ModLogEntry : ISharedEvent {
public string? Message { get; set; } public string? Message { get; set; }
/// <summary> /// <summary>
/// If included in the query, gets the associated <seealso cref="CachedGuildUser"/> for this entry. /// Gets the associated <seealso cref="CachedGuildUser"/> for this entry. This entity is auto-included.
/// </summary> /// </summary>
public CachedGuildUser User { get; set; } = null!; public CachedGuildUser User { get; set; } = null!;
} }

View file

@ -1,5 +1,4 @@
using Discord; using Discord;
using Microsoft.EntityFrameworkCore;
using RegexBot.Data; using RegexBot.Data;
using System.Text; using System.Text;
@ -24,8 +23,7 @@ internal partial class ModLogs {
using var db = new BotDatabaseContext(); using var db = new BotDatabaseContext();
var cachedMsg = db.GuildMessageCache var cachedMsg = db.GuildMessageCache
.Include(gm => gm.Author) .Where(gm => gm.MessageId == argMsg.Id)
.Where(gm => gm.MessageId == (long)argMsg.Id)
.SingleOrDefault(); .SingleOrDefault();
var reportEmbed = new EmbedBuilder() var reportEmbed = new EmbedBuilder()
@ -50,8 +48,8 @@ internal partial class ModLogs {
}; };
} else { } else {
reportEmbed.Author = new EmbedAuthorBuilder() { reportEmbed.Author = new EmbedAuthorBuilder() {
Name = $"{cachedMsg.Author.Username}#{cachedMsg.Author.Discriminator}", Name = $"{cachedMsg.Author.User.Username}#{cachedMsg.Author.User.Discriminator}",
IconUrl = cachedMsg.Author.AvatarUrl ?? GetDefaultAvatarUrl(cachedMsg.Author.Discriminator) IconUrl = cachedMsg.Author.User.AvatarUrl ?? GetDefaultAvatarUrl(cachedMsg.Author.User.Discriminator)
}; };
} }
SetAttachmentsField(reportEmbed, cachedMsg.AttachmentNames); SetAttachmentsField(reportEmbed, cachedMsg.AttachmentNames);

View file

@ -22,16 +22,16 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="CommandLineParser" Version="2.9.1" /> <PackageReference Include="CommandLineParser" Version="2.9.1" />
<PackageReference Include="Discord.Net" Version="3.8.1" /> <PackageReference Include="Discord.Net" Version="3.8.1" />
<PackageReference Include="EFCore.NamingConventions" Version="6.0.0" /> <PackageReference Include="EFCore.NamingConventions" Version="7.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.7" /> <PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="6.0.7"> <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="7.0.0">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="6.0.7" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="7.0.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.2" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.2" />
<PackageReference Include="Npgsql" Version="6.0.7" /> <PackageReference Include="Npgsql" Version="7.0.0" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="6.0.7" /> <PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="7.0.0" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL.Design" Version="1.1.0" /> <PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL.Design" Version="1.1.0" />
</ItemGroup> </ItemGroup>

View file

@ -24,8 +24,8 @@ partial class RegexbotClient {
/// </returns> /// </returns>
public async Task<ModLogEntry> AddUserNoteAsync(SocketGuild guild, ulong targetUser, string source, string? message) { public async Task<ModLogEntry> AddUserNoteAsync(SocketGuild guild, ulong targetUser, string source, string? message) {
var entry = new ModLogEntry() { var entry = new ModLogEntry() {
GuildId = (long)guild.Id, GuildId = guild.Id,
UserId = (long)targetUser, UserId = targetUser,
LogType = ModLogType.Note, LogType = ModLogType.Note,
IssuedBy = source, IssuedBy = source,
Message = message Message = message
@ -53,8 +53,8 @@ partial class RegexbotClient {
/// </returns> /// </returns>
public async Task<(ModLogEntry, LogAppendResult)> AddUserWarnAsync(SocketGuild guild, ulong targetUser, string source, string? message) { public async Task<(ModLogEntry, LogAppendResult)> AddUserWarnAsync(SocketGuild guild, ulong targetUser, string source, string? message) {
var entry = new ModLogEntry() { var entry = new ModLogEntry() {
GuildId = (long)guild.Id, GuildId = guild.Id,
UserId = (long)targetUser, UserId = targetUser,
LogType = ModLogType.Warn, LogType = ModLogType.Warn,
IssuedBy = source, IssuedBy = source,
Message = message Message = message

View file

@ -8,8 +8,8 @@ internal partial class CommonFunctionsService : Service {
// A notification for this entry is then propagated. // A notification for this entry is then propagated.
private void ModLogsProcessRemoval(ulong guildId, ulong targetId, ModLogType remType, string source, string? logReason) { private void ModLogsProcessRemoval(ulong guildId, ulong targetId, ModLogType remType, string source, string? logReason) {
var entry = new ModLogEntry() { var entry = new ModLogEntry() {
GuildId = (long)guildId, GuildId = guildId,
UserId = (long)targetId, UserId = targetId,
LogType = remType, LogType = remType,
IssuedBy = source, IssuedBy = source,
Message = logReason Message = logReason

View file

@ -25,8 +25,8 @@ internal partial class CommonFunctionsService : Service {
return new TimeoutSetResult(ex, false, target); return new TimeoutSetResult(ex, false, target);
} }
var entry = new ModLogEntry() { var entry = new ModLogEntry() {
GuildId = (long)guild.Id, GuildId = guild.Id,
UserId = (long)target.Id, UserId = target.Id,
LogType = ModLogType.Timeout, LogType = ModLogType.Timeout,
IssuedBy = source, IssuedBy = source,
Message = $"Duration: {Math.Floor(duration.TotalMinutes)}min{(reason == null ? "." : " - " + reason)}" Message = $"Duration: {Math.Floor(duration.TotalMinutes)}min{(reason == null ? "." : " - " + reason)}"

View file

@ -28,7 +28,7 @@ class MessageCachingSubservice {
if (arg is SocketSystemMessage) return; if (arg is SocketSystemMessage) return;
using var db = new BotDatabaseContext(); using var db = new BotDatabaseContext();
CachedGuildMessage? cachedMsg = db.GuildMessageCache.Where(m => m.MessageId == (long)arg.Id).SingleOrDefault(); CachedGuildMessage? cachedMsg = db.GuildMessageCache.Where(m => m.MessageId == arg.Id).SingleOrDefault();
if (isUpdate) { if (isUpdate) {
// Alternative for Discord.Net's MessageUpdated handler: // Alternative for Discord.Net's MessageUpdated handler:
@ -40,10 +40,10 @@ class MessageCachingSubservice {
if (cachedMsg == null) { if (cachedMsg == null) {
cachedMsg = new() { cachedMsg = new() {
MessageId = (long)arg.Id, MessageId = arg.Id,
AuthorId = (long)arg.Author.Id, AuthorId = arg.Author.Id,
GuildId = (long)((SocketGuildUser)arg.Author).Guild.Id, GuildId = ((SocketGuildUser)arg.Author).Guild.Id,
ChannelId = (long)arg.Channel.Id, ChannelId = arg.Channel.Id,
AttachmentNames = arg.Attachments.Select(a => a.Filename).ToList(), AttachmentNames = arg.Attachments.Select(a => a.Filename).ToList(),
Content = arg.Content Content = arg.Content
}; };

View file

@ -1,5 +1,4 @@
#pragma warning disable CA1822 // "Mark members as static" - members should only be callable by code with access to this instance #pragma warning disable CA1822 // "Mark members as static" - members should only be callable by code with access to this instance
using Microsoft.EntityFrameworkCore;
using RegexBot.Common; using RegexBot.Common;
using RegexBot.Data; using RegexBot.Data;
@ -52,9 +51,9 @@ class UserCachingSubservice {
// IMPORTANT: Do NOT forget to save changes in database after calling this! // IMPORTANT: Do NOT forget to save changes in database after calling this!
private static void UpdateUser(SocketUser user, BotDatabaseContext db) { private static void UpdateUser(SocketUser user, BotDatabaseContext db) {
var uinfo = db.UserCache.Where(c => c.UserId == (long)user.Id).SingleOrDefault(); var uinfo = db.UserCache.Where(c => c.UserId == user.Id).SingleOrDefault();
if (uinfo == null) { if (uinfo == null) {
uinfo = new() { UserId = (long)user.Id }; uinfo = new() { UserId = user.Id };
db.UserCache.Add(uinfo); db.UserCache.Add(uinfo);
} }
@ -65,9 +64,9 @@ class UserCachingSubservice {
} }
private static void UpdateGuildUser(SocketGuildUser user, BotDatabaseContext db) { private static void UpdateGuildUser(SocketGuildUser user, BotDatabaseContext db) {
var guinfo = db.GuildUserCache.Where(c => c.GuildId == (long)user.Guild.Id && c.UserId == (long)user.Id).SingleOrDefault(); var guinfo = db.GuildUserCache.Where(c => c.GuildId == user.Guild.Id && c.UserId == user.Id).SingleOrDefault();
if (guinfo == null) { if (guinfo == null) {
guinfo = new() { GuildId = (long)user.Guild.Id, UserId = (long)user.Id }; guinfo = new() { GuildId = user.Guild.Id, UserId = user.Id };
db.GuildUserCache.Add(guinfo); db.GuildUserCache.Add(guinfo);
} }
@ -83,7 +82,7 @@ class UserCachingSubservice {
var query = db.UserCache.AsQueryable(); var query = db.UserCache.AsQueryable();
if (sID.HasValue) if (sID.HasValue)
query = query.Where(c => c.UserId == (long)sID.Value); query = query.Where(c => c.UserId == sID.Value);
if (nameSearch != null) { if (nameSearch != null) {
query = query.Where(c => c.Username.ToLower() == nameSearch.Value.name.ToLower()); query = query.Where(c => c.Username.ToLower() == nameSearch.Value.name.ToLower());
if (nameSearch.Value.disc != null) query = query.Where(c => c.Discriminator == nameSearch.Value.disc); if (nameSearch.Value.disc != null) query = query.Where(c => c.Discriminator == nameSearch.Value.disc);
@ -112,9 +111,9 @@ class UserCachingSubservice {
internal CachedGuildUser? DoGuildUserQuery(ulong guildId, string search) { internal CachedGuildUser? DoGuildUserQuery(ulong guildId, string search) {
static CachedGuildUser? innerQuery(ulong guildId, ulong? sID, (string name, string? disc)? nameSearch) { static CachedGuildUser? innerQuery(ulong guildId, ulong? sID, (string name, string? disc)? nameSearch) {
var db = new BotDatabaseContext(); var db = new BotDatabaseContext();
var query = db.GuildUserCache.Include(gu => gu.User).Where(c => c.GuildId == (long)guildId); var query = db.GuildUserCache.Where(c => c.GuildId == guildId);
if (sID.HasValue) if (sID.HasValue)
query = query.Where(c => c.UserId == (long)sID.Value); query = query.Where(c => c.UserId == sID.Value);
if (nameSearch != null) { if (nameSearch != null) {
query = query.Where(c => (c.Nickname != null && c.Nickname.ToLower() == nameSearch.Value.name.ToLower()) || query = query.Where(c => (c.Nickname != null && c.Nickname.ToLower() == nameSearch.Value.name.ToLower()) ||
c.User.Username.ToLower() == nameSearch.Value.name.ToLower()); c.User.Username.ToLower() == nameSearch.Value.name.ToLower());