From 03fdb56190532f2d2fa4998a1e780f54c31b1d22 Mon Sep 17 00:00:00 2001 From: adam Date: Mon, 3 Feb 2025 20:41:11 -0500 Subject: [PATCH] ok no i take it back, we do need a rememberer? send 2 messages - it'll pull out a channel and complain it's already been attached. --- Migrations/20250204004906_cascade.Designer.cs | 271 ++++++++++++++++++ Migrations/20250204004906_cascade.cs | 133 +++++++++ Migrations/ChattingContextModelSnapshot.cs | 15 +- Models/Channel.cs | 4 + Models/Message.cs | 2 + Models/User.cs | 2 + .../DiscordInterface/DiscordInterface.cs | 17 +- appsettings.json | 3 +- 8 files changed, 435 insertions(+), 12 deletions(-) create mode 100644 Migrations/20250204004906_cascade.Designer.cs create mode 100644 Migrations/20250204004906_cascade.cs diff --git a/Migrations/20250204004906_cascade.Designer.cs b/Migrations/20250204004906_cascade.Designer.cs new file mode 100644 index 0000000..b1dc86b --- /dev/null +++ b/Migrations/20250204004906_cascade.Designer.cs @@ -0,0 +1,271 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; +using vassago.Models; + +#nullable disable + +namespace vassago.Migrations +{ + [DbContext(typeof(ChattingContext))] + [Migration("20250204004906_cascade")] + partial class cascade + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "7.0.5") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("vassago.Models.Account", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("DisplayName") + .HasColumnType("text"); + + b.Property("ExternalId") + .HasColumnType("text"); + + b.Property("IsBot") + .HasColumnType("boolean"); + + b.Property("IsUserId") + .HasColumnType("uuid"); + + b.Property("Protocol") + .HasColumnType("text"); + + b.Property("SeenInChannelId") + .HasColumnType("uuid"); + + b.Property("Username") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("IsUserId"); + + b.HasIndex("SeenInChannelId"); + + b.ToTable("Accounts"); + }); + + modelBuilder.Entity("vassago.Models.Attachment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Content") + .HasColumnType("bytea"); + + b.Property("ContentType") + .HasColumnType("text"); + + b.Property("Description") + .HasColumnType("text"); + + b.Property("ExternalId") + .HasColumnType("numeric(20,0)"); + + b.Property("Filename") + .HasColumnType("text"); + + b.Property("MessageId") + .HasColumnType("uuid"); + + b.Property("Size") + .HasColumnType("integer"); + + b.Property("Source") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("MessageId"); + + b.ToTable("Attachments"); + }); + + modelBuilder.Entity("vassago.Models.Channel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ChannelType") + .HasColumnType("integer"); + + b.Property("DisplayName") + .HasColumnType("text"); + + b.Property("ExternalId") + .HasColumnType("text"); + + b.Property("LewdnessFilterLevel") + .HasColumnType("integer"); + + b.Property("LinksAllowed") + .HasColumnType("boolean"); + + b.Property("MaxAttachmentBytes") + .HasColumnType("numeric(20,0)"); + + b.Property("MaxTextChars") + .HasColumnType("bigint"); + + b.Property("MeannessFilterLevel") + .HasColumnType("integer"); + + b.Property("ParentChannelId") + .HasColumnType("uuid"); + + b.Property("Protocol") + .HasColumnType("text"); + + b.Property("ReactionsPossible") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.HasIndex("ParentChannelId"); + + b.ToTable("Channels"); + }); + + modelBuilder.Entity("vassago.Models.Message", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ActedOn") + .HasColumnType("boolean"); + + b.Property("AuthorId") + .HasColumnType("uuid"); + + b.Property("ChannelId") + .HasColumnType("uuid"); + + b.Property("Content") + .HasColumnType("text"); + + b.Property("ExternalId") + .HasColumnType("text"); + + b.Property("MentionsMe") + .HasColumnType("boolean"); + + b.Property("Protocol") + .HasColumnType("text"); + + b.Property("Timestamp") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("AuthorId"); + + b.HasIndex("ChannelId"); + + b.ToTable("Messages"); + }); + + modelBuilder.Entity("vassago.Models.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("vassago.Models.Account", b => + { + b.HasOne("vassago.Models.User", "IsUser") + .WithMany("Accounts") + .HasForeignKey("IsUserId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("vassago.Models.Channel", "SeenInChannel") + .WithMany("Users") + .HasForeignKey("SeenInChannelId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("IsUser"); + + b.Navigation("SeenInChannel"); + }); + + modelBuilder.Entity("vassago.Models.Attachment", b => + { + b.HasOne("vassago.Models.Message", "Message") + .WithMany("Attachments") + .HasForeignKey("MessageId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("Message"); + }); + + modelBuilder.Entity("vassago.Models.Channel", b => + { + b.HasOne("vassago.Models.Channel", "ParentChannel") + .WithMany("SubChannels") + .HasForeignKey("ParentChannelId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("ParentChannel"); + }); + + modelBuilder.Entity("vassago.Models.Message", b => + { + b.HasOne("vassago.Models.Account", "Author") + .WithMany() + .HasForeignKey("AuthorId"); + + b.HasOne("vassago.Models.Channel", "Channel") + .WithMany("Messages") + .HasForeignKey("ChannelId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("Author"); + + b.Navigation("Channel"); + }); + + modelBuilder.Entity("vassago.Models.Channel", b => + { + b.Navigation("Messages"); + + b.Navigation("SubChannels"); + + b.Navigation("Users"); + }); + + modelBuilder.Entity("vassago.Models.Message", b => + { + b.Navigation("Attachments"); + }); + + modelBuilder.Entity("vassago.Models.User", b => + { + b.Navigation("Accounts"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Migrations/20250204004906_cascade.cs b/Migrations/20250204004906_cascade.cs new file mode 100644 index 0000000..bafb6d6 --- /dev/null +++ b/Migrations/20250204004906_cascade.cs @@ -0,0 +1,133 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace vassago.Migrations +{ + /// + public partial class cascade : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_Accounts_Channels_SeenInChannelId", + table: "Accounts"); + + migrationBuilder.DropForeignKey( + name: "FK_Accounts_Users_IsUserId", + table: "Accounts"); + + migrationBuilder.DropForeignKey( + name: "FK_Attachments_Messages_MessageId", + table: "Attachments"); + + migrationBuilder.DropForeignKey( + name: "FK_Channels_Channels_ParentChannelId", + table: "Channels"); + + migrationBuilder.DropForeignKey( + name: "FK_Messages_Channels_ChannelId", + table: "Messages"); + + migrationBuilder.AddForeignKey( + name: "FK_Accounts_Channels_SeenInChannelId", + table: "Accounts", + column: "SeenInChannelId", + principalTable: "Channels", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "FK_Accounts_Users_IsUserId", + table: "Accounts", + column: "IsUserId", + principalTable: "Users", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "FK_Attachments_Messages_MessageId", + table: "Attachments", + column: "MessageId", + principalTable: "Messages", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "FK_Channels_Channels_ParentChannelId", + table: "Channels", + column: "ParentChannelId", + principalTable: "Channels", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "FK_Messages_Channels_ChannelId", + table: "Messages", + column: "ChannelId", + principalTable: "Channels", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_Accounts_Channels_SeenInChannelId", + table: "Accounts"); + + migrationBuilder.DropForeignKey( + name: "FK_Accounts_Users_IsUserId", + table: "Accounts"); + + migrationBuilder.DropForeignKey( + name: "FK_Attachments_Messages_MessageId", + table: "Attachments"); + + migrationBuilder.DropForeignKey( + name: "FK_Channels_Channels_ParentChannelId", + table: "Channels"); + + migrationBuilder.DropForeignKey( + name: "FK_Messages_Channels_ChannelId", + table: "Messages"); + + migrationBuilder.AddForeignKey( + name: "FK_Accounts_Channels_SeenInChannelId", + table: "Accounts", + column: "SeenInChannelId", + principalTable: "Channels", + principalColumn: "Id"); + + migrationBuilder.AddForeignKey( + name: "FK_Accounts_Users_IsUserId", + table: "Accounts", + column: "IsUserId", + principalTable: "Users", + principalColumn: "Id"); + + migrationBuilder.AddForeignKey( + name: "FK_Attachments_Messages_MessageId", + table: "Attachments", + column: "MessageId", + principalTable: "Messages", + principalColumn: "Id"); + + migrationBuilder.AddForeignKey( + name: "FK_Channels_Channels_ParentChannelId", + table: "Channels", + column: "ParentChannelId", + principalTable: "Channels", + principalColumn: "Id"); + + migrationBuilder.AddForeignKey( + name: "FK_Messages_Channels_ChannelId", + table: "Messages", + column: "ChannelId", + principalTable: "Channels", + principalColumn: "Id"); + } + } +} diff --git a/Migrations/ChattingContextModelSnapshot.cs b/Migrations/ChattingContextModelSnapshot.cs index cf8fd25..06ae3d3 100644 --- a/Migrations/ChattingContextModelSnapshot.cs +++ b/Migrations/ChattingContextModelSnapshot.cs @@ -195,11 +195,13 @@ namespace vassago.Migrations { b.HasOne("vassago.Models.User", "IsUser") .WithMany("Accounts") - .HasForeignKey("IsUserId"); + .HasForeignKey("IsUserId") + .OnDelete(DeleteBehavior.Cascade); b.HasOne("vassago.Models.Channel", "SeenInChannel") .WithMany("Users") - .HasForeignKey("SeenInChannelId"); + .HasForeignKey("SeenInChannelId") + .OnDelete(DeleteBehavior.Cascade); b.Navigation("IsUser"); @@ -210,7 +212,8 @@ namespace vassago.Migrations { b.HasOne("vassago.Models.Message", "Message") .WithMany("Attachments") - .HasForeignKey("MessageId"); + .HasForeignKey("MessageId") + .OnDelete(DeleteBehavior.Cascade); b.Navigation("Message"); }); @@ -219,7 +222,8 @@ namespace vassago.Migrations { b.HasOne("vassago.Models.Channel", "ParentChannel") .WithMany("SubChannels") - .HasForeignKey("ParentChannelId"); + .HasForeignKey("ParentChannelId") + .OnDelete(DeleteBehavior.Cascade); b.Navigation("ParentChannel"); }); @@ -232,7 +236,8 @@ namespace vassago.Migrations b.HasOne("vassago.Models.Channel", "Channel") .WithMany("Messages") - .HasForeignKey("ChannelId"); + .HasForeignKey("ChannelId") + .OnDelete(DeleteBehavior.Cascade); b.Navigation("Author"); diff --git a/Models/Channel.cs b/Models/Channel.cs index 6eaea55..f9c820d 100644 --- a/Models/Channel.cs +++ b/Models/Channel.cs @@ -6,6 +6,7 @@ using System.ComponentModel.DataAnnotations.Schema; using System.Reflection; using System.Threading.Tasks; using Microsoft.AspNetCore.Components.Web; +using Microsoft.EntityFrameworkCore; using static vassago.Models.Enumerations; public class Channel @@ -14,10 +15,13 @@ public class Channel public Guid Id { get; set; } public string ExternalId { get; set; } public string DisplayName { get; set; } + [DeleteBehavior(DeleteBehavior.Cascade)] public List SubChannels { get; set; } public Channel ParentChannel { get; set; } public string Protocol { get; set; } + [DeleteBehavior(DeleteBehavior.Cascade)] public List Messages { get; set; } + [DeleteBehavior(DeleteBehavior.Cascade)] public List Users { get; set; } public ChannelType ChannelType {get; set; } diff --git a/Models/Message.cs b/Models/Message.cs index ebfa68f..03aca13 100644 --- a/Models/Message.cs +++ b/Models/Message.cs @@ -6,6 +6,7 @@ using System.ComponentModel.DataAnnotations.Schema; using System.Reflection; using System.Threading.Tasks; using Discord.WebSocket; +using Microsoft.EntityFrameworkCore; public class Message { @@ -17,6 +18,7 @@ public class Message public bool MentionsMe { get; set; } public DateTimeOffset Timestamp { get; set; } public bool ActedOn { get; set; } + [DeleteBehavior(DeleteBehavior.Cascade)] public List Attachments { get; set; } public Account Author { get; set; } public Channel Channel { get; set; } diff --git a/Models/User.cs b/Models/User.cs index f4abb9b..9184a4f 100644 --- a/Models/User.cs +++ b/Models/User.cs @@ -4,11 +4,13 @@ using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations.Schema; using System.Reflection; +using Microsoft.EntityFrameworkCore; public class User { [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public Guid Id { get; set; } + [DeleteBehavior(DeleteBehavior.Cascade)] public List Accounts { get; set; } //if I ever get lots and lots of tags, or some automatic way to register a feature's arbitrary tags, then I can move this off. diff --git a/ProtocolInterfaces/DiscordInterface/DiscordInterface.cs b/ProtocolInterfaces/DiscordInterface/DiscordInterface.cs index 805bbd7..4a9cacd 100644 --- a/ProtocolInterfaces/DiscordInterface/DiscordInterface.cs +++ b/ProtocolInterfaces/DiscordInterface/DiscordInterface.cs @@ -234,7 +234,7 @@ public class DiscordInterface m.Reply = (t) => { return dMessage.ReplyAsync(t); }; m.React = (e) => { return attemptReact(dMessage, e); }; - db.SaveChangesAsync(); + db.SaveChanges(); return m; } internal Channel UpsertChannel(IMessageChannel channel) @@ -255,7 +255,7 @@ public class DiscordInterface c.Protocol = PROTOCOL; if (channel is IGuildChannel) { - c.ParentChannel = UpsertChannel((channel as IGuildChannel).Guild); + c.ParentChannel = UpsertChannel((channel as IGuildChannel).Guild, db); c.ParentChannel.SubChannels.Add(c); } else if (channel is IPrivateChannel) @@ -277,19 +277,25 @@ public class DiscordInterface c.DisplayName = "DM: " + (channel as IPrivateChannel).Recipients?.FirstOrDefault(u => u.Id != client.CurrentUser.Id).Username; break; } - db.SaveChangesAsync(); + db.SaveChanges(); return c; } - internal Channel UpsertChannel(IGuild channel) + internal Channel UpsertChannel(IGuild channel, ChattingContext db = null) { - var db = new ChattingContext(); + db = db ?? new ChattingContext(); + Console.WriteLine($"upserting *guild*: {channel.Id}"); Channel c = db.Channels.FirstOrDefault(ci => ci.ExternalId == channel.Id.ToString() && ci.Protocol == PROTOCOL); if (c == null) { + Console.WriteLine($"don't have one already. Creating."); c = new Channel(); db.Channels.Add(c); Console.WriteLine($"upserting channel {channel.Name} from discord, have to create a new one in the DB"); } + else + { + Console.WriteLine($"found one."); + } c.DisplayName = channel.Name; c.ExternalId = channel.Id.ToString(); @@ -307,7 +313,6 @@ public class DiscordInterface } internal Account UpsertAccount(IUser user, Channel inChannel) { - var db = new ChattingContext(); var acc = db.Accounts.FirstOrDefault(ui => ui.ExternalId == user.Id.ToString() && ui.SeenInChannel.Id == inChannel.Id); if (acc == null) diff --git a/appsettings.json b/appsettings.json index f7a96cc..143a993 100644 --- a/appsettings.json +++ b/appsettings.json @@ -2,7 +2,8 @@ "Logging": { "LogLevel": { "Default": "Information", - "Microsoft.AspNetCore": "Warning" + "Microsoft.AspNetCore": "Warning", + "Microsoft.EntityFrameworkCore": "None" } }, "AllowedHosts": "*",