Adds PhotoAlbum, CreatorHome, AboutCreator.
This commit is contained in:
@@ -4,4 +4,5 @@ public static class SubDirectoryNames
|
||||
{
|
||||
public static string Profile = "profile";
|
||||
public static string Contents = "contents";
|
||||
public static string Albums = "albums";
|
||||
}
|
||||
|
||||
30
backend/src/Web/Features/Contents/Data/Album.cs
Normal file
30
backend/src/Web/Features/Contents/Data/Album.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Hutopy.Web.Features.Contents.Data;
|
||||
|
||||
public class Album
|
||||
{
|
||||
public Guid Id { get; init; }
|
||||
public Guid CreatedBy { get; init; }
|
||||
public DateTimeOffset CreatedAt { get; init; }
|
||||
public Guid? DeletedBy { get; set; }
|
||||
public DateTimeOffset? DeletedAt { get; set; }
|
||||
public bool IsDeleted { get; private set; } // private set → EF updates it
|
||||
[MaxLength(255)] public required string Title { get; set; }
|
||||
public IList<AlbumPhoto> Photos { get; set; } = new List<AlbumPhoto>();
|
||||
}
|
||||
|
||||
public class AlbumPhoto
|
||||
{
|
||||
public Guid Id { get; init; }
|
||||
public Guid CreatedBy { get; init; }
|
||||
public DateTimeOffset CreatedAt { get; init; }
|
||||
public Guid? DeletedBy { get; set; }
|
||||
public DateTimeOffset? DeletedAt { get; set; }
|
||||
public bool IsDeleted { get; private set; } // private set → EF updates it
|
||||
public Guid AlbumId { get; set; }
|
||||
public Album Album { get; init; } = null!;
|
||||
[MaxLength(2048)] public required string PhotoUrl { get; set; }
|
||||
[MaxLength(255)] public string? Caption { get; set; }
|
||||
public int Order { get; set; }
|
||||
}
|
||||
@@ -9,6 +9,8 @@ public class ContentDbContext(
|
||||
public DbSet<Content> Contents => Set<Content>();
|
||||
public DbSet<Creator> Creators => Set<Creator>();
|
||||
public DbSet<Slugs> Slugs => Set<Slugs>();
|
||||
public DbSet<Album> Albums => Set<Album>();
|
||||
public DbSet<AlbumPhoto> AlbumPhotos => Set<AlbumPhoto>();
|
||||
|
||||
protected override void OnModelCreating(
|
||||
ModelBuilder modelBuilder)
|
||||
@@ -62,16 +64,50 @@ public class ContentDbContext(
|
||||
|
||||
modelBuilder
|
||||
.Entity<Creator>()
|
||||
.OwnsOne<Images>(x => x.Images)
|
||||
.ToTable(nameof(Images));
|
||||
|
||||
modelBuilder
|
||||
.Entity<Creator>()
|
||||
.OwnsOne<PresentationInfos>(x => x.PresentationInfos)
|
||||
.ToTable(nameof(PresentationInfos));
|
||||
.OwnsOne<Presentation>(x => x.Presentation)
|
||||
.ToTable(nameof(Presentation));
|
||||
|
||||
modelBuilder
|
||||
.Entity<Creator>()
|
||||
.HasQueryFilter(c => !c.IsDeleted);
|
||||
|
||||
// Album configuration
|
||||
modelBuilder
|
||||
.Entity<Album>()
|
||||
.Property(c => c.CreatedAt)
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasDefaultValueSql("CURRENT_TIMESTAMP");
|
||||
|
||||
modelBuilder
|
||||
.Entity<Album>()
|
||||
.Property(c => c.IsDeleted)
|
||||
.HasComputedColumnSql("\"DeletedAt\" IS NOT NULL", stored: true);
|
||||
|
||||
modelBuilder
|
||||
.Entity<Album>()
|
||||
.HasQueryFilter(a => !a.IsDeleted);
|
||||
|
||||
// AlbumPhoto configuration
|
||||
modelBuilder
|
||||
.Entity<AlbumPhoto>()
|
||||
.Property(c => c.CreatedAt)
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasDefaultValueSql("CURRENT_TIMESTAMP");
|
||||
|
||||
modelBuilder
|
||||
.Entity<AlbumPhoto>()
|
||||
.Property(c => c.IsDeleted)
|
||||
.HasComputedColumnSql("\"DeletedAt\" IS NOT NULL", stored: true);
|
||||
|
||||
modelBuilder
|
||||
.Entity<AlbumPhoto>()
|
||||
.HasOne(ap => ap.Album)
|
||||
.WithMany(a => a.Photos)
|
||||
.HasForeignKey(ap => ap.AlbumId)
|
||||
.IsRequired();
|
||||
|
||||
modelBuilder
|
||||
.Entity<AlbumPhoto>()
|
||||
.HasQueryFilter(ap => !ap.IsDeleted);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ public class Creator
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
|
||||
public Guid CreatedBy { get; set; }
|
||||
public Guid CreatedBy { get; set; }
|
||||
public DateTimeOffset CreatedAt { get; init; }
|
||||
public Guid? DeletedBy { get; set; }
|
||||
public DateTimeOffset? DeletedAt { get; set; }
|
||||
@@ -16,14 +16,16 @@ public class Creator
|
||||
/// </summary>
|
||||
public bool IsDeleted { get; private set; } // private set → EF updates it
|
||||
|
||||
public bool AcceptDonation { get; set; }
|
||||
[MaxLength(2048)] public string? BannerUrl { get; set; }
|
||||
[MaxLength(2048)] public string? PortraitUrl { get; set; }
|
||||
public bool Verified { get; set; }
|
||||
[MaxLength(255)] public string Name { get; set; }
|
||||
[MaxLength(128)] public string Slug { get; set; }
|
||||
[MaxLength(255)] public string? Title { get; set; }
|
||||
|
||||
public bool AcceptDonation { get; set; }
|
||||
public Socials Socials { get; set; } = new();
|
||||
public Images Images { get; set; } = new();
|
||||
public PresentationInfos PresentationInfos { get; set; } = new();
|
||||
public Presentation Presentation { get; set; } = new();
|
||||
}
|
||||
|
||||
public class Socials
|
||||
@@ -38,29 +40,10 @@ public class Socials
|
||||
[MaxLength(2048)] public string? WebsiteUrl { get; set; }
|
||||
}
|
||||
|
||||
public class Images
|
||||
public class Presentation
|
||||
{
|
||||
[MaxLength(2048)] public string? Banner { get; set; }
|
||||
[MaxLength(2048)] public string? Logo { get; set; }
|
||||
}
|
||||
|
||||
public class PresentationInfos
|
||||
{
|
||||
[MaxLength(255)] public string PhoneNumber { get; set; } = string.Empty;
|
||||
[MaxLength(255)] public string Email { get; set; } = string.Empty;
|
||||
[MaxLength(2000)] public string Title { get; set; } = string.Empty;
|
||||
[MaxLength(2048)] public string MainImageUrl { get; set; } = string.Empty;
|
||||
[MaxLength(10000)] public string MainImageText { get; set; } = string.Empty;
|
||||
[MaxLength(10000)] public string MainVideoText { get; set; } = string.Empty;
|
||||
[MaxLength(2000)] public string ImagesSubtitle { get; set; } = string.Empty;
|
||||
[MaxLength(2048)] public string Image1Url { get; set; } = string.Empty;
|
||||
[MaxLength(2048)] public string Image2Url { get; set; } = string.Empty;
|
||||
[MaxLength(2048)] public string Image3Url { get; set; } = string.Empty;
|
||||
[MaxLength(2048)] public string Image4Url { get; set; } = string.Empty;
|
||||
[MaxLength(10000)] public string ImagesText { get; set; } = string.Empty;
|
||||
[MaxLength(2000)] public string VideoSubtitle { get; set; } = string.Empty;
|
||||
[MaxLength(2000)] public string VideoSubtitleMain { get; set; } = string.Empty;
|
||||
[MaxLength(2048)] public string VideoUrlMain { get; set; } = string.Empty;
|
||||
[MaxLength(2048)] public string VideoUrl { get; set; } = string.Empty;
|
||||
[MaxLength(10000)] public string VideoText { get; set; } = string.Empty;
|
||||
[MaxLength(2000)] public string Description { get; set; } = null!;
|
||||
[MaxLength(2048)] public string? VideoUrl { get; set; }
|
||||
[MaxLength(255)] public string? PhoneNumber { get; set; }
|
||||
[MaxLength(255)] public string? Email { get; set; }
|
||||
}
|
||||
|
||||
301
backend/src/Web/Features/Contents/Data/Migrations/20250423153323_AddPresentation.Designer.cs
generated
Normal file
301
backend/src/Web/Features/Contents/Data/Migrations/20250423153323_AddPresentation.Designer.cs
generated
Normal file
@@ -0,0 +1,301 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using Hutopy.Web.Features.Contents.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 Hutopy.Web.Features.Contents.Data.Migrations
|
||||
{
|
||||
[DbContext(typeof(ContentDbContext))]
|
||||
[Migration("20250423153323_AddPresentation")]
|
||||
partial class AddPresentation
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasDefaultSchema("Content")
|
||||
.HasAnnotation("ProductVersion", "9.0.3")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
||||
|
||||
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
||||
|
||||
modelBuilder.Entity("Hutopy.Web.Features.Contents.Data.Content", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<DateTimeOffset>("CreatedAt")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasDefaultValueSql("CURRENT_TIMESTAMP");
|
||||
|
||||
b.Property<Guid>("CreatedBy")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<Guid>("CreatorId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<DateTimeOffset?>("DeletedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<Guid?>("DeletedBy")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<string>("Description")
|
||||
.IsRequired()
|
||||
.HasMaxLength(2048)
|
||||
.HasColumnType("character varying(2048)");
|
||||
|
||||
b.Property<string>("HtmlFileUrl")
|
||||
.HasMaxLength(2048)
|
||||
.HasColumnType("character varying(2048)");
|
||||
|
||||
b.Property<string>("ThumbnailUrl")
|
||||
.HasMaxLength(2048)
|
||||
.HasColumnType("character varying(2048)");
|
||||
|
||||
b.Property<string>("Title")
|
||||
.IsRequired()
|
||||
.HasMaxLength(128)
|
||||
.HasColumnType("character varying(128)");
|
||||
|
||||
b.PrimitiveCollection<string[]>("Urls")
|
||||
.HasColumnType("text[]");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("CreatorId");
|
||||
|
||||
b.ToTable("Contents", "Content");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Hutopy.Web.Features.Contents.Data.Creator", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<bool>("AcceptDonation")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.Property<string>("BannerUrl")
|
||||
.HasMaxLength(2048)
|
||||
.HasColumnType("character varying(2048)");
|
||||
|
||||
b.Property<DateTimeOffset>("CreatedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<Guid>("CreatedBy")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<DateTimeOffset?>("DeletedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<Guid?>("DeletedBy")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<bool>("IsDeleted")
|
||||
.ValueGeneratedOnAddOrUpdate()
|
||||
.HasColumnType("boolean")
|
||||
.HasComputedColumnSql("\"DeletedAt\" IS NOT NULL", true);
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("character varying(255)");
|
||||
|
||||
b.Property<string>("PortraitUrl")
|
||||
.HasMaxLength(2048)
|
||||
.HasColumnType("character varying(2048)");
|
||||
|
||||
b.Property<string>("Slug")
|
||||
.IsRequired()
|
||||
.HasMaxLength(128)
|
||||
.HasColumnType("character varying(128)");
|
||||
|
||||
b.Property<string>("Title")
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("character varying(255)");
|
||||
|
||||
b.Property<bool>("Verified")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Creators", "Content");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Hutopy.Web.Features.Contents.Data.Slugs", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<DateTimeOffset>("CreatedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<Guid>("CreatedBy")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(128)
|
||||
.HasColumnType("character varying(128)");
|
||||
|
||||
b.Property<string>("NormalizedName")
|
||||
.IsRequired()
|
||||
.ValueGeneratedOnAddOrUpdate()
|
||||
.HasMaxLength(128)
|
||||
.HasColumnType("character varying(128)")
|
||||
.HasComputedColumnSql("LOWER( \"Content\".\"Slugs\".\"Name\")", true);
|
||||
|
||||
b.Property<DateTimeOffset>("ReservedUntil")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<Guid?>("UsedBy")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("NormalizedName")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("Slugs", "Content");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Hutopy.Web.Features.Contents.Data.Content", b =>
|
||||
{
|
||||
b.HasOne("Hutopy.Web.Features.Contents.Data.Creator", "Creator")
|
||||
.WithMany()
|
||||
.HasForeignKey("CreatorId");
|
||||
|
||||
b.OwnsMany("Hutopy.Web.Features.Contents.Data.ContentReaction", "Reactions", b1 =>
|
||||
{
|
||||
b1.Property<Guid>("ContentId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b1.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("integer");
|
||||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b1.Property<int>("Id"));
|
||||
|
||||
b1.Property<int>("Reaction")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b1.Property<Guid>("UserId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b1.Property<string>("UserName")
|
||||
.IsRequired()
|
||||
.HasMaxLength(128)
|
||||
.HasColumnType("character varying(128)");
|
||||
|
||||
b1.HasKey("ContentId", "Id");
|
||||
|
||||
b1.ToTable("Reactions", "Content");
|
||||
|
||||
b1.WithOwner()
|
||||
.HasForeignKey("ContentId");
|
||||
});
|
||||
|
||||
b.Navigation("Creator");
|
||||
|
||||
b.Navigation("Reactions");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Hutopy.Web.Features.Contents.Data.Creator", b =>
|
||||
{
|
||||
b.OwnsOne("Hutopy.Web.Features.Contents.Data.Presentation", "Presentation", b1 =>
|
||||
{
|
||||
b1.Property<Guid>("CreatorId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b1.Property<string>("Description")
|
||||
.IsRequired()
|
||||
.HasMaxLength(2000)
|
||||
.HasColumnType("character varying(2000)");
|
||||
|
||||
b1.Property<string>("Email")
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("character varying(255)");
|
||||
|
||||
b1.Property<string>("PhoneNumber")
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("character varying(255)");
|
||||
|
||||
b1.Property<string>("VideoUrl")
|
||||
.HasMaxLength(2048)
|
||||
.HasColumnType("character varying(2048)");
|
||||
|
||||
b1.HasKey("CreatorId");
|
||||
|
||||
b1.ToTable("Presentation", "Content");
|
||||
|
||||
b1.WithOwner()
|
||||
.HasForeignKey("CreatorId");
|
||||
});
|
||||
|
||||
b.OwnsOne("Hutopy.Web.Features.Contents.Data.Socials", "Socials", b1 =>
|
||||
{
|
||||
b1.Property<Guid>("CreatorId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b1.Property<string>("FacebookUrl")
|
||||
.HasMaxLength(2048)
|
||||
.HasColumnType("character varying(2048)");
|
||||
|
||||
b1.Property<string>("InstagramUrl")
|
||||
.HasMaxLength(2048)
|
||||
.HasColumnType("character varying(2048)");
|
||||
|
||||
b1.Property<string>("LinkedInUrl")
|
||||
.HasMaxLength(2048)
|
||||
.HasColumnType("character varying(2048)");
|
||||
|
||||
b1.Property<string>("RedditUrl")
|
||||
.HasMaxLength(2048)
|
||||
.HasColumnType("character varying(2048)");
|
||||
|
||||
b1.Property<string>("TikTokUrl")
|
||||
.HasMaxLength(2048)
|
||||
.HasColumnType("character varying(2048)");
|
||||
|
||||
b1.Property<string>("WebsiteUrl")
|
||||
.HasMaxLength(2048)
|
||||
.HasColumnType("character varying(2048)");
|
||||
|
||||
b1.Property<string>("XUrl")
|
||||
.HasMaxLength(2048)
|
||||
.HasColumnType("character varying(2048)");
|
||||
|
||||
b1.Property<string>("YoutubeUrl")
|
||||
.HasMaxLength(2048)
|
||||
.HasColumnType("character varying(2048)");
|
||||
|
||||
b1.HasKey("CreatorId");
|
||||
|
||||
b1.ToTable("Socials", "Content");
|
||||
|
||||
b1.WithOwner()
|
||||
.HasForeignKey("CreatorId");
|
||||
});
|
||||
|
||||
b.Navigation("Presentation")
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Socials")
|
||||
.IsRequired();
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Hutopy.Web.Features.Contents.Data.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class AddPresentation : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "Images",
|
||||
schema: "Content");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "PresentationInfos",
|
||||
schema: "Content");
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "BannerUrl",
|
||||
schema: "Content",
|
||||
table: "Creators",
|
||||
type: "character varying(2048)",
|
||||
maxLength: 2048,
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "PortraitUrl",
|
||||
schema: "Content",
|
||||
table: "Creators",
|
||||
type: "character varying(2048)",
|
||||
maxLength: 2048,
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "Presentation",
|
||||
schema: "Content",
|
||||
columns: table => new
|
||||
{
|
||||
CreatorId = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
Description = table.Column<string>(type: "character varying(2000)", maxLength: 2000, nullable: false),
|
||||
VideoUrl = table.Column<string>(type: "character varying(2048)", maxLength: 2048, nullable: true),
|
||||
PhoneNumber = table.Column<string>(type: "character varying(255)", maxLength: 255, nullable: true),
|
||||
Email = table.Column<string>(type: "character varying(255)", maxLength: 255, nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_Presentation", x => x.CreatorId);
|
||||
table.ForeignKey(
|
||||
name: "FK_Presentation_Creators_CreatorId",
|
||||
column: x => x.CreatorId,
|
||||
principalSchema: "Content",
|
||||
principalTable: "Creators",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "Presentation",
|
||||
schema: "Content");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "BannerUrl",
|
||||
schema: "Content",
|
||||
table: "Creators");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "PortraitUrl",
|
||||
schema: "Content",
|
||||
table: "Creators");
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "Images",
|
||||
schema: "Content",
|
||||
columns: table => new
|
||||
{
|
||||
CreatorId = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
Banner = table.Column<string>(type: "character varying(2048)", maxLength: 2048, nullable: true),
|
||||
Logo = table.Column<string>(type: "character varying(2048)", maxLength: 2048, nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_Images", x => x.CreatorId);
|
||||
table.ForeignKey(
|
||||
name: "FK_Images_Creators_CreatorId",
|
||||
column: x => x.CreatorId,
|
||||
principalSchema: "Content",
|
||||
principalTable: "Creators",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "PresentationInfos",
|
||||
schema: "Content",
|
||||
columns: table => new
|
||||
{
|
||||
CreatorId = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
Email = table.Column<string>(type: "character varying(255)", maxLength: 255, nullable: false),
|
||||
Image1Url = table.Column<string>(type: "character varying(2048)", maxLength: 2048, nullable: false),
|
||||
Image2Url = table.Column<string>(type: "character varying(2048)", maxLength: 2048, nullable: false),
|
||||
Image3Url = table.Column<string>(type: "character varying(2048)", maxLength: 2048, nullable: false),
|
||||
Image4Url = table.Column<string>(type: "character varying(2048)", maxLength: 2048, nullable: false),
|
||||
ImagesSubtitle = table.Column<string>(type: "character varying(2000)", maxLength: 2000, nullable: false),
|
||||
ImagesText = table.Column<string>(type: "character varying(10000)", maxLength: 10000, nullable: false),
|
||||
MainImageText = table.Column<string>(type: "character varying(10000)", maxLength: 10000, nullable: false),
|
||||
MainImageUrl = table.Column<string>(type: "character varying(2048)", maxLength: 2048, nullable: false),
|
||||
MainVideoText = table.Column<string>(type: "character varying(10000)", maxLength: 10000, nullable: false),
|
||||
PhoneNumber = table.Column<string>(type: "character varying(255)", maxLength: 255, nullable: false),
|
||||
Title = table.Column<string>(type: "character varying(2000)", maxLength: 2000, nullable: false),
|
||||
VideoSubtitle = table.Column<string>(type: "character varying(2000)", maxLength: 2000, nullable: false),
|
||||
VideoSubtitleMain = table.Column<string>(type: "character varying(2000)", maxLength: 2000, nullable: false),
|
||||
VideoText = table.Column<string>(type: "character varying(10000)", maxLength: 10000, nullable: false),
|
||||
VideoUrl = table.Column<string>(type: "character varying(2048)", maxLength: 2048, nullable: false),
|
||||
VideoUrlMain = table.Column<string>(type: "character varying(2048)", maxLength: 2048, nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_PresentationInfos", x => x.CreatorId);
|
||||
table.ForeignKey(
|
||||
name: "FK_PresentationInfos_Creators_CreatorId",
|
||||
column: x => x.CreatorId,
|
||||
principalSchema: "Content",
|
||||
principalTable: "Creators",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
407
backend/src/Web/Features/Contents/Data/Migrations/20250423173651_AddAlbumAndPhotos.Designer.cs
generated
Normal file
407
backend/src/Web/Features/Contents/Data/Migrations/20250423173651_AddAlbumAndPhotos.Designer.cs
generated
Normal file
@@ -0,0 +1,407 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using Hutopy.Web.Features.Contents.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 Hutopy.Web.Features.Contents.Data.Migrations
|
||||
{
|
||||
[DbContext(typeof(ContentDbContext))]
|
||||
[Migration("20250423173651_AddAlbumAndPhotos")]
|
||||
partial class AddAlbumAndPhotos
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasDefaultSchema("Content")
|
||||
.HasAnnotation("ProductVersion", "9.0.3")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
||||
|
||||
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
||||
|
||||
modelBuilder.Entity("Hutopy.Web.Features.Contents.Data.Album", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<string>("CoverPhotoUrl")
|
||||
.HasMaxLength(2048)
|
||||
.HasColumnType("character varying(2048)");
|
||||
|
||||
b.Property<DateTimeOffset>("CreatedAt")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasDefaultValueSql("CURRENT_TIMESTAMP");
|
||||
|
||||
b.Property<Guid>("CreatedBy")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<DateTimeOffset?>("DeletedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<Guid?>("DeletedBy")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<string>("Description")
|
||||
.HasMaxLength(1000)
|
||||
.HasColumnType("character varying(1000)");
|
||||
|
||||
b.Property<bool>("IsDeleted")
|
||||
.ValueGeneratedOnAddOrUpdate()
|
||||
.HasColumnType("boolean")
|
||||
.HasComputedColumnSql("\"DeletedAt\" IS NOT NULL", true);
|
||||
|
||||
b.Property<string>("Title")
|
||||
.IsRequired()
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("character varying(255)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Albums", "Content");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Hutopy.Web.Features.Contents.Data.AlbumPhoto", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<Guid>("AlbumId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<string>("Caption")
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("character varying(255)");
|
||||
|
||||
b.Property<DateTimeOffset>("CreatedAt")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasDefaultValueSql("CURRENT_TIMESTAMP");
|
||||
|
||||
b.Property<Guid>("CreatedBy")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<DateTimeOffset?>("DeletedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<Guid?>("DeletedBy")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<bool>("IsDeleted")
|
||||
.ValueGeneratedOnAddOrUpdate()
|
||||
.HasColumnType("boolean")
|
||||
.HasComputedColumnSql("\"DeletedAt\" IS NOT NULL", true);
|
||||
|
||||
b.Property<int>("Order")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<string>("PhotoUrl")
|
||||
.IsRequired()
|
||||
.HasMaxLength(2048)
|
||||
.HasColumnType("character varying(2048)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("AlbumId");
|
||||
|
||||
b.ToTable("AlbumPhotos", "Content");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Hutopy.Web.Features.Contents.Data.Content", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<DateTimeOffset>("CreatedAt")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasDefaultValueSql("CURRENT_TIMESTAMP");
|
||||
|
||||
b.Property<Guid>("CreatedBy")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<Guid>("CreatorId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<DateTimeOffset?>("DeletedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<Guid?>("DeletedBy")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<string>("Description")
|
||||
.IsRequired()
|
||||
.HasMaxLength(2048)
|
||||
.HasColumnType("character varying(2048)");
|
||||
|
||||
b.Property<string>("HtmlFileUrl")
|
||||
.HasMaxLength(2048)
|
||||
.HasColumnType("character varying(2048)");
|
||||
|
||||
b.Property<string>("ThumbnailUrl")
|
||||
.HasMaxLength(2048)
|
||||
.HasColumnType("character varying(2048)");
|
||||
|
||||
b.Property<string>("Title")
|
||||
.IsRequired()
|
||||
.HasMaxLength(128)
|
||||
.HasColumnType("character varying(128)");
|
||||
|
||||
b.PrimitiveCollection<string[]>("Urls")
|
||||
.HasColumnType("text[]");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("CreatorId");
|
||||
|
||||
b.ToTable("Contents", "Content");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Hutopy.Web.Features.Contents.Data.Creator", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<bool>("AcceptDonation")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.Property<string>("BannerUrl")
|
||||
.HasMaxLength(2048)
|
||||
.HasColumnType("character varying(2048)");
|
||||
|
||||
b.Property<DateTimeOffset>("CreatedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<Guid>("CreatedBy")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<DateTimeOffset?>("DeletedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<Guid?>("DeletedBy")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<bool>("IsDeleted")
|
||||
.ValueGeneratedOnAddOrUpdate()
|
||||
.HasColumnType("boolean")
|
||||
.HasComputedColumnSql("\"DeletedAt\" IS NOT NULL", true);
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("character varying(255)");
|
||||
|
||||
b.Property<string>("PortraitUrl")
|
||||
.HasMaxLength(2048)
|
||||
.HasColumnType("character varying(2048)");
|
||||
|
||||
b.Property<string>("Slug")
|
||||
.IsRequired()
|
||||
.HasMaxLength(128)
|
||||
.HasColumnType("character varying(128)");
|
||||
|
||||
b.Property<string>("Title")
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("character varying(255)");
|
||||
|
||||
b.Property<bool>("Verified")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Creators", "Content");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Hutopy.Web.Features.Contents.Data.Slugs", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<DateTimeOffset>("CreatedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<Guid>("CreatedBy")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(128)
|
||||
.HasColumnType("character varying(128)");
|
||||
|
||||
b.Property<string>("NormalizedName")
|
||||
.IsRequired()
|
||||
.ValueGeneratedOnAddOrUpdate()
|
||||
.HasMaxLength(128)
|
||||
.HasColumnType("character varying(128)")
|
||||
.HasComputedColumnSql("LOWER( \"Content\".\"Slugs\".\"Name\")", true);
|
||||
|
||||
b.Property<DateTimeOffset>("ReservedUntil")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<Guid?>("UsedBy")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("NormalizedName")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("Slugs", "Content");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Hutopy.Web.Features.Contents.Data.AlbumPhoto", b =>
|
||||
{
|
||||
b.HasOne("Hutopy.Web.Features.Contents.Data.Album", "Album")
|
||||
.WithMany("Photos")
|
||||
.HasForeignKey("AlbumId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Album");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Hutopy.Web.Features.Contents.Data.Content", b =>
|
||||
{
|
||||
b.HasOne("Hutopy.Web.Features.Contents.Data.Creator", "Creator")
|
||||
.WithMany()
|
||||
.HasForeignKey("CreatorId");
|
||||
|
||||
b.OwnsMany("Hutopy.Web.Features.Contents.Data.ContentReaction", "Reactions", b1 =>
|
||||
{
|
||||
b1.Property<Guid>("ContentId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b1.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("integer");
|
||||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b1.Property<int>("Id"));
|
||||
|
||||
b1.Property<int>("Reaction")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b1.Property<Guid>("UserId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b1.Property<string>("UserName")
|
||||
.IsRequired()
|
||||
.HasMaxLength(128)
|
||||
.HasColumnType("character varying(128)");
|
||||
|
||||
b1.HasKey("ContentId", "Id");
|
||||
|
||||
b1.ToTable("Reactions", "Content");
|
||||
|
||||
b1.WithOwner()
|
||||
.HasForeignKey("ContentId");
|
||||
});
|
||||
|
||||
b.Navigation("Creator");
|
||||
|
||||
b.Navigation("Reactions");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Hutopy.Web.Features.Contents.Data.Creator", b =>
|
||||
{
|
||||
b.OwnsOne("Hutopy.Web.Features.Contents.Data.Presentation", "Presentation", b1 =>
|
||||
{
|
||||
b1.Property<Guid>("CreatorId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b1.Property<string>("Description")
|
||||
.IsRequired()
|
||||
.HasMaxLength(2000)
|
||||
.HasColumnType("character varying(2000)");
|
||||
|
||||
b1.Property<string>("Email")
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("character varying(255)");
|
||||
|
||||
b1.Property<string>("PhoneNumber")
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("character varying(255)");
|
||||
|
||||
b1.Property<string>("VideoUrl")
|
||||
.HasMaxLength(2048)
|
||||
.HasColumnType("character varying(2048)");
|
||||
|
||||
b1.HasKey("CreatorId");
|
||||
|
||||
b1.ToTable("Presentation", "Content");
|
||||
|
||||
b1.WithOwner()
|
||||
.HasForeignKey("CreatorId");
|
||||
});
|
||||
|
||||
b.OwnsOne("Hutopy.Web.Features.Contents.Data.Socials", "Socials", b1 =>
|
||||
{
|
||||
b1.Property<Guid>("CreatorId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b1.Property<string>("FacebookUrl")
|
||||
.HasMaxLength(2048)
|
||||
.HasColumnType("character varying(2048)");
|
||||
|
||||
b1.Property<string>("InstagramUrl")
|
||||
.HasMaxLength(2048)
|
||||
.HasColumnType("character varying(2048)");
|
||||
|
||||
b1.Property<string>("LinkedInUrl")
|
||||
.HasMaxLength(2048)
|
||||
.HasColumnType("character varying(2048)");
|
||||
|
||||
b1.Property<string>("RedditUrl")
|
||||
.HasMaxLength(2048)
|
||||
.HasColumnType("character varying(2048)");
|
||||
|
||||
b1.Property<string>("TikTokUrl")
|
||||
.HasMaxLength(2048)
|
||||
.HasColumnType("character varying(2048)");
|
||||
|
||||
b1.Property<string>("WebsiteUrl")
|
||||
.HasMaxLength(2048)
|
||||
.HasColumnType("character varying(2048)");
|
||||
|
||||
b1.Property<string>("XUrl")
|
||||
.HasMaxLength(2048)
|
||||
.HasColumnType("character varying(2048)");
|
||||
|
||||
b1.Property<string>("YoutubeUrl")
|
||||
.HasMaxLength(2048)
|
||||
.HasColumnType("character varying(2048)");
|
||||
|
||||
b1.HasKey("CreatorId");
|
||||
|
||||
b1.ToTable("Socials", "Content");
|
||||
|
||||
b1.WithOwner()
|
||||
.HasForeignKey("CreatorId");
|
||||
});
|
||||
|
||||
b.Navigation("Presentation")
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Socials")
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Hutopy.Web.Features.Contents.Data.Album", b =>
|
||||
{
|
||||
b.Navigation("Photos");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Hutopy.Web.Features.Contents.Data.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class AddAlbumAndPhotos : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.CreateTable(
|
||||
name: "Albums",
|
||||
schema: "Content",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
CreatedBy = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
CreatedAt = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false, defaultValueSql: "CURRENT_TIMESTAMP"),
|
||||
DeletedBy = table.Column<Guid>(type: "uuid", nullable: true),
|
||||
DeletedAt = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: true),
|
||||
IsDeleted = table.Column<bool>(type: "boolean", nullable: false, computedColumnSql: "\"DeletedAt\" IS NOT NULL", stored: true),
|
||||
Title = table.Column<string>(type: "character varying(255)", maxLength: 255, nullable: false),
|
||||
Description = table.Column<string>(type: "character varying(1000)", maxLength: 1000, nullable: true),
|
||||
CoverPhotoUrl = table.Column<string>(type: "character varying(2048)", maxLength: 2048, nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_Albums", x => x.Id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "AlbumPhotos",
|
||||
schema: "Content",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
CreatedBy = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
CreatedAt = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false, defaultValueSql: "CURRENT_TIMESTAMP"),
|
||||
DeletedBy = table.Column<Guid>(type: "uuid", nullable: true),
|
||||
DeletedAt = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: true),
|
||||
IsDeleted = table.Column<bool>(type: "boolean", nullable: false, computedColumnSql: "\"DeletedAt\" IS NOT NULL", stored: true),
|
||||
AlbumId = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
PhotoUrl = table.Column<string>(type: "character varying(2048)", maxLength: 2048, nullable: false),
|
||||
Caption = table.Column<string>(type: "character varying(255)", maxLength: 255, nullable: true),
|
||||
Order = table.Column<int>(type: "integer", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_AlbumPhotos", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_AlbumPhotos_Albums_AlbumId",
|
||||
column: x => x.AlbumId,
|
||||
principalSchema: "Content",
|
||||
principalTable: "Albums",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_AlbumPhotos_AlbumId",
|
||||
schema: "Content",
|
||||
table: "AlbumPhotos",
|
||||
column: "AlbumId");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "AlbumPhotos",
|
||||
schema: "Content");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "Albums",
|
||||
schema: "Content");
|
||||
}
|
||||
}
|
||||
}
|
||||
399
backend/src/Web/Features/Contents/Data/Migrations/20250423180519_SimplifyAlbums.Designer.cs
generated
Normal file
399
backend/src/Web/Features/Contents/Data/Migrations/20250423180519_SimplifyAlbums.Designer.cs
generated
Normal file
@@ -0,0 +1,399 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using Hutopy.Web.Features.Contents.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 Hutopy.Web.Features.Contents.Data.Migrations
|
||||
{
|
||||
[DbContext(typeof(ContentDbContext))]
|
||||
[Migration("20250423180519_SimplifyAlbums")]
|
||||
partial class SimplifyAlbums
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasDefaultSchema("Content")
|
||||
.HasAnnotation("ProductVersion", "9.0.3")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
||||
|
||||
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
||||
|
||||
modelBuilder.Entity("Hutopy.Web.Features.Contents.Data.Album", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<DateTimeOffset>("CreatedAt")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasDefaultValueSql("CURRENT_TIMESTAMP");
|
||||
|
||||
b.Property<Guid>("CreatedBy")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<DateTimeOffset?>("DeletedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<Guid?>("DeletedBy")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<bool>("IsDeleted")
|
||||
.ValueGeneratedOnAddOrUpdate()
|
||||
.HasColumnType("boolean")
|
||||
.HasComputedColumnSql("\"DeletedAt\" IS NOT NULL", true);
|
||||
|
||||
b.Property<string>("Title")
|
||||
.IsRequired()
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("character varying(255)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Albums", "Content");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Hutopy.Web.Features.Contents.Data.AlbumPhoto", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<Guid>("AlbumId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<string>("Caption")
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("character varying(255)");
|
||||
|
||||
b.Property<DateTimeOffset>("CreatedAt")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasDefaultValueSql("CURRENT_TIMESTAMP");
|
||||
|
||||
b.Property<Guid>("CreatedBy")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<DateTimeOffset?>("DeletedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<Guid?>("DeletedBy")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<bool>("IsDeleted")
|
||||
.ValueGeneratedOnAddOrUpdate()
|
||||
.HasColumnType("boolean")
|
||||
.HasComputedColumnSql("\"DeletedAt\" IS NOT NULL", true);
|
||||
|
||||
b.Property<int>("Order")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<string>("PhotoUrl")
|
||||
.IsRequired()
|
||||
.HasMaxLength(2048)
|
||||
.HasColumnType("character varying(2048)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("AlbumId");
|
||||
|
||||
b.ToTable("AlbumPhotos", "Content");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Hutopy.Web.Features.Contents.Data.Content", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<DateTimeOffset>("CreatedAt")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasDefaultValueSql("CURRENT_TIMESTAMP");
|
||||
|
||||
b.Property<Guid>("CreatedBy")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<Guid>("CreatorId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<DateTimeOffset?>("DeletedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<Guid?>("DeletedBy")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<string>("Description")
|
||||
.IsRequired()
|
||||
.HasMaxLength(2048)
|
||||
.HasColumnType("character varying(2048)");
|
||||
|
||||
b.Property<string>("HtmlFileUrl")
|
||||
.HasMaxLength(2048)
|
||||
.HasColumnType("character varying(2048)");
|
||||
|
||||
b.Property<string>("ThumbnailUrl")
|
||||
.HasMaxLength(2048)
|
||||
.HasColumnType("character varying(2048)");
|
||||
|
||||
b.Property<string>("Title")
|
||||
.IsRequired()
|
||||
.HasMaxLength(128)
|
||||
.HasColumnType("character varying(128)");
|
||||
|
||||
b.PrimitiveCollection<string[]>("Urls")
|
||||
.HasColumnType("text[]");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("CreatorId");
|
||||
|
||||
b.ToTable("Contents", "Content");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Hutopy.Web.Features.Contents.Data.Creator", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<bool>("AcceptDonation")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.Property<string>("BannerUrl")
|
||||
.HasMaxLength(2048)
|
||||
.HasColumnType("character varying(2048)");
|
||||
|
||||
b.Property<DateTimeOffset>("CreatedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<Guid>("CreatedBy")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<DateTimeOffset?>("DeletedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<Guid?>("DeletedBy")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<bool>("IsDeleted")
|
||||
.ValueGeneratedOnAddOrUpdate()
|
||||
.HasColumnType("boolean")
|
||||
.HasComputedColumnSql("\"DeletedAt\" IS NOT NULL", true);
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("character varying(255)");
|
||||
|
||||
b.Property<string>("PortraitUrl")
|
||||
.HasMaxLength(2048)
|
||||
.HasColumnType("character varying(2048)");
|
||||
|
||||
b.Property<string>("Slug")
|
||||
.IsRequired()
|
||||
.HasMaxLength(128)
|
||||
.HasColumnType("character varying(128)");
|
||||
|
||||
b.Property<string>("Title")
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("character varying(255)");
|
||||
|
||||
b.Property<bool>("Verified")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Creators", "Content");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Hutopy.Web.Features.Contents.Data.Slugs", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<DateTimeOffset>("CreatedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<Guid>("CreatedBy")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(128)
|
||||
.HasColumnType("character varying(128)");
|
||||
|
||||
b.Property<string>("NormalizedName")
|
||||
.IsRequired()
|
||||
.ValueGeneratedOnAddOrUpdate()
|
||||
.HasMaxLength(128)
|
||||
.HasColumnType("character varying(128)")
|
||||
.HasComputedColumnSql("LOWER( \"Content\".\"Slugs\".\"Name\")", true);
|
||||
|
||||
b.Property<DateTimeOffset>("ReservedUntil")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<Guid?>("UsedBy")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("NormalizedName")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("Slugs", "Content");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Hutopy.Web.Features.Contents.Data.AlbumPhoto", b =>
|
||||
{
|
||||
b.HasOne("Hutopy.Web.Features.Contents.Data.Album", "Album")
|
||||
.WithMany("Photos")
|
||||
.HasForeignKey("AlbumId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Album");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Hutopy.Web.Features.Contents.Data.Content", b =>
|
||||
{
|
||||
b.HasOne("Hutopy.Web.Features.Contents.Data.Creator", "Creator")
|
||||
.WithMany()
|
||||
.HasForeignKey("CreatorId");
|
||||
|
||||
b.OwnsMany("Hutopy.Web.Features.Contents.Data.ContentReaction", "Reactions", b1 =>
|
||||
{
|
||||
b1.Property<Guid>("ContentId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b1.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("integer");
|
||||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b1.Property<int>("Id"));
|
||||
|
||||
b1.Property<int>("Reaction")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b1.Property<Guid>("UserId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b1.Property<string>("UserName")
|
||||
.IsRequired()
|
||||
.HasMaxLength(128)
|
||||
.HasColumnType("character varying(128)");
|
||||
|
||||
b1.HasKey("ContentId", "Id");
|
||||
|
||||
b1.ToTable("Reactions", "Content");
|
||||
|
||||
b1.WithOwner()
|
||||
.HasForeignKey("ContentId");
|
||||
});
|
||||
|
||||
b.Navigation("Creator");
|
||||
|
||||
b.Navigation("Reactions");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Hutopy.Web.Features.Contents.Data.Creator", b =>
|
||||
{
|
||||
b.OwnsOne("Hutopy.Web.Features.Contents.Data.Presentation", "Presentation", b1 =>
|
||||
{
|
||||
b1.Property<Guid>("CreatorId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b1.Property<string>("Description")
|
||||
.IsRequired()
|
||||
.HasMaxLength(2000)
|
||||
.HasColumnType("character varying(2000)");
|
||||
|
||||
b1.Property<string>("Email")
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("character varying(255)");
|
||||
|
||||
b1.Property<string>("PhoneNumber")
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("character varying(255)");
|
||||
|
||||
b1.Property<string>("VideoUrl")
|
||||
.HasMaxLength(2048)
|
||||
.HasColumnType("character varying(2048)");
|
||||
|
||||
b1.HasKey("CreatorId");
|
||||
|
||||
b1.ToTable("Presentation", "Content");
|
||||
|
||||
b1.WithOwner()
|
||||
.HasForeignKey("CreatorId");
|
||||
});
|
||||
|
||||
b.OwnsOne("Hutopy.Web.Features.Contents.Data.Socials", "Socials", b1 =>
|
||||
{
|
||||
b1.Property<Guid>("CreatorId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b1.Property<string>("FacebookUrl")
|
||||
.HasMaxLength(2048)
|
||||
.HasColumnType("character varying(2048)");
|
||||
|
||||
b1.Property<string>("InstagramUrl")
|
||||
.HasMaxLength(2048)
|
||||
.HasColumnType("character varying(2048)");
|
||||
|
||||
b1.Property<string>("LinkedInUrl")
|
||||
.HasMaxLength(2048)
|
||||
.HasColumnType("character varying(2048)");
|
||||
|
||||
b1.Property<string>("RedditUrl")
|
||||
.HasMaxLength(2048)
|
||||
.HasColumnType("character varying(2048)");
|
||||
|
||||
b1.Property<string>("TikTokUrl")
|
||||
.HasMaxLength(2048)
|
||||
.HasColumnType("character varying(2048)");
|
||||
|
||||
b1.Property<string>("WebsiteUrl")
|
||||
.HasMaxLength(2048)
|
||||
.HasColumnType("character varying(2048)");
|
||||
|
||||
b1.Property<string>("XUrl")
|
||||
.HasMaxLength(2048)
|
||||
.HasColumnType("character varying(2048)");
|
||||
|
||||
b1.Property<string>("YoutubeUrl")
|
||||
.HasMaxLength(2048)
|
||||
.HasColumnType("character varying(2048)");
|
||||
|
||||
b1.HasKey("CreatorId");
|
||||
|
||||
b1.ToTable("Socials", "Content");
|
||||
|
||||
b1.WithOwner()
|
||||
.HasForeignKey("CreatorId");
|
||||
});
|
||||
|
||||
b.Navigation("Presentation")
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Socials")
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Hutopy.Web.Features.Contents.Data.Album", b =>
|
||||
{
|
||||
b.Navigation("Photos");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Hutopy.Web.Features.Contents.Data.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class SimplifyAlbums : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "CoverPhotoUrl",
|
||||
schema: "Content",
|
||||
table: "Albums");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "Description",
|
||||
schema: "Content",
|
||||
table: "Albums");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "CoverPhotoUrl",
|
||||
schema: "Content",
|
||||
table: "Albums",
|
||||
type: "character varying(2048)",
|
||||
maxLength: 2048,
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "Description",
|
||||
schema: "Content",
|
||||
table: "Albums",
|
||||
type: "character varying(1000)",
|
||||
maxLength: 1000,
|
||||
nullable: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -23,6 +23,88 @@ namespace Hutopy.Web.Features.Contents.Data.Migrations
|
||||
|
||||
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
||||
|
||||
modelBuilder.Entity("Hutopy.Web.Features.Contents.Data.Album", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<DateTimeOffset>("CreatedAt")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasDefaultValueSql("CURRENT_TIMESTAMP");
|
||||
|
||||
b.Property<Guid>("CreatedBy")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<DateTimeOffset?>("DeletedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<Guid?>("DeletedBy")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<bool>("IsDeleted")
|
||||
.ValueGeneratedOnAddOrUpdate()
|
||||
.HasColumnType("boolean")
|
||||
.HasComputedColumnSql("\"DeletedAt\" IS NOT NULL", true);
|
||||
|
||||
b.Property<string>("Title")
|
||||
.IsRequired()
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("character varying(255)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Albums", "Content");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Hutopy.Web.Features.Contents.Data.AlbumPhoto", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<Guid>("AlbumId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<string>("Caption")
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("character varying(255)");
|
||||
|
||||
b.Property<DateTimeOffset>("CreatedAt")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasDefaultValueSql("CURRENT_TIMESTAMP");
|
||||
|
||||
b.Property<Guid>("CreatedBy")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<DateTimeOffset?>("DeletedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<Guid?>("DeletedBy")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<bool>("IsDeleted")
|
||||
.ValueGeneratedOnAddOrUpdate()
|
||||
.HasColumnType("boolean")
|
||||
.HasComputedColumnSql("\"DeletedAt\" IS NOT NULL", true);
|
||||
|
||||
b.Property<int>("Order")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<string>("PhotoUrl")
|
||||
.IsRequired()
|
||||
.HasMaxLength(2048)
|
||||
.HasColumnType("character varying(2048)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("AlbumId");
|
||||
|
||||
b.ToTable("AlbumPhotos", "Content");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Hutopy.Web.Features.Contents.Data.Content", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
@@ -83,6 +165,10 @@ namespace Hutopy.Web.Features.Contents.Data.Migrations
|
||||
b.Property<bool>("AcceptDonation")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.Property<string>("BannerUrl")
|
||||
.HasMaxLength(2048)
|
||||
.HasColumnType("character varying(2048)");
|
||||
|
||||
b.Property<DateTimeOffset>("CreatedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
@@ -105,6 +191,10 @@ namespace Hutopy.Web.Features.Contents.Data.Migrations
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("character varying(255)");
|
||||
|
||||
b.Property<string>("PortraitUrl")
|
||||
.HasMaxLength(2048)
|
||||
.HasColumnType("character varying(2048)");
|
||||
|
||||
b.Property<string>("Slug")
|
||||
.IsRequired()
|
||||
.HasMaxLength(128)
|
||||
@@ -160,6 +250,17 @@ namespace Hutopy.Web.Features.Contents.Data.Migrations
|
||||
b.ToTable("Slugs", "Content");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Hutopy.Web.Features.Contents.Data.AlbumPhoto", b =>
|
||||
{
|
||||
b.HasOne("Hutopy.Web.Features.Contents.Data.Album", "Album")
|
||||
.WithMany("Photos")
|
||||
.HasForeignKey("AlbumId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Album");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Hutopy.Web.Features.Contents.Data.Content", b =>
|
||||
{
|
||||
b.HasOne("Hutopy.Web.Features.Contents.Data.Creator", "Creator")
|
||||
@@ -203,120 +304,31 @@ namespace Hutopy.Web.Features.Contents.Data.Migrations
|
||||
|
||||
modelBuilder.Entity("Hutopy.Web.Features.Contents.Data.Creator", b =>
|
||||
{
|
||||
b.OwnsOne("Hutopy.Web.Features.Contents.Data.Images", "Images", b1 =>
|
||||
b.OwnsOne("Hutopy.Web.Features.Contents.Data.Presentation", "Presentation", b1 =>
|
||||
{
|
||||
b1.Property<Guid>("CreatorId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b1.Property<string>("Banner")
|
||||
.HasMaxLength(2048)
|
||||
.HasColumnType("character varying(2048)");
|
||||
|
||||
b1.Property<string>("Logo")
|
||||
.HasMaxLength(2048)
|
||||
.HasColumnType("character varying(2048)");
|
||||
|
||||
b1.HasKey("CreatorId");
|
||||
|
||||
b1.ToTable("Images", "Content");
|
||||
|
||||
b1.WithOwner()
|
||||
.HasForeignKey("CreatorId");
|
||||
});
|
||||
|
||||
b.OwnsOne("Hutopy.Web.Features.Contents.Data.PresentationInfos", "PresentationInfos", b1 =>
|
||||
{
|
||||
b1.Property<Guid>("CreatorId")
|
||||
.HasColumnType("uuid");
|
||||
b1.Property<string>("Description")
|
||||
.IsRequired()
|
||||
.HasMaxLength(2000)
|
||||
.HasColumnType("character varying(2000)");
|
||||
|
||||
b1.Property<string>("Email")
|
||||
.IsRequired()
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("character varying(255)");
|
||||
|
||||
b1.Property<string>("Image1Url")
|
||||
.IsRequired()
|
||||
.HasMaxLength(2048)
|
||||
.HasColumnType("character varying(2048)");
|
||||
|
||||
b1.Property<string>("Image2Url")
|
||||
.IsRequired()
|
||||
.HasMaxLength(2048)
|
||||
.HasColumnType("character varying(2048)");
|
||||
|
||||
b1.Property<string>("Image3Url")
|
||||
.IsRequired()
|
||||
.HasMaxLength(2048)
|
||||
.HasColumnType("character varying(2048)");
|
||||
|
||||
b1.Property<string>("Image4Url")
|
||||
.IsRequired()
|
||||
.HasMaxLength(2048)
|
||||
.HasColumnType("character varying(2048)");
|
||||
|
||||
b1.Property<string>("ImagesSubtitle")
|
||||
.IsRequired()
|
||||
.HasMaxLength(2000)
|
||||
.HasColumnType("character varying(2000)");
|
||||
|
||||
b1.Property<string>("ImagesText")
|
||||
.IsRequired()
|
||||
.HasMaxLength(10000)
|
||||
.HasColumnType("character varying(10000)");
|
||||
|
||||
b1.Property<string>("MainImageText")
|
||||
.IsRequired()
|
||||
.HasMaxLength(10000)
|
||||
.HasColumnType("character varying(10000)");
|
||||
|
||||
b1.Property<string>("MainImageUrl")
|
||||
.IsRequired()
|
||||
.HasMaxLength(2048)
|
||||
.HasColumnType("character varying(2048)");
|
||||
|
||||
b1.Property<string>("MainVideoText")
|
||||
.IsRequired()
|
||||
.HasMaxLength(10000)
|
||||
.HasColumnType("character varying(10000)");
|
||||
|
||||
b1.Property<string>("PhoneNumber")
|
||||
.IsRequired()
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("character varying(255)");
|
||||
|
||||
b1.Property<string>("Title")
|
||||
.IsRequired()
|
||||
.HasMaxLength(2000)
|
||||
.HasColumnType("character varying(2000)");
|
||||
|
||||
b1.Property<string>("VideoSubtitle")
|
||||
.IsRequired()
|
||||
.HasMaxLength(2000)
|
||||
.HasColumnType("character varying(2000)");
|
||||
|
||||
b1.Property<string>("VideoSubtitleMain")
|
||||
.IsRequired()
|
||||
.HasMaxLength(2000)
|
||||
.HasColumnType("character varying(2000)");
|
||||
|
||||
b1.Property<string>("VideoText")
|
||||
.IsRequired()
|
||||
.HasMaxLength(10000)
|
||||
.HasColumnType("character varying(10000)");
|
||||
|
||||
b1.Property<string>("VideoUrl")
|
||||
.IsRequired()
|
||||
.HasMaxLength(2048)
|
||||
.HasColumnType("character varying(2048)");
|
||||
|
||||
b1.Property<string>("VideoUrlMain")
|
||||
.IsRequired()
|
||||
.HasMaxLength(2048)
|
||||
.HasColumnType("character varying(2048)");
|
||||
|
||||
b1.HasKey("CreatorId");
|
||||
|
||||
b1.ToTable("PresentationInfos", "Content");
|
||||
b1.ToTable("Presentation", "Content");
|
||||
|
||||
b1.WithOwner()
|
||||
.HasForeignKey("CreatorId");
|
||||
@@ -367,15 +379,17 @@ namespace Hutopy.Web.Features.Contents.Data.Migrations
|
||||
.HasForeignKey("CreatorId");
|
||||
});
|
||||
|
||||
b.Navigation("Images")
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("PresentationInfos")
|
||||
b.Navigation("Presentation")
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Socials")
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Hutopy.Web.Features.Contents.Data.Album", b =>
|
||||
{
|
||||
b.Navigation("Photos");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
|
||||
121
backend/src/Web/Features/Contents/Handlers/AddPhotoToAlbum.cs
Normal file
121
backend/src/Web/Features/Contents/Handlers/AddPhotoToAlbum.cs
Normal file
@@ -0,0 +1,121 @@
|
||||
using FastEndpoints;
|
||||
using JetBrains.Annotations;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Hutopy.Web.Features.Contents.Data;
|
||||
using Hutopy.Web.Common.Security;
|
||||
using Hutopy.Web.Common.BlobStorage;
|
||||
|
||||
namespace Hutopy.Web.Features.Contents.Handlers;
|
||||
|
||||
[PublicAPI]
|
||||
public record AddPhotoToAlbumRequest(
|
||||
Guid AlbumId,
|
||||
Guid PhotoId,
|
||||
IFormFile File,
|
||||
string? Caption = null);
|
||||
|
||||
[PublicAPI]
|
||||
public record AddPhotoToAlbumResponse(
|
||||
Guid PhotoId,
|
||||
string PhotoUrl);
|
||||
|
||||
[PublicAPI]
|
||||
public sealed class AddPhotoToAlbumRequestValidator : Validator<AddPhotoToAlbumRequest>
|
||||
{
|
||||
public AddPhotoToAlbumRequestValidator()
|
||||
{
|
||||
RuleFor(x => x.AlbumId)
|
||||
.NotNull()
|
||||
.NotEmpty();
|
||||
|
||||
RuleFor(x => x.PhotoId)
|
||||
.NotNull()
|
||||
.NotEmpty();
|
||||
|
||||
RuleFor(x => x.File)
|
||||
.NotNull()
|
||||
.NotEmpty()
|
||||
.Must(file => file.ContentType.StartsWith("image/"))
|
||||
.WithMessage("File must be an image");
|
||||
|
||||
RuleFor(x => x.Caption)
|
||||
.MaximumLength(255);
|
||||
}
|
||||
}
|
||||
|
||||
[PublicAPI]
|
||||
public class AddPhotoToAlbumHandler(
|
||||
ContentDbContext context,
|
||||
AzureBlobStorage blobStorage)
|
||||
: Endpoint<AddPhotoToAlbumRequest, AddPhotoToAlbumResponse>
|
||||
{
|
||||
public override void Configure()
|
||||
{
|
||||
Post("/api/albums/{AlbumId}/photos");
|
||||
Options(o => o.WithTags("Albums"));
|
||||
AllowFileUploads();
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(
|
||||
AddPhotoToAlbumRequest request,
|
||||
CancellationToken ct)
|
||||
{
|
||||
var userId = User.GetUserId();
|
||||
|
||||
var album = await context
|
||||
.Albums
|
||||
.SingleOrDefaultAsync(
|
||||
a => a.Id == request.AlbumId && a.CreatedBy == userId,
|
||||
cancellationToken: ct);
|
||||
|
||||
if (album is null)
|
||||
{
|
||||
await SendNotFoundAsync(ct);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if a photo with the same ID already exists
|
||||
var existingPhoto = await context
|
||||
.AlbumPhotos
|
||||
.AnyAsync(p => p.Id == request.PhotoId, ct);
|
||||
|
||||
if (existingPhoto)
|
||||
{
|
||||
await SendErrorsAsync(409, ct);
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the next order number
|
||||
var nextOrder = await context
|
||||
.AlbumPhotos
|
||||
.Where(p => p.AlbumId == request.AlbumId)
|
||||
.MaxAsync(p => (int?)p.Order, ct) ?? 0;
|
||||
|
||||
// Upload the photo to blob storage
|
||||
var photoUrl = await blobStorage.UploadFileAsync(
|
||||
ContainerNames.Creators,
|
||||
$"{SubDirectoryNames.Albums}/{request.AlbumId}/{request.PhotoId}",
|
||||
request.File.OpenReadStream(),
|
||||
request.File.ContentType,
|
||||
ct);
|
||||
|
||||
// Create the album photo
|
||||
var photo = new AlbumPhoto
|
||||
{
|
||||
Id = request.PhotoId,
|
||||
CreatedBy = userId,
|
||||
AlbumId = request.AlbumId,
|
||||
PhotoUrl = photoUrl,
|
||||
Caption = request.Caption,
|
||||
Order = nextOrder + 1
|
||||
};
|
||||
|
||||
context.AlbumPhotos.Add(photo);
|
||||
|
||||
await context.SaveChangesAsync(ct);
|
||||
|
||||
await SendOkAsync(
|
||||
new AddPhotoToAlbumResponse(photo.Id, photoUrl),
|
||||
ct);
|
||||
}
|
||||
}
|
||||
@@ -31,7 +31,6 @@ public class ChangeBannerHandler(
|
||||
{
|
||||
var creator = await context
|
||||
.Creators
|
||||
.Include(c => c.Images)
|
||||
.SingleOrDefaultAsync(
|
||||
c => c.Id == request.CreatorId,
|
||||
cancellationToken: ct);
|
||||
@@ -49,7 +48,7 @@ public class ChangeBannerHandler(
|
||||
request.File.ContentType,
|
||||
ct);
|
||||
|
||||
creator.Images.Banner = $"{blobUrl}?t={DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()}";
|
||||
creator.BannerUrl = $"{blobUrl}?t={DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()}";
|
||||
|
||||
await context.SaveChangesAsync(ct);
|
||||
|
||||
|
||||
@@ -46,7 +46,6 @@ public class ChangeLogoHandler(
|
||||
{
|
||||
var creator = await context
|
||||
.Creators
|
||||
.Include(c => c.Images)
|
||||
.SingleOrDefaultAsync(
|
||||
c => c.Id == request.CreatorId,
|
||||
cancellationToken: ct);
|
||||
@@ -57,7 +56,6 @@ public class ChangeLogoHandler(
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: this upload should be done to the Creators container
|
||||
var blobUrl = await blobStorage.UploadFileAsync(
|
||||
ContainerNames.Creators,
|
||||
$"{request.CreatorId}/{SubDirectoryNames.Profile}/{CommonFileNames.ProfilePicture}",
|
||||
@@ -65,7 +63,7 @@ public class ChangeLogoHandler(
|
||||
request.File.ContentType,
|
||||
ct);
|
||||
|
||||
creator.Images.Logo = $"{blobUrl}?t={DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()}";
|
||||
creator.PortraitUrl = $"{blobUrl}?t={DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()}";
|
||||
|
||||
await context.SaveChangesAsync(ct);
|
||||
|
||||
|
||||
@@ -6,28 +6,10 @@ namespace Hutopy.Web.Features.Contents.Handlers;
|
||||
[PublicAPI]
|
||||
public record ChangePresentationInfosRequest(
|
||||
Guid CreatorId,
|
||||
string? PhoneNumber,
|
||||
string? Email,
|
||||
string? Title,
|
||||
string? MainImageText,
|
||||
string? MainVideoText,
|
||||
string? ImagesSubtitle,
|
||||
string? ImagesText,
|
||||
string? VideoSubtitle,
|
||||
string? VideoSubtitleMain,
|
||||
string? VideoUrlMain,
|
||||
string Description,
|
||||
string? VideoUrl,
|
||||
string? VideoText,
|
||||
string? MainImageUrl,
|
||||
string? Image1Url,
|
||||
string? Image2Url,
|
||||
string? Image3Url,
|
||||
string? Image4Url,
|
||||
IFormFile? MainImage,
|
||||
IFormFile? Image1,
|
||||
IFormFile? Image2,
|
||||
IFormFile? Image3,
|
||||
IFormFile? Image4);
|
||||
string? PhoneNumber,
|
||||
string? Email);
|
||||
|
||||
[PublicAPI]
|
||||
public class ChangePresentationInfosHandler(
|
||||
@@ -39,7 +21,6 @@ public class ChangePresentationInfosHandler(
|
||||
{
|
||||
Post("/api/creators/{CreatorId}/presentation-infos");
|
||||
Options(o => o.WithTags("Creators"));
|
||||
AllowFileUploads();
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(
|
||||
@@ -48,7 +29,7 @@ public class ChangePresentationInfosHandler(
|
||||
{
|
||||
var creator = await context
|
||||
.Creators
|
||||
.Include(c => c.PresentationInfos)
|
||||
.Include(c => c.Presentation)
|
||||
.SingleOrDefaultAsync(
|
||||
c => c.Id == request.CreatorId,
|
||||
cancellationToken: ct);
|
||||
@@ -59,56 +40,12 @@ public class ChangePresentationInfosHandler(
|
||||
return;
|
||||
}
|
||||
|
||||
async Task<string> UploadFileOrDefaultAsync(
|
||||
IFormFile? file,
|
||||
string subDirectory,
|
||||
string fileName,
|
||||
string? newUrl)
|
||||
{
|
||||
if (newUrl == "")
|
||||
return "";
|
||||
|
||||
if (file != null)
|
||||
{
|
||||
return await blobStorage.UploadFileAsync(
|
||||
ContainerNames.Creators,
|
||||
$"{request.CreatorId}/{subDirectory}/{fileName}",
|
||||
file.OpenReadStream(),
|
||||
file.ContentType,
|
||||
ct);
|
||||
}
|
||||
|
||||
return newUrl?.Trim() ?? "";
|
||||
}
|
||||
|
||||
creator.PresentationInfos.MainImageUrl = await UploadFileOrDefaultAsync(
|
||||
request.MainImage, "Profile", "MainImage", request.MainImageUrl);
|
||||
|
||||
creator.PresentationInfos.Image1Url = await UploadFileOrDefaultAsync(
|
||||
request.Image1, "Profile", "Image1", request.Image1Url);
|
||||
|
||||
creator.PresentationInfos.Image2Url = await UploadFileOrDefaultAsync(
|
||||
request.Image2, "Profile", "Image2", request.Image2Url);
|
||||
|
||||
creator.PresentationInfos.Image3Url = await UploadFileOrDefaultAsync(
|
||||
request.Image3, "Profile", "Image3", request.Image3Url);
|
||||
|
||||
creator.PresentationInfos.Image4Url = await UploadFileOrDefaultAsync(
|
||||
request.Image4, "Profile", "Image4", request.Image4Url);
|
||||
|
||||
creator.PresentationInfos.PhoneNumber = request.PhoneNumber?.Trim() ?? "";
|
||||
creator.PresentationInfos.Email = request.Email?.Trim() ?? "";
|
||||
creator.PresentationInfos.Title = request.Title?.Trim() ?? "";
|
||||
creator.PresentationInfos.MainImageText = request.MainImageText?.Trim() ?? "";
|
||||
creator.PresentationInfos.MainVideoText = request.MainVideoText?.Trim() ?? "";
|
||||
creator.PresentationInfos.ImagesSubtitle = request.ImagesSubtitle?.Trim() ?? "";
|
||||
creator.PresentationInfos.ImagesText = request.ImagesText?.Trim() ?? "";
|
||||
creator.PresentationInfos.VideoSubtitle = request.VideoSubtitle?.Trim() ?? "";
|
||||
creator.PresentationInfos.VideoSubtitleMain = request.VideoSubtitleMain?.Trim() ?? "";
|
||||
creator.PresentationInfos.VideoUrlMain = request.VideoUrlMain?.Trim() ?? "";
|
||||
creator.PresentationInfos.VideoUrl = request.VideoUrl?.Trim() ?? "";
|
||||
creator.PresentationInfos.VideoText = request.VideoText?.Trim() ?? "";
|
||||
|
||||
// Update the presentation info with the new values
|
||||
creator.Presentation.Description = request.Description.Trim();
|
||||
creator.Presentation.VideoUrl = request.VideoUrl?.Trim();
|
||||
creator.Presentation.PhoneNumber = request.PhoneNumber?.Trim();
|
||||
creator.Presentation.Email = request.Email?.Trim();
|
||||
|
||||
await context.SaveChangesAsync(ct);
|
||||
await SendOkAsync(ct);
|
||||
}
|
||||
|
||||
75
backend/src/Web/Features/Contents/Handlers/CreateAlbum.cs
Normal file
75
backend/src/Web/Features/Contents/Handlers/CreateAlbum.cs
Normal file
@@ -0,0 +1,75 @@
|
||||
using Hutopy.Web.Features.Contents.Data;
|
||||
using Hutopy.Web.Common.Security;
|
||||
|
||||
namespace Hutopy.Web.Features.Contents.Handlers;
|
||||
|
||||
[PublicAPI]
|
||||
public record CreateAlbumRequest(
|
||||
Guid AlbumId,
|
||||
string Title,
|
||||
string? Description = null);
|
||||
|
||||
[PublicAPI]
|
||||
public record CreateAlbumResponse(
|
||||
Guid AlbumId);
|
||||
|
||||
[PublicAPI]
|
||||
public sealed class CreateAlbumRequestValidator : Validator<CreateAlbumRequest>
|
||||
{
|
||||
public CreateAlbumRequestValidator()
|
||||
{
|
||||
RuleFor(x => x.AlbumId)
|
||||
.NotNull()
|
||||
.NotEmpty();
|
||||
|
||||
RuleFor(x => x.Title)
|
||||
.NotNull()
|
||||
.NotEmpty()
|
||||
.MaximumLength(255);
|
||||
|
||||
RuleFor(x => x.Description)
|
||||
.MaximumLength(1000);
|
||||
}
|
||||
}
|
||||
|
||||
[PublicAPI]
|
||||
public class CreateAlbumHandler(
|
||||
ContentDbContext context)
|
||||
: Endpoint<CreateAlbumRequest, CreateAlbumResponse>
|
||||
{
|
||||
public override void Configure()
|
||||
{
|
||||
Post("/api/albums");
|
||||
Options(o => o.WithTags("Albums"));
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(
|
||||
CreateAlbumRequest request,
|
||||
CancellationToken ct)
|
||||
{
|
||||
// Check if an album with the same ID already exists
|
||||
var existingAlbum = await context
|
||||
.Albums
|
||||
.AnyAsync(a => a.Id == request.AlbumId, ct);
|
||||
|
||||
if (existingAlbum)
|
||||
{
|
||||
await SendErrorsAsync(409, ct);
|
||||
return;
|
||||
}
|
||||
|
||||
var album = new Album
|
||||
{
|
||||
Id = request.AlbumId,
|
||||
CreatedBy = User.GetUserId(),
|
||||
Title = request.Title
|
||||
};
|
||||
|
||||
context.Albums.Add(album);
|
||||
await context.SaveChangesAsync(ct);
|
||||
|
||||
await SendOkAsync(
|
||||
new CreateAlbumResponse(album.Id),
|
||||
ct);
|
||||
}
|
||||
}
|
||||
@@ -68,7 +68,7 @@ public sealed class PostContentHtml(
|
||||
Id = c.Id,
|
||||
CreatedBy = c.CreatedBy,
|
||||
CreatedByName = c.Creator.Name,
|
||||
CreatedByPortraitUrl = c.Creator.Images.Logo,
|
||||
CreatedByPortraitUrl = c.Creator.PortraitUrl,
|
||||
CreatedAt = c.CreatedAt,
|
||||
DeletedBy = c.DeletedBy,
|
||||
DeletedAt = c.DeletedAt,
|
||||
|
||||
@@ -8,7 +8,7 @@ public record CreateCreatorRequest(
|
||||
Guid SlugReservationId,
|
||||
Guid CreatorId);
|
||||
|
||||
[UsedImplicitly]
|
||||
[PublicAPI]
|
||||
public sealed class CreateCreatorRequestValidator : Validator<CreateCreatorRequest>
|
||||
{
|
||||
public CreateCreatorRequestValidator()
|
||||
@@ -64,7 +64,7 @@ public sealed class CreateCreatorHandler(
|
||||
Id = req.CreatorId,
|
||||
CreatedBy = User.GetUserId(),
|
||||
Name = slug.Name,
|
||||
Slug = slug.NormalizedName,
|
||||
Slug = slug.NormalizedName
|
||||
},
|
||||
ct);
|
||||
|
||||
|
||||
86
backend/src/Web/Features/Contents/Handlers/GetAlbum.cs
Normal file
86
backend/src/Web/Features/Contents/Handlers/GetAlbum.cs
Normal file
@@ -0,0 +1,86 @@
|
||||
using FastEndpoints;
|
||||
using JetBrains.Annotations;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Hutopy.Web.Features.Contents.Data;
|
||||
using Hutopy.Web.Common.Security;
|
||||
|
||||
namespace Hutopy.Web.Features.Contents.Handlers;
|
||||
|
||||
[PublicAPI]
|
||||
public record GetAlbumRequest(
|
||||
Guid AlbumId);
|
||||
|
||||
[PublicAPI]
|
||||
public record AlbumPhotoDto(
|
||||
Guid Id,
|
||||
string PhotoUrl,
|
||||
string? Caption,
|
||||
int Order,
|
||||
DateTimeOffset CreatedAt);
|
||||
|
||||
[PublicAPI]
|
||||
public record GetAlbumResponse(
|
||||
Guid Id,
|
||||
string Title,
|
||||
IReadOnlyList<AlbumPhotoDto> Photos,
|
||||
DateTimeOffset CreatedAt);
|
||||
|
||||
[PublicAPI]
|
||||
public sealed class GetAlbumRequestValidator : Validator<GetAlbumRequest>
|
||||
{
|
||||
public GetAlbumRequestValidator()
|
||||
{
|
||||
RuleFor(x => x.AlbumId)
|
||||
.NotNull()
|
||||
.NotEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
[PublicAPI]
|
||||
public class GetAlbumHandler(
|
||||
ContentDbContext context)
|
||||
: Endpoint<GetAlbumRequest, GetAlbumResponse>
|
||||
{
|
||||
public override void Configure()
|
||||
{
|
||||
Get("/api/albums/{AlbumId}");
|
||||
Options(o => o.WithTags("Albums"));
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(
|
||||
GetAlbumRequest request,
|
||||
CancellationToken ct)
|
||||
{
|
||||
var userId = User.GetUserId();
|
||||
|
||||
var album = await context
|
||||
.Albums
|
||||
.Include(a => a.Photos.OrderBy(p => p.Order))
|
||||
.SingleOrDefaultAsync(
|
||||
a => a.Id == request.AlbumId && a.CreatedBy == userId,
|
||||
cancellationToken: ct);
|
||||
|
||||
if (album is null)
|
||||
{
|
||||
await SendNotFoundAsync(ct);
|
||||
return;
|
||||
}
|
||||
|
||||
var photos = album.Photos
|
||||
.Select(p => new AlbumPhotoDto(
|
||||
p.Id,
|
||||
p.PhotoUrl,
|
||||
p.Caption,
|
||||
p.Order,
|
||||
p.CreatedAt))
|
||||
.ToList();
|
||||
|
||||
await SendOkAsync(
|
||||
new GetAlbumResponse(
|
||||
album.Id,
|
||||
album.Title,
|
||||
photos,
|
||||
album.CreatedAt),
|
||||
ct);
|
||||
}
|
||||
}
|
||||
@@ -32,7 +32,7 @@ public class GetContent(
|
||||
Id = c.Id,
|
||||
CreatedBy = c.CreatedBy,
|
||||
CreatedByName = c.Creator.Name,
|
||||
CreatedByPortraitUrl = c.Creator.Images.Logo,
|
||||
CreatedByPortraitUrl = c.Creator.PortraitUrl,
|
||||
CreatedAt = c.CreatedAt,
|
||||
DeletedBy = c.DeletedBy,
|
||||
DeletedAt = c.DeletedAt,
|
||||
|
||||
@@ -43,7 +43,7 @@ public class GetContentsByCreatorHandler(
|
||||
Id = c.Id,
|
||||
CreatedBy = c.CreatedBy,
|
||||
CreatedByName = c.Creator.Name,
|
||||
CreatedByPortraitUrl = c.Creator.Images.Logo,
|
||||
CreatedByPortraitUrl = c.Creator.PortraitUrl,
|
||||
CreatedAt = c.CreatedAt,
|
||||
DeletedBy = c.DeletedBy,
|
||||
DeletedAt = c.DeletedAt,
|
||||
|
||||
@@ -10,36 +10,23 @@ public sealed class GetCreatorBySlugRequest
|
||||
}
|
||||
|
||||
[PublicAPI]
|
||||
public class GetCreatorBySlugResponse(
|
||||
Guid id,
|
||||
Guid createdBy,
|
||||
DateTimeOffset createdAt,
|
||||
Guid? deletedBy,
|
||||
DateTimeOffset? deletedAt,
|
||||
bool isDeleted,
|
||||
bool verified,
|
||||
bool acceptDonation,
|
||||
string name,
|
||||
string slug,
|
||||
string? title,
|
||||
Socials socials,
|
||||
PresentationInfos presentationInfos,
|
||||
Images images)
|
||||
public record GetCreatorBySlugResponse
|
||||
{
|
||||
public Guid Id { get; } = id;
|
||||
public Guid CreatedBy { get; } = createdBy;
|
||||
public DateTimeOffset CreatedAt { get; } = createdAt;
|
||||
public Guid? DeletedBy { get; } = deletedBy;
|
||||
public DateTimeOffset? DeletedAt { get; } = deletedAt;
|
||||
public bool IsDeleted { get; } = isDeleted;
|
||||
public bool Verified { get; } = verified;
|
||||
public bool AcceptDonation { get; } = acceptDonation;
|
||||
public string Name { get; } = name;
|
||||
public string Slug { get; } = slug;
|
||||
public string? Title { get; } = title;
|
||||
public Socials Socials { get; } = socials;
|
||||
public PresentationInfos PresentationInfos { get; } = presentationInfos;
|
||||
public Images Images { get; } = images;
|
||||
public Guid Id { get; init; }
|
||||
public Guid CreatedBy { get; init; }
|
||||
public DateTimeOffset CreatedAt { get; init; }
|
||||
public Guid? DeletedBy { get; init; }
|
||||
public DateTimeOffset? DeletedAt { get; init; }
|
||||
public bool IsDeleted { get; init; }
|
||||
public bool Verified { get; init; }
|
||||
public bool AcceptDonation { get; init; }
|
||||
public string? BannerUrl { get; init; }
|
||||
public string? PortraitUrl { get; init; }
|
||||
public string Slug { get; init; }
|
||||
public string Name { get; init; }
|
||||
public string? Title { get; init; }
|
||||
public Socials Socials { get; init; }
|
||||
public Presentation Presentation { get; init; }
|
||||
}
|
||||
|
||||
[UsedImplicitly]
|
||||
@@ -72,45 +59,47 @@ public class GetCreatorBySlugHandler(
|
||||
{
|
||||
var creatorName = req.Name.ToLower();
|
||||
|
||||
var creator = await context
|
||||
var response = await context
|
||||
.Creators
|
||||
.IgnoreQueryFilters()
|
||||
.Where(c => EF.Functions.ILike(c.Slug, creatorName))
|
||||
.AsNoTracking()
|
||||
.Select(c => new GetCreatorBySlugResponse
|
||||
(
|
||||
c.Id,
|
||||
c.CreatedBy,
|
||||
c.CreatedAt,
|
||||
c.DeletedBy,
|
||||
c.DeletedAt,
|
||||
c.IsDeleted,
|
||||
c.Verified,
|
||||
c.AcceptDonation,
|
||||
c.Name,
|
||||
c.Slug,
|
||||
c.Title,
|
||||
c.Socials,
|
||||
c.PresentationInfos,
|
||||
c.Images))
|
||||
{
|
||||
Id = c.Id,
|
||||
CreatedBy = c.CreatedBy,
|
||||
CreatedAt = c.CreatedAt,
|
||||
DeletedBy = c.DeletedBy,
|
||||
DeletedAt = c.DeletedAt,
|
||||
IsDeleted = c.IsDeleted,
|
||||
Verified = c.Verified,
|
||||
AcceptDonation = c.AcceptDonation,
|
||||
BannerUrl = c.BannerUrl,
|
||||
PortraitUrl = c.PortraitUrl,
|
||||
Slug = c.Slug,
|
||||
Name = c.Name,
|
||||
Title = c.Title,
|
||||
Socials = c.Socials,
|
||||
Presentation = c.Presentation
|
||||
})
|
||||
.SingleOrDefaultAsync(ct);
|
||||
|
||||
if (creator is null)
|
||||
if (response is null)
|
||||
{
|
||||
await SendNotFoundAsync(ct);
|
||||
return;
|
||||
}
|
||||
|
||||
bool isOwner = User.Identity?.IsAuthenticated == true
|
||||
&& User.GetUserId() == creator.CreatedBy;
|
||||
&& User.GetUserId() == response.CreatedBy;
|
||||
|
||||
if (creator.IsDeleted && !isOwner)
|
||||
if (response.IsDeleted && !isOwner)
|
||||
{
|
||||
await SendNotFoundAsync(ct);
|
||||
}
|
||||
else
|
||||
{
|
||||
await SendAsync(creator, cancellation: ct);
|
||||
await SendAsync(response, cancellation: ct);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,8 +17,7 @@ public sealed class GetCreatorProfileResponse
|
||||
public string? Title { get; set; }
|
||||
public bool Verified { get; set; }
|
||||
public bool AcceptDonation { get; set; }
|
||||
public required Images Images { get; set; }
|
||||
public required PresentationInfos PresentationInfos { get; set; }
|
||||
public required Presentation Presentation { get; set; }
|
||||
public required Socials Socials { get; set; }
|
||||
}
|
||||
|
||||
@@ -54,8 +53,7 @@ public class GetCreatorProfileHandler(
|
||||
Title = c.Title,
|
||||
Verified = c.Verified,
|
||||
AcceptDonation = c.AcceptDonation,
|
||||
Images = c.Images,
|
||||
PresentationInfos = c.PresentationInfos,
|
||||
Presentation = c.Presentation,
|
||||
Socials = c.Socials,
|
||||
})
|
||||
.SingleOrDefaultAsync(ct);
|
||||
|
||||
@@ -42,7 +42,7 @@ public class GetFeaturedContentsHandler(
|
||||
Id = c.Id,
|
||||
CreatedBy = c.CreatedBy,
|
||||
CreatedByName = c.Creator.Name,
|
||||
CreatedByPortraitUrl = c.Creator.Images.Logo,
|
||||
CreatedByPortraitUrl = c.Creator.PortraitUrl,
|
||||
CreatedAt = c.CreatedAt,
|
||||
DeletedBy = c.DeletedBy,
|
||||
DeletedAt = c.DeletedAt,
|
||||
|
||||
69
backend/src/Web/Features/Contents/Handlers/RemoveAlbum.cs
Normal file
69
backend/src/Web/Features/Contents/Handlers/RemoveAlbum.cs
Normal file
@@ -0,0 +1,69 @@
|
||||
using FastEndpoints;
|
||||
using JetBrains.Annotations;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Hutopy.Web.Features.Contents.Data;
|
||||
using Hutopy.Web.Common.Security;
|
||||
|
||||
namespace Hutopy.Web.Features.Contents.Handlers;
|
||||
|
||||
[PublicAPI]
|
||||
public record RemoveAlbumRequest(
|
||||
Guid AlbumId);
|
||||
|
||||
[PublicAPI]
|
||||
public sealed class RemoveAlbumRequestValidator : Validator<RemoveAlbumRequest>
|
||||
{
|
||||
public RemoveAlbumRequestValidator()
|
||||
{
|
||||
RuleFor(x => x.AlbumId)
|
||||
.NotNull()
|
||||
.NotEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
[PublicAPI]
|
||||
public class RemoveAlbumHandler(
|
||||
ContentDbContext context)
|
||||
: Endpoint<RemoveAlbumRequest>
|
||||
{
|
||||
public override void Configure()
|
||||
{
|
||||
Delete("/api/albums/{AlbumId}");
|
||||
Options(o => o.WithTags("Albums"));
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(
|
||||
RemoveAlbumRequest request,
|
||||
CancellationToken ct)
|
||||
{
|
||||
var userId = User.GetUserId();
|
||||
|
||||
var album = await context
|
||||
.Albums
|
||||
.Include(a => a.Photos)
|
||||
.SingleOrDefaultAsync(
|
||||
a => a.Id == request.AlbumId && a.CreatedBy == userId,
|
||||
cancellationToken: ct);
|
||||
|
||||
if (album is null)
|
||||
{
|
||||
await SendNotFoundAsync(ct);
|
||||
return;
|
||||
}
|
||||
|
||||
// Soft delete the album
|
||||
album.DeletedBy = userId;
|
||||
album.DeletedAt = DateTimeOffset.UtcNow;
|
||||
|
||||
// Soft delete all photos in the album
|
||||
foreach (var photo in album.Photos)
|
||||
{
|
||||
photo.DeletedBy = userId;
|
||||
photo.DeletedAt = DateTimeOffset.UtcNow;
|
||||
}
|
||||
|
||||
await context.SaveChangesAsync(ct);
|
||||
|
||||
await SendNoContentAsync(ct);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
using FastEndpoints;
|
||||
using JetBrains.Annotations;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Hutopy.Web.Features.Contents.Data;
|
||||
using Hutopy.Web.Common.Security;
|
||||
|
||||
namespace Hutopy.Web.Features.Contents.Handlers;
|
||||
|
||||
[PublicAPI]
|
||||
public record RemovePhotoFromAlbumRequest(
|
||||
Guid AlbumId,
|
||||
Guid PhotoId);
|
||||
|
||||
[PublicAPI]
|
||||
public sealed class RemovePhotoFromAlbumRequestValidator : Validator<RemovePhotoFromAlbumRequest>
|
||||
{
|
||||
public RemovePhotoFromAlbumRequestValidator()
|
||||
{
|
||||
RuleFor(x => x.AlbumId)
|
||||
.NotNull()
|
||||
.NotEmpty();
|
||||
|
||||
RuleFor(x => x.PhotoId)
|
||||
.NotNull()
|
||||
.NotEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
[PublicAPI]
|
||||
public class RemovePhotoFromAlbumHandler(
|
||||
ContentDbContext context)
|
||||
: Endpoint<RemovePhotoFromAlbumRequest>
|
||||
{
|
||||
public override void Configure()
|
||||
{
|
||||
Delete("/api/albums/{AlbumId}/photos/{PhotoId}");
|
||||
Options(o => o.WithTags("Albums"));
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(
|
||||
RemovePhotoFromAlbumRequest request,
|
||||
CancellationToken ct)
|
||||
{
|
||||
var userId = User.GetUserId();
|
||||
|
||||
var album = await context
|
||||
.Albums
|
||||
.Include(a => a.Photos)
|
||||
.SingleOrDefaultAsync(
|
||||
a => a.Id == request.AlbumId && a.CreatedBy == userId,
|
||||
cancellationToken: ct);
|
||||
|
||||
if (album is null)
|
||||
{
|
||||
await SendNotFoundAsync(ct);
|
||||
return;
|
||||
}
|
||||
|
||||
var photo = album.Photos
|
||||
.SingleOrDefault(p => p.Id == request.PhotoId);
|
||||
|
||||
if (photo is null)
|
||||
{
|
||||
await SendNotFoundAsync(ct);
|
||||
return;
|
||||
}
|
||||
|
||||
// Soft delete the photo
|
||||
photo.DeletedBy = userId;
|
||||
photo.DeletedAt = DateTimeOffset.UtcNow;
|
||||
|
||||
await context.SaveChangesAsync(ct);
|
||||
|
||||
await SendNoContentAsync(ct);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user