Split Slug from Creator
This commit is contained in:
@@ -18,7 +18,8 @@ public class Creator
|
|||||||
|
|
||||||
public bool AcceptDonation { get; set; }
|
public bool AcceptDonation { get; set; }
|
||||||
public bool Verified { get; set; }
|
public bool Verified { get; set; }
|
||||||
public Slugs Slugs { get; set; } = null!;
|
[MaxLength(255)] public string Name { get; set; }
|
||||||
|
[MaxLength(128)] public string Slug { get; set; }
|
||||||
[MaxLength(255)] public string? Title { get; set; }
|
[MaxLength(255)] public string? Title { get; set; }
|
||||||
public Socials Socials { get; set; } = new();
|
public Socials Socials { get; set; } = new();
|
||||||
public Images Images { get; set; } = new();
|
public Images Images { get; set; } = new();
|
||||||
|
|||||||
382
backend/src/Web/Features/Contents/Data/Migrations/20250415071053_SplitSlugFromCreator.Designer.cs
generated
Normal file
382
backend/src/Web/Features/Contents/Data/Migrations/20250415071053_SplitSlugFromCreator.Designer.cs
generated
Normal file
@@ -0,0 +1,382 @@
|
|||||||
|
// <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("20250415071053_SplitSlugFromCreator")]
|
||||||
|
partial class SplitSlugFromCreator
|
||||||
|
{
|
||||||
|
/// <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<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("CreatedBy");
|
||||||
|
|
||||||
|
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<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>("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("CreatedBy");
|
||||||
|
|
||||||
|
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.Images", "Images", 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>("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.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("Images")
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("PresentationInfos")
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Socials")
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,111 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Hutopy.Web.Features.Contents.Data.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class SplitSlugFromCreator : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_Creators_Slugs_SlugsId",
|
||||||
|
schema: "Content",
|
||||||
|
table: "Creators");
|
||||||
|
|
||||||
|
migrationBuilder.DropIndex(
|
||||||
|
name: "IX_Creators_SlugsId",
|
||||||
|
schema: "Content",
|
||||||
|
table: "Creators");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "Active",
|
||||||
|
schema: "Content",
|
||||||
|
table: "Slugs");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "SlugsId",
|
||||||
|
schema: "Content",
|
||||||
|
table: "Creators");
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<Guid>(
|
||||||
|
name: "UsedBy",
|
||||||
|
schema: "Content",
|
||||||
|
table: "Slugs",
|
||||||
|
type: "uuid",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "Name",
|
||||||
|
schema: "Content",
|
||||||
|
table: "Creators",
|
||||||
|
type: "character varying(255)",
|
||||||
|
maxLength: 255,
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: "");
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "Slug",
|
||||||
|
schema: "Content",
|
||||||
|
table: "Creators",
|
||||||
|
type: "character varying(128)",
|
||||||
|
maxLength: 128,
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: "");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "UsedBy",
|
||||||
|
schema: "Content",
|
||||||
|
table: "Slugs");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "Name",
|
||||||
|
schema: "Content",
|
||||||
|
table: "Creators");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "Slug",
|
||||||
|
schema: "Content",
|
||||||
|
table: "Creators");
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<bool>(
|
||||||
|
name: "Active",
|
||||||
|
schema: "Content",
|
||||||
|
table: "Slugs",
|
||||||
|
type: "boolean",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: false);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<Guid>(
|
||||||
|
name: "SlugsId",
|
||||||
|
schema: "Content",
|
||||||
|
table: "Creators",
|
||||||
|
type: "uuid",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: new Guid("00000000-0000-0000-0000-000000000000"));
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Creators_SlugsId",
|
||||||
|
schema: "Content",
|
||||||
|
table: "Creators",
|
||||||
|
column: "SlugsId");
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_Creators_Slugs_SlugsId",
|
||||||
|
schema: "Content",
|
||||||
|
table: "Creators",
|
||||||
|
column: "SlugsId",
|
||||||
|
principalSchema: "Content",
|
||||||
|
principalTable: "Slugs",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -97,8 +97,15 @@ namespace Hutopy.Web.Features.Contents.Data.Migrations
|
|||||||
.HasColumnType("boolean")
|
.HasColumnType("boolean")
|
||||||
.HasComputedColumnSql("\"DeletedAt\" IS NOT NULL", true);
|
.HasComputedColumnSql("\"DeletedAt\" IS NOT NULL", true);
|
||||||
|
|
||||||
b.Property<Guid>("SlugsId")
|
b.Property<string>("Name")
|
||||||
.HasColumnType("uuid");
|
.IsRequired()
|
||||||
|
.HasMaxLength(255)
|
||||||
|
.HasColumnType("character varying(255)");
|
||||||
|
|
||||||
|
b.Property<string>("Slug")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(128)
|
||||||
|
.HasColumnType("character varying(128)");
|
||||||
|
|
||||||
b.Property<string>("Title")
|
b.Property<string>("Title")
|
||||||
.HasMaxLength(255)
|
.HasMaxLength(255)
|
||||||
@@ -109,8 +116,6 @@ namespace Hutopy.Web.Features.Contents.Data.Migrations
|
|||||||
|
|
||||||
b.HasKey("Id");
|
b.HasKey("Id");
|
||||||
|
|
||||||
b.HasIndex("SlugsId");
|
|
||||||
|
|
||||||
b.ToTable("Creators", "Content");
|
b.ToTable("Creators", "Content");
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -120,9 +125,6 @@ namespace Hutopy.Web.Features.Contents.Data.Migrations
|
|||||||
.ValueGeneratedOnAdd()
|
.ValueGeneratedOnAdd()
|
||||||
.HasColumnType("uuid");
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
b.Property<bool>("Active")
|
|
||||||
.HasColumnType("boolean");
|
|
||||||
|
|
||||||
b.Property<DateTimeOffset>("CreatedAt")
|
b.Property<DateTimeOffset>("CreatedAt")
|
||||||
.HasColumnType("timestamp with time zone");
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
@@ -144,6 +146,9 @@ namespace Hutopy.Web.Features.Contents.Data.Migrations
|
|||||||
b.Property<DateTimeOffset>("ReservedUntil")
|
b.Property<DateTimeOffset>("ReservedUntil")
|
||||||
.HasColumnType("timestamp with time zone");
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<Guid?>("UsedBy")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
b.HasKey("Id");
|
b.HasKey("Id");
|
||||||
|
|
||||||
b.HasIndex("NormalizedName")
|
b.HasIndex("NormalizedName")
|
||||||
@@ -195,12 +200,6 @@ namespace Hutopy.Web.Features.Contents.Data.Migrations
|
|||||||
|
|
||||||
modelBuilder.Entity("Hutopy.Web.Features.Contents.Data.Creator", b =>
|
modelBuilder.Entity("Hutopy.Web.Features.Contents.Data.Creator", b =>
|
||||||
{
|
{
|
||||||
b.HasOne("Hutopy.Web.Features.Contents.Data.Slugs", "Slugs")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("SlugsId")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired();
|
|
||||||
|
|
||||||
b.OwnsOne("Hutopy.Web.Features.Contents.Data.Images", "Images", b1 =>
|
b.OwnsOne("Hutopy.Web.Features.Contents.Data.Images", "Images", b1 =>
|
||||||
{
|
{
|
||||||
b1.Property<Guid>("CreatorId")
|
b1.Property<Guid>("CreatorId")
|
||||||
@@ -371,8 +370,6 @@ namespace Hutopy.Web.Features.Contents.Data.Migrations
|
|||||||
b.Navigation("PresentationInfos")
|
b.Navigation("PresentationInfos")
|
||||||
.IsRequired();
|
.IsRequired();
|
||||||
|
|
||||||
b.Navigation("Slugs");
|
|
||||||
|
|
||||||
b.Navigation("Socials")
|
b.Navigation("Socials")
|
||||||
.IsRequired();
|
.IsRequired();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ public class Slugs
|
|||||||
public Guid Id { get; set; }
|
public Guid Id { get; set; }
|
||||||
public Guid CreatedBy { get; set; }
|
public Guid CreatedBy { get; set; }
|
||||||
public DateTimeOffset CreatedAt { get; init; }
|
public DateTimeOffset CreatedAt { get; init; }
|
||||||
|
public Guid? UsedBy { get; set; }
|
||||||
[MaxLength(128)] public string Name { get; set; } = null!;
|
[MaxLength(128)] public string Name { get; set; } = null!;
|
||||||
[MaxLength(128)] public string NormalizedName { get; set; } = null!;
|
[MaxLength(128)] public string NormalizedName { get; set; } = null!;
|
||||||
public DateTimeOffset ReservedUntil { get; set; }
|
public DateTimeOffset ReservedUntil { get; set; }
|
||||||
public bool Active { get; set; }
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ public sealed class PostContentHtml(
|
|||||||
{
|
{
|
||||||
Id = c.Id,
|
Id = c.Id,
|
||||||
CreatedBy = c.CreatedBy,
|
CreatedBy = c.CreatedBy,
|
||||||
CreatedByName = c.Creator!.Slugs.Name,
|
CreatedByName = c.Creator.Name,
|
||||||
CreatedByPortraitUrl = c.Creator.Images.Logo,
|
CreatedByPortraitUrl = c.Creator.Images.Logo,
|
||||||
CreatedAt = c.CreatedAt,
|
CreatedAt = c.CreatedAt,
|
||||||
DeletedBy = c.DeletedBy,
|
DeletedBy = c.DeletedBy,
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ public sealed class CreateCreatorRequestValidator : Validator<CreateCreatorReque
|
|||||||
RuleFor(r => r.SlugReservationId)
|
RuleFor(r => r.SlugReservationId)
|
||||||
.NotNull()
|
.NotNull()
|
||||||
.NotEmpty()
|
.NotEmpty()
|
||||||
.WithMessage("You should specify a valid Name");
|
.WithMessage("You should specify a valid SlugReservationId");
|
||||||
|
|
||||||
RuleFor(r => r.CreatorId)
|
RuleFor(r => r.CreatorId)
|
||||||
.NotNull()
|
.NotNull()
|
||||||
@@ -48,7 +48,7 @@ public sealed class CreateCreatorHandler(
|
|||||||
.Slugs
|
.Slugs
|
||||||
.SingleAsync(s => s.Id == req.SlugReservationId, ct);
|
.SingleAsync(s => s.Id == req.SlugReservationId, ct);
|
||||||
|
|
||||||
if (slug.Active
|
if (slug.UsedBy is not null
|
||||||
|| slug.ReservedUntil < DateTimeOffset.UtcNow
|
|| slug.ReservedUntil < DateTimeOffset.UtcNow
|
||||||
|| slug.CreatedBy != User.GetUserId())
|
|| slug.CreatedBy != User.GetUserId())
|
||||||
{
|
{
|
||||||
@@ -56,14 +56,15 @@ public sealed class CreateCreatorHandler(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
slug.Active = true;
|
slug.UsedBy = req.CreatorId;
|
||||||
|
|
||||||
await context.Creators.AddAsync(
|
await context.Creators.AddAsync(
|
||||||
new Creator
|
new Creator
|
||||||
{
|
{
|
||||||
Id = req.CreatorId,
|
Id = req.CreatorId,
|
||||||
CreatedBy = User.GetUserId(),
|
CreatedBy = User.GetUserId(),
|
||||||
Slugs = slug
|
Name = slug.Name,
|
||||||
|
Slug = slug.NormalizedName,
|
||||||
},
|
},
|
||||||
ct);
|
ct);
|
||||||
|
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ public class GetContent(
|
|||||||
{
|
{
|
||||||
Id = c.Id,
|
Id = c.Id,
|
||||||
CreatedBy = c.CreatedBy,
|
CreatedBy = c.CreatedBy,
|
||||||
CreatedByName = c.Creator!.Slugs.Name,
|
CreatedByName = c.Creator.Name,
|
||||||
CreatedByPortraitUrl = c.Creator.Images.Logo,
|
CreatedByPortraitUrl = c.Creator.Images.Logo,
|
||||||
CreatedAt = c.CreatedAt,
|
CreatedAt = c.CreatedAt,
|
||||||
DeletedBy = c.DeletedBy,
|
DeletedBy = c.DeletedBy,
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ public class GetContentsByCreatorHandler(
|
|||||||
{
|
{
|
||||||
Id = c.Id,
|
Id = c.Id,
|
||||||
CreatedBy = c.CreatedBy,
|
CreatedBy = c.CreatedBy,
|
||||||
CreatedByName = c.Creator!.Slugs.Name,
|
CreatedByName = c.Creator.Name,
|
||||||
CreatedByPortraitUrl = c.Creator.Images.Logo,
|
CreatedByPortraitUrl = c.Creator.Images.Logo,
|
||||||
CreatedAt = c.CreatedAt,
|
CreatedAt = c.CreatedAt,
|
||||||
DeletedBy = c.DeletedBy,
|
DeletedBy = c.DeletedBy,
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ public class GetCreatorBySlugHandler(
|
|||||||
|
|
||||||
var creator = await context
|
var creator = await context
|
||||||
.Creators
|
.Creators
|
||||||
.Where(c => EF.Functions.ILike(c.Slugs.Name, creatorName))
|
.Where(c => EF.Functions.ILike(c.Slug, creatorName))
|
||||||
.AsNoTracking()
|
.AsNoTracking()
|
||||||
.Select(c => new GetCreatorBySlugResponse
|
.Select(c => new GetCreatorBySlugResponse
|
||||||
(
|
(
|
||||||
@@ -74,7 +74,7 @@ public class GetCreatorBySlugHandler(
|
|||||||
c.CreatedAt,
|
c.CreatedAt,
|
||||||
c.Verified,
|
c.Verified,
|
||||||
c.AcceptDonation,
|
c.AcceptDonation,
|
||||||
c.Slugs.NormalizedName,
|
c.Name,
|
||||||
c.Title,
|
c.Title,
|
||||||
c.Socials,
|
c.Socials,
|
||||||
c.PresentationInfos,
|
c.PresentationInfos,
|
||||||
|
|||||||
@@ -42,8 +42,8 @@ public class GetCreatorProfileHandler(
|
|||||||
Id = c.Id,
|
Id = c.Id,
|
||||||
CreatedBy = c.CreatedBy,
|
CreatedBy = c.CreatedBy,
|
||||||
CreatedAt = c.CreatedAt,
|
CreatedAt = c.CreatedAt,
|
||||||
|
Name = c.Name,
|
||||||
Title = c.Title,
|
Title = c.Title,
|
||||||
Name = c.Slugs.NormalizedName,
|
|
||||||
Verified = c.Verified,
|
Verified = c.Verified,
|
||||||
AcceptDonation = c.AcceptDonation,
|
AcceptDonation = c.AcceptDonation,
|
||||||
Images = c.Images,
|
Images = c.Images,
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ public class GetFeaturedContentsHandler(
|
|||||||
{
|
{
|
||||||
Id = c.Id,
|
Id = c.Id,
|
||||||
CreatedBy = c.CreatedBy,
|
CreatedBy = c.CreatedBy,
|
||||||
CreatedByName = c.Creator!.Slugs.Name,
|
CreatedByName = c.Creator.Name,
|
||||||
CreatedByPortraitUrl = c.Creator.Images.Logo,
|
CreatedByPortraitUrl = c.Creator.Images.Logo,
|
||||||
CreatedAt = c.CreatedAt,
|
CreatedAt = c.CreatedAt,
|
||||||
DeletedBy = c.DeletedBy,
|
DeletedBy = c.DeletedBy,
|
||||||
|
|||||||
@@ -40,7 +40,6 @@ public sealed class RemoveCreatorHandler(
|
|||||||
{
|
{
|
||||||
var creator = await context
|
var creator = await context
|
||||||
.Creators
|
.Creators
|
||||||
.Include(c => c.Slugs)
|
|
||||||
.Where(c => c.Id == req.CreatorId)
|
.Where(c => c.Id == req.CreatorId)
|
||||||
.SingleOrDefaultAsync(cancellationToken: ct);
|
.SingleOrDefaultAsync(cancellationToken: ct);
|
||||||
|
|
||||||
@@ -52,8 +51,6 @@ public sealed class RemoveCreatorHandler(
|
|||||||
|
|
||||||
creator.DeletedAt = DateTimeOffset.UtcNow;
|
creator.DeletedAt = DateTimeOffset.UtcNow;
|
||||||
creator.DeletedBy = User.GetUserId();
|
creator.DeletedBy = User.GetUserId();
|
||||||
|
|
||||||
creator.Slugs.Active = false;
|
|
||||||
|
|
||||||
await context.SaveChangesAsync(ct);
|
await context.SaveChangesAsync(ct);
|
||||||
|
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ namespace Hutopy.Web.Features.Contents.Handlers;
|
|||||||
[PublicAPI]
|
[PublicAPI]
|
||||||
public record ReserveSlugRequest
|
public record ReserveSlugRequest
|
||||||
{
|
{
|
||||||
public string Slug { get; set; } = null!;
|
|
||||||
public required Guid ReservationId { get; set; }
|
public required Guid ReservationId { get; set; }
|
||||||
|
public string Slug { get; set; } = null!;
|
||||||
}
|
}
|
||||||
|
|
||||||
[PublicAPI]
|
[PublicAPI]
|
||||||
@@ -46,17 +46,26 @@ public sealed class ReserveSlug(
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await context.Slugs.AddAsync(
|
var reservation = await context.Slugs.FirstOrDefaultAsync(
|
||||||
new Slugs
|
s => s.Id == req.ReservationId && s.CreatedBy == User.GetUserId(),
|
||||||
{
|
|
||||||
Id = req.ReservationId,
|
|
||||||
Active = false,
|
|
||||||
Name = req.Slug,
|
|
||||||
ReservedUntil = DateTimeOffset.UtcNow + opts.Value.SlugReservationDuration,
|
|
||||||
CreatedBy = User.GetUserId(),
|
|
||||||
},
|
|
||||||
cancellationToken: ct);
|
cancellationToken: ct);
|
||||||
|
|
||||||
|
if (reservation == null)
|
||||||
|
{
|
||||||
|
reservation = new Slugs
|
||||||
|
{
|
||||||
|
Id = req.ReservationId,
|
||||||
|
CreatedBy = User.GetUserId(),
|
||||||
|
CreatedAt = DateTimeOffset.UtcNow,
|
||||||
|
};
|
||||||
|
|
||||||
|
context.Slugs.Attach(reservation);
|
||||||
|
context.Entry(reservation).State = EntityState.Added;
|
||||||
|
}
|
||||||
|
|
||||||
|
reservation.Name = req.Slug;
|
||||||
|
reservation.ReservedUntil = DateTimeOffset.UtcNow + opts.Value.SlugReservationDuration;
|
||||||
|
|
||||||
await context.SaveChangesAsync(ct);
|
await context.SaveChangesAsync(ct);
|
||||||
|
|
||||||
await transaction.CommitAsync(ct);
|
await transaction.CommitAsync(ct);
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ const creatorProfileStore = useCreatorProfileStore();
|
|||||||
const userProfileStore = useUserProfileStore();
|
const userProfileStore = useUserProfileStore();
|
||||||
|
|
||||||
function handleCreatorNameReservationIdChanged($event) {
|
function handleCreatorNameReservationIdChanged($event) {
|
||||||
creatorNameReservationId.value = $event.value
|
creatorNameReservationId.value = $event
|
||||||
}
|
}
|
||||||
|
|
||||||
function cancel () {
|
function cancel () {
|
||||||
@@ -70,7 +70,7 @@ async function createAccount() {
|
|||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
<name-editor
|
<name-editor
|
||||||
v-model:name="creatorName"
|
v-model:name="creatorName"
|
||||||
creator-name-reservation-id="creatorNameDirty"
|
creator-name-reservation-id="creatorNameReservationId"
|
||||||
@update:creator-name-reservation-id="handleCreatorNameReservationIdChanged($event)"
|
@update:creator-name-reservation-id="handleCreatorNameReservationIdChanged($event)"
|
||||||
></name-editor>
|
></name-editor>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ const isReserved = computed(() => reservationState.value === 'reserved');
|
|||||||
|
|
||||||
const isOperationPending = ref(false);
|
const isOperationPending = ref(false);
|
||||||
const reservationState = ref(null);
|
const reservationState = ref(null);
|
||||||
const reservationId = ref(null);
|
const reservationId = ref(v7());
|
||||||
|
|
||||||
let timeout = null;
|
let timeout = null;
|
||||||
const handleInput = () => {
|
const handleInput = () => {
|
||||||
@@ -40,21 +40,19 @@ const checkNameAvailability = async () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const id = v7();
|
|
||||||
isOperationPending.value = true;
|
isOperationPending.value = true;
|
||||||
reservationState.value = "loading";
|
reservationState.value = "loading";
|
||||||
await client.post(
|
await client.post(
|
||||||
`/api/creators/@${encodeURIComponent(name.value)}/reserve`,
|
`/api/creators/@${encodeURIComponent(name.value)}/reserve`,
|
||||||
{reservationId: id}
|
{reservationId: reservationId.value}
|
||||||
);
|
);
|
||||||
reservationState.value = "reserved";
|
reservationState.value = "reserved";
|
||||||
reservationId.value = id;
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
reservationState.value = "unavailable"; // Handle API failure case
|
reservationState.value = "unavailable"; // Handle API failure case
|
||||||
reservationId.value = undefined;
|
reservationId.value = undefined;
|
||||||
} finally {
|
} finally {
|
||||||
emits('update:name', name);
|
emits('update:name', name.value);
|
||||||
emits('update:creatorNameReservationId', reservationId);
|
emits('update:creatorNameReservationId', reservationId.value);
|
||||||
isOperationPending.value = false;
|
isOperationPending.value = false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user