From a6e8ba1a6576c6f9b64e8f0f58798d40dce8c640 Mon Sep 17 00:00:00 2001 From: Artemy <109195690+stalcker2288969@users.noreply.github.com> Date: Sun, 22 Jun 2025 11:45:25 +0700 Subject: [PATCH] Update models Messages --- .../Validators/MessageValidatorTests.cs | 16 +- Govor.API/Services/LocalStorageService.cs | 2 +- .../Validators/MessageValidator.cs | 4 +- Govor.Core/Models/Message.cs | 4 + Govor.Core/Models/MessageView.cs | 9 + .../MediaAttachmentsConfiguration.cs | 26 ++ .../MessageReactionConfiguration.cs | 24 ++ .../MessageViewConfiguration.cs | 18 + .../Configurations/MessagesConfiguration.cs | 36 ++ Govor.Data/GovorDbContext.cs | 18 +- .../20250622044435_MessagesInit.Designer.cs | 310 ++++++++++++++++++ .../Migrations/20250622044435_MessagesInit.cs | 152 +++++++++ .../Migrations/GovorDbContextModelSnapshot.cs | 181 ++++++++++ 13 files changed, 794 insertions(+), 6 deletions(-) create mode 100644 Govor.Core/Models/MessageView.cs create mode 100644 Govor.Data/Configurations/MediaAttachmentsConfiguration.cs create mode 100644 Govor.Data/Configurations/MessageReactionConfiguration.cs create mode 100644 Govor.Data/Configurations/MessageViewConfiguration.cs create mode 100644 Govor.Data/Configurations/MessagesConfiguration.cs create mode 100644 Govor.Data/Migrations/20250622044435_MessagesInit.Designer.cs create mode 100644 Govor.Data/Migrations/20250622044435_MessagesInit.cs diff --git a/Govor.API.Tests/UnitTests/Infrastructure/Validators/MessageValidatorTests.cs b/Govor.API.Tests/UnitTests/Infrastructure/Validators/MessageValidatorTests.cs index b075361..c171087 100644 --- a/Govor.API.Tests/UnitTests/Infrastructure/Validators/MessageValidatorTests.cs +++ b/Govor.API.Tests/UnitTests/Infrastructure/Validators/MessageValidatorTests.cs @@ -73,14 +73,26 @@ public class MessageValidatorTests Assert.ThrowsAsync>(async () => _messageValidator.Validate(message)); Assert.That(_messageValidator.TryValidate(message), Is.False); } - + [Test] - public void Given_EmptyEncryptedMessage_When_Validate_Should_Throw_InvalidObjectException() + public void Given_EmptyEncryptedMessageAndNotEmptyMedia_When_Validate_Should_Throw_InvalidObjectException() { // Arrange Message message = _fixture.Create(); message.EncryptedContent = string.Empty; + Assert.DoesNotThrowAsync(async () => _messageValidator.Validate(message)); + Assert.That(_messageValidator.TryValidate(message), Is.True); + } + + [Test] + public void Given_EmptyEncryptedMessageAndEmptyMedia_When_Validate_Should_Throw_InvalidObjectException() + { + // Arrange + Message message = _fixture.Create(); + message.EncryptedContent = string.Empty; + message.MediaAttachments = default; + Assert.ThrowsAsync>(async () => _messageValidator.Validate(message)); Assert.That(_messageValidator.TryValidate(message), Is.False); } diff --git a/Govor.API/Services/LocalStorageService.cs b/Govor.API/Services/LocalStorageService.cs index cc6439c..21d4f85 100644 --- a/Govor.API/Services/LocalStorageService.cs +++ b/Govor.API/Services/LocalStorageService.cs @@ -38,7 +38,7 @@ public class LocalStorageService : IStorageService public async Task LoadAsync(string url) { - var filePath = Path.Combine(_storagePath, url); // url уже включает yyyy/MM + var filePath = Path.Combine(_storagePath, url); if (!File.Exists(filePath)) throw new FileNotFoundException("File not found.", filePath); diff --git a/Govor.Core/Infrastructure/Validators/MessageValidator.cs b/Govor.Core/Infrastructure/Validators/MessageValidator.cs index d012291..fbe5530 100644 --- a/Govor.Core/Infrastructure/Validators/MessageValidator.cs +++ b/Govor.Core/Infrastructure/Validators/MessageValidator.cs @@ -16,8 +16,8 @@ public class MessageValidator : IObjectValidator throw new ArgumentException("Sender ID cannot be empty", nameof(message.SenderId)); if (message.RecipientId == Guid.Empty) throw new ArgumentException("Recipient ID cannot be empty", nameof(message.RecipientId)); - if(string.IsNullOrWhiteSpace(message.EncryptedContent)) - throw new ArgumentException("Encrypted content cannot be empty", nameof(message.EncryptedContent)); + if(string.IsNullOrWhiteSpace(message.EncryptedContent) && (message.MediaAttachments is null || message.MediaAttachments.Count == 0)) + throw new ArgumentException("Encrypted content cannot be empty when media attachments are empty", nameof(message.EncryptedContent)); if(message.IsEdited && message.EditedAt == DateTime.MinValue) throw new ArgumentException("Edited at time cannot be empty", nameof(message.EditedAt)); if (message.SentAt == DateTime.MinValue) diff --git a/Govor.Core/Models/Message.cs b/Govor.Core/Models/Message.cs index 3436fcd..44ccb68 100644 --- a/Govor.Core/Models/Message.cs +++ b/Govor.Core/Models/Message.cs @@ -12,6 +12,10 @@ public class Message public DateTime? EditedAt { get; set; } public List Reactions { get; set; } = new List(); public List MediaAttachments { get; set; } = new List(); + public List MessageViews { get; set; } = new List(); + + public Guid? ReplyToMessageId { get; set; } + public Message? ReplyToMessage { get; set; } // navigation } public enum RecipientType diff --git a/Govor.Core/Models/MessageView.cs b/Govor.Core/Models/MessageView.cs new file mode 100644 index 0000000..8f09035 --- /dev/null +++ b/Govor.Core/Models/MessageView.cs @@ -0,0 +1,9 @@ +namespace Govor.Core.Models; + +public class MessageView +{ + public Guid Id { get; set; } + public Guid MessageId { get; set; } + public Guid UserId { get; set; } + public DateTime ViewedAt { get; set; } +} diff --git a/Govor.Data/Configurations/MediaAttachmentsConfiguration.cs b/Govor.Data/Configurations/MediaAttachmentsConfiguration.cs new file mode 100644 index 0000000..d9c6bc4 --- /dev/null +++ b/Govor.Data/Configurations/MediaAttachmentsConfiguration.cs @@ -0,0 +1,26 @@ +using Govor.Core.Models; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace Govor.Data.Configurations; + +public class MediaAttachmentsConfiguration : IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder builder) + { + builder.HasKey(ma => ma.Id); + + builder.Property(ma => ma.FilePath) + .IsRequired(); + + builder.Property(ma => ma.MimeType) + .IsRequired(); + + builder.Property(ma => ma.EncryptedKey) + .HasMaxLength(512); // зависит от шифра + + builder.Property(ma => ma.Type) + .HasConversion() // enum as string (e.g., "Image") + .IsRequired(); + } +} \ No newline at end of file diff --git a/Govor.Data/Configurations/MessageReactionConfiguration.cs b/Govor.Data/Configurations/MessageReactionConfiguration.cs new file mode 100644 index 0000000..90080c3 --- /dev/null +++ b/Govor.Data/Configurations/MessageReactionConfiguration.cs @@ -0,0 +1,24 @@ +using Govor.Core.Models; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace Govor.Data.Configurations; + +public class MessageReactionConfiguration : IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder builder) + { + builder.HasKey(r => r.Id); + + builder.HasIndex(r => new { r.MessageId, r.UserId }).IsUnique(); // Одна реакция от одного юзера + + builder.Property(r => r.ReactionCode) + .IsRequired() + .HasMaxLength(64); // можно увеличить для кастомных эмодзи + + builder.HasOne(r => r.User) + .WithMany() + .HasForeignKey(r => r.UserId) + .OnDelete(DeleteBehavior.Cascade); + } +} \ No newline at end of file diff --git a/Govor.Data/Configurations/MessageViewConfiguration.cs b/Govor.Data/Configurations/MessageViewConfiguration.cs new file mode 100644 index 0000000..7758abc --- /dev/null +++ b/Govor.Data/Configurations/MessageViewConfiguration.cs @@ -0,0 +1,18 @@ +using Govor.Core.Models; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace Govor.Data.Configurations; + +public class MessageViewConfiguration : IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder builder) + { + builder.HasKey(mv => mv.Id); + + builder.HasIndex(mv => new { mv.MessageId, mv.UserId }).IsUnique(); + + builder.Property(mv => mv.ViewedAt) + .IsRequired(); + } +} \ No newline at end of file diff --git a/Govor.Data/Configurations/MessagesConfiguration.cs b/Govor.Data/Configurations/MessagesConfiguration.cs new file mode 100644 index 0000000..39f8adb --- /dev/null +++ b/Govor.Data/Configurations/MessagesConfiguration.cs @@ -0,0 +1,36 @@ +using Govor.Core.Models; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace Govor.Data.Configurations; + +public class MessagesConfiguration : IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder builder) + { + builder.HasKey(m => m.Id); + + builder.HasMany(m => m.Reactions) + .WithOne(r => r.Message) + .HasForeignKey(r => r.MessageId) + .OnDelete(DeleteBehavior.Cascade); + + builder.HasMany(m => m.MediaAttachments) + .WithOne(ma => ma.Message) + .HasForeignKey(ma => ma.MessageId) + .OnDelete(DeleteBehavior.Cascade); + + builder.HasMany(m => m.MessageViews) + .WithOne() + .HasForeignKey(mv => mv.MessageId) + .OnDelete(DeleteBehavior.Cascade); + + builder.HasOne(m => m.ReplyToMessage) + .WithMany() + .HasForeignKey(m => m.ReplyToMessageId) + .OnDelete(DeleteBehavior.Restrict); + + builder.Property(m => m.EncryptedContent) + .IsRequired(); + } +} \ No newline at end of file diff --git a/Govor.Data/GovorDbContext.cs b/Govor.Data/GovorDbContext.cs index 2e2f1ec..e8fec37 100644 --- a/Govor.Data/GovorDbContext.cs +++ b/Govor.Data/GovorDbContext.cs @@ -1,5 +1,6 @@ using System.Text.RegularExpressions; using Govor.Core.Models; +using Govor.Data.Configurations; using Microsoft.EntityFrameworkCore; namespace Govor.Data; @@ -7,8 +8,23 @@ namespace Govor.Data; public class GovorDbContext(DbContextOptions options) : DbContext(options) { public virtual DbSet Users { get; set; } - public virtual DbSet ChatGroups { get; set; } + public virtual DbSet Messages { get; set; } + public virtual DbSet MessageViews { get; set; } + public virtual DbSet MessageReactions { get; set; } + public virtual DbSet MediaAttachments { get; set; } + + public virtual DbSet ChatGroups { get; set; } public virtual DbSet GroupMemberships { get; set; } public virtual DbSet GroupAdmins { get; set; } + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.ApplyConfiguration(new MessagesConfiguration()); + modelBuilder.ApplyConfiguration(new MessageReactionConfiguration()); + modelBuilder.ApplyConfiguration(new MediaAttachmentsConfiguration()); + modelBuilder.ApplyConfiguration(new MessageViewConfiguration()); + + base.OnModelCreating(modelBuilder); + } } \ No newline at end of file diff --git a/Govor.Data/Migrations/20250622044435_MessagesInit.Designer.cs b/Govor.Data/Migrations/20250622044435_MessagesInit.Designer.cs new file mode 100644 index 0000000..2fdacdc --- /dev/null +++ b/Govor.Data/Migrations/20250622044435_MessagesInit.Designer.cs @@ -0,0 +1,310 @@ +// +using System; +using System.Collections.Generic; +using Govor.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 Govor.Data.Migrations +{ + [DbContext(typeof(GovorDbContext))] + [Migration("20250622044435_MessagesInit")] + partial class MessagesInit + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "9.0.6") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("Govor.Core.Models.ChatGroup", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.PrimitiveCollection>("Admins") + .IsRequired() + .HasColumnType("uuid[]"); + + b.PrimitiveCollection>("InviteCode") + .IsRequired() + .HasColumnType("text[]"); + + b.Property("IsChannel") + .HasColumnType("boolean"); + + b.Property("IsPrivate") + .HasColumnType("boolean"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("ChatGroups"); + }); + + modelBuilder.Entity("Govor.Core.Models.GroupAdmins", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("GroupId") + .HasColumnType("uuid"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.ToTable("GroupAdmins"); + }); + + modelBuilder.Entity("Govor.Core.Models.GroupMembership", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("GroupId") + .HasColumnType("uuid"); + + b.Property("IsBanned") + .HasColumnType("boolean"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.ToTable("GroupMemberships"); + }); + + modelBuilder.Entity("Govor.Core.Models.MediaAttachments", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("EncryptedKey") + .HasMaxLength(512) + .HasColumnType("character varying(512)"); + + b.Property("FilePath") + .IsRequired() + .HasColumnType("text"); + + b.Property("MessageId") + .HasColumnType("uuid"); + + b.Property("MimeType") + .IsRequired() + .HasColumnType("text"); + + b.Property("Type") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("MessageId"); + + b.ToTable("MediaAttachments"); + }); + + modelBuilder.Entity("Govor.Core.Models.Message", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("EditedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("EncryptedContent") + .IsRequired() + .HasColumnType("text"); + + b.Property("IsEdited") + .HasColumnType("boolean"); + + b.Property("RecipientId") + .HasColumnType("uuid"); + + b.Property("RecipientType") + .HasColumnType("integer"); + + b.Property("ReplyToMessageId") + .HasColumnType("uuid"); + + b.Property("SenderId") + .HasColumnType("uuid"); + + b.Property("SentAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("ReplyToMessageId"); + + b.ToTable("Messages"); + }); + + modelBuilder.Entity("Govor.Core.Models.MessageReaction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("MessageId") + .HasColumnType("uuid"); + + b.Property("ReactedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ReactionCode") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.HasIndex("MessageId", "UserId") + .IsUnique(); + + b.ToTable("MessageReactions"); + }); + + modelBuilder.Entity("Govor.Core.Models.MessageView", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("MessageId") + .HasColumnType("uuid"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.Property("ViewedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("MessageId", "UserId") + .IsUnique(); + + b.ToTable("MessageViews"); + }); + + modelBuilder.Entity("Govor.Core.Models.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedOn") + .HasColumnType("date"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("IconId") + .HasColumnType("uuid"); + + b.Property("PasswordHash") + .IsRequired() + .HasColumnType("text"); + + b.Property("Username") + .IsRequired() + .HasColumnType("text"); + + b.Property("WasOnline") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("Govor.Core.Models.MediaAttachments", b => + { + b.HasOne("Govor.Core.Models.Message", "Message") + .WithMany("MediaAttachments") + .HasForeignKey("MessageId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Message"); + }); + + modelBuilder.Entity("Govor.Core.Models.Message", b => + { + b.HasOne("Govor.Core.Models.Message", "ReplyToMessage") + .WithMany() + .HasForeignKey("ReplyToMessageId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("ReplyToMessage"); + }); + + modelBuilder.Entity("Govor.Core.Models.MessageReaction", b => + { + b.HasOne("Govor.Core.Models.Message", "Message") + .WithMany("Reactions") + .HasForeignKey("MessageId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Govor.Core.Models.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Message"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Govor.Core.Models.MessageView", b => + { + b.HasOne("Govor.Core.Models.Message", null) + .WithMany("MessageViews") + .HasForeignKey("MessageId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Govor.Core.Models.Message", b => + { + b.Navigation("MediaAttachments"); + + b.Navigation("MessageViews"); + + b.Navigation("Reactions"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Govor.Data/Migrations/20250622044435_MessagesInit.cs b/Govor.Data/Migrations/20250622044435_MessagesInit.cs new file mode 100644 index 0000000..49ea51b --- /dev/null +++ b/Govor.Data/Migrations/20250622044435_MessagesInit.cs @@ -0,0 +1,152 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Govor.Data.Migrations +{ + /// + public partial class MessagesInit : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "Messages", + columns: table => new + { + Id = table.Column(type: "uuid", nullable: false), + SenderId = table.Column(type: "uuid", nullable: false), + RecipientId = table.Column(type: "uuid", nullable: false), + RecipientType = table.Column(type: "integer", nullable: false), + EncryptedContent = table.Column(type: "text", nullable: false), + SentAt = table.Column(type: "timestamp with time zone", nullable: false), + IsEdited = table.Column(type: "boolean", nullable: false), + EditedAt = table.Column(type: "timestamp with time zone", nullable: true), + ReplyToMessageId = table.Column(type: "uuid", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Messages", x => x.Id); + table.ForeignKey( + name: "FK_Messages_Messages_ReplyToMessageId", + column: x => x.ReplyToMessageId, + principalTable: "Messages", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + }); + + migrationBuilder.CreateTable( + name: "MediaAttachments", + columns: table => new + { + Id = table.Column(type: "uuid", nullable: false), + MessageId = table.Column(type: "uuid", nullable: false), + Type = table.Column(type: "text", nullable: false), + FilePath = table.Column(type: "text", nullable: false), + MimeType = table.Column(type: "text", nullable: false), + EncryptedKey = table.Column(type: "character varying(512)", maxLength: 512, nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_MediaAttachments", x => x.Id); + table.ForeignKey( + name: "FK_MediaAttachments_Messages_MessageId", + column: x => x.MessageId, + principalTable: "Messages", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "MessageReactions", + columns: table => new + { + Id = table.Column(type: "uuid", nullable: false), + MessageId = table.Column(type: "uuid", nullable: false), + UserId = table.Column(type: "uuid", nullable: false), + ReactionCode = table.Column(type: "character varying(64)", maxLength: 64, nullable: false), + ReactedAt = table.Column(type: "timestamp with time zone", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_MessageReactions", x => x.Id); + table.ForeignKey( + name: "FK_MessageReactions_Messages_MessageId", + column: x => x.MessageId, + principalTable: "Messages", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_MessageReactions_Users_UserId", + column: x => x.UserId, + principalTable: "Users", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "MessageViews", + columns: table => new + { + Id = table.Column(type: "uuid", nullable: false), + MessageId = table.Column(type: "uuid", nullable: false), + UserId = table.Column(type: "uuid", nullable: false), + ViewedAt = table.Column(type: "timestamp with time zone", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_MessageViews", x => x.Id); + table.ForeignKey( + name: "FK_MessageViews_Messages_MessageId", + column: x => x.MessageId, + principalTable: "Messages", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_MediaAttachments_MessageId", + table: "MediaAttachments", + column: "MessageId"); + + migrationBuilder.CreateIndex( + name: "IX_MessageReactions_MessageId_UserId", + table: "MessageReactions", + columns: new[] { "MessageId", "UserId" }, + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_MessageReactions_UserId", + table: "MessageReactions", + column: "UserId"); + + migrationBuilder.CreateIndex( + name: "IX_Messages_ReplyToMessageId", + table: "Messages", + column: "ReplyToMessageId"); + + migrationBuilder.CreateIndex( + name: "IX_MessageViews_MessageId_UserId", + table: "MessageViews", + columns: new[] { "MessageId", "UserId" }, + unique: true); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "MediaAttachments"); + + migrationBuilder.DropTable( + name: "MessageReactions"); + + migrationBuilder.DropTable( + name: "MessageViews"); + + migrationBuilder.DropTable( + name: "Messages"); + } + } +} diff --git a/Govor.Data/Migrations/GovorDbContextModelSnapshot.cs b/Govor.Data/Migrations/GovorDbContextModelSnapshot.cs index a49aac5..3cd857e 100644 --- a/Govor.Data/Migrations/GovorDbContextModelSnapshot.cs +++ b/Govor.Data/Migrations/GovorDbContextModelSnapshot.cs @@ -89,6 +89,129 @@ namespace Govor.Data.Migrations b.ToTable("GroupMemberships"); }); + modelBuilder.Entity("Govor.Core.Models.MediaAttachments", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("EncryptedKey") + .HasMaxLength(512) + .HasColumnType("character varying(512)"); + + b.Property("FilePath") + .IsRequired() + .HasColumnType("text"); + + b.Property("MessageId") + .HasColumnType("uuid"); + + b.Property("MimeType") + .IsRequired() + .HasColumnType("text"); + + b.Property("Type") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("MessageId"); + + b.ToTable("MediaAttachments"); + }); + + modelBuilder.Entity("Govor.Core.Models.Message", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("EditedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("EncryptedContent") + .IsRequired() + .HasColumnType("text"); + + b.Property("IsEdited") + .HasColumnType("boolean"); + + b.Property("RecipientId") + .HasColumnType("uuid"); + + b.Property("RecipientType") + .HasColumnType("integer"); + + b.Property("ReplyToMessageId") + .HasColumnType("uuid"); + + b.Property("SenderId") + .HasColumnType("uuid"); + + b.Property("SentAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("ReplyToMessageId"); + + b.ToTable("Messages"); + }); + + modelBuilder.Entity("Govor.Core.Models.MessageReaction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("MessageId") + .HasColumnType("uuid"); + + b.Property("ReactedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ReactionCode") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.HasIndex("MessageId", "UserId") + .IsUnique(); + + b.ToTable("MessageReactions"); + }); + + modelBuilder.Entity("Govor.Core.Models.MessageView", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("MessageId") + .HasColumnType("uuid"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.Property("ViewedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("MessageId", "UserId") + .IsUnique(); + + b.ToTable("MessageViews"); + }); + modelBuilder.Entity("Govor.Core.Models.User", b => { b.Property("Id") @@ -120,6 +243,64 @@ namespace Govor.Data.Migrations b.ToTable("Users"); }); + + modelBuilder.Entity("Govor.Core.Models.MediaAttachments", b => + { + b.HasOne("Govor.Core.Models.Message", "Message") + .WithMany("MediaAttachments") + .HasForeignKey("MessageId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Message"); + }); + + modelBuilder.Entity("Govor.Core.Models.Message", b => + { + b.HasOne("Govor.Core.Models.Message", "ReplyToMessage") + .WithMany() + .HasForeignKey("ReplyToMessageId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("ReplyToMessage"); + }); + + modelBuilder.Entity("Govor.Core.Models.MessageReaction", b => + { + b.HasOne("Govor.Core.Models.Message", "Message") + .WithMany("Reactions") + .HasForeignKey("MessageId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Govor.Core.Models.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Message"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Govor.Core.Models.MessageView", b => + { + b.HasOne("Govor.Core.Models.Message", null) + .WithMany("MessageViews") + .HasForeignKey("MessageId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Govor.Core.Models.Message", b => + { + b.Navigation("MediaAttachments"); + + b.Navigation("MessageViews"); + + b.Navigation("Reactions"); + }); #pragma warning restore 612, 618 } }