many fixes and improvements - rework for modules/ and common/

feat(emailer): add Postmark and Resend providers
This commit is contained in:
2025-06-06 12:21:43 -04:00
parent 31ba18fa8d
commit 25b94d3e02
313 changed files with 6586 additions and 18260 deletions

View File

@@ -1,12 +0,0 @@
{
"version": 1,
"isRoot": true,
"tools": {
"dotnet-ef": {
"version": "9.0.3",
"commands": [
"dotnet-ef"
]
}
}
}

View File

@@ -1,147 +0,0 @@
using Azure;
using Azure.Storage.Blobs;
using Azure.Storage.Blobs.Models;
namespace Hutopy.Web.Common.BlobStorage;
public class AzureBlobStorage
{
private const long MaxUploadSize = 10 * 1024 * 1024; // 10 MB in bytes
private readonly BlobServiceClient _blobServiceClient;
private readonly ILogger<AzureBlobStorage> _logger;
public AzureBlobStorage(IConfiguration configuration, ILogger<AzureBlobStorage> logger)
{
_logger = logger;
var connectionString = configuration.GetConnectionString("AzureBlob");
_blobServiceClient = new BlobServiceClient(connectionString);
}
/// <summary>
/// Upload a file to microsoft azure blob storage.
/// </summary>
/// <param name="containerName">The name of the container where the file is stored.</param>
/// <param name="blobName">The blob name (path within the container, include the file name).</param>
/// <param name="stream"></param>
/// <param name="contentType">The content type.</param>
/// <param name="ct">The cancellation token</param>
/// <returns></returns>
public async Task<string> UploadFileAsync(string containerName, string blobName, Stream stream,
string contentType, CancellationToken ct = default)
{
// Read the file stream into a memory stream to determine the length
// WATCH FOR MEMORY USAGE USING THE MEMORY STREAM.
stream.Position = 0;
// Check if the file size exceeds the maximum upload size
if (stream.Length > MaxUploadSize)
{
_logger.LogError(
$"Blob storage: File size exceeds the maximum allowed size of {MaxUploadSize} bytes.");
throw new InvalidOperationException(
$"Blob storage: File size exceeds the maximum allowed size of {MaxUploadSize} bytes.");
}
// Validate content type
if (!ContentTypes.IsAllowed(contentType, stream))
{
_logger.LogError(
$"Blob storage: Unsupported file type {contentType}.");
throw new InvalidOperationException("Unsupported file type.");
}
try
{
// Get a reference to a container
var containerClient = _blobServiceClient.GetBlobContainerClient(containerName);
// Create the container if it does not exist
await containerClient.CreateIfNotExistsAsync(
PublicAccessType.Blob,
cancellationToken: ct);
// Get a reference to a blob
var blobClient = containerClient.GetBlobClient(blobName);
// Define the BlobHttpHeaders to include the content type
var blobHttpHeaders = new BlobHttpHeaders { ContentType = contentType };
// Upload the file
var response = await blobClient.UploadAsync(
stream,
new BlobUploadOptions { HttpHeaders = blobHttpHeaders },
ct);
var fileUri = blobClient.Uri.ToString();
_logger.LogInformation(
"""
Blob storage: Status [ {ResponseStatus} ]
Uploaded [ {BlobName} ] to the container [ {ContainerName} ]
with contentType [ {ContentType} ]
with a length of [ {StreamLength} bytes ]
with the uri [ {FileUri} ]
""",
response.GetRawResponse().Status.ToString(),
blobName,
containerName,
contentType,
stream.Length,
fileUri
);
// Return the URI of the uploaded blob
return fileUri;
}
catch (RequestFailedException ex)
{
_logger.LogError($"Blob storage: Azure Storage request failed: {ex.Message}");
throw;
}
catch (Exception ex)
{
_logger.LogError($"Blob storage: An error occurred: {ex.Message}");
throw;
}
}
/// <summary>
/// Download a file to microsoft's azure blob storage.
/// </summary>
/// <param name="blobName">The blob name (path within the container).</param>
/// <param name="containerName">The name of the container where the file is stored. (users)</param>
/// <param name="ct">The cancellation token for the request</param>
/// <returns></returns>
public async Task<MemoryStream> DownloadFileAsync(string containerName, string blobName,
CancellationToken ct = default)
{
try
{
// Get a reference to a container
var containerClient = _blobServiceClient.GetBlobContainerClient(containerName);
// Get a reference to a blob
var blobClient = containerClient.GetBlobClient(blobName);
// Download the blob to a stream
BlobDownloadInfo download = await blobClient.DownloadAsync(ct);
MemoryStream memoryStream = new();
await download.Content.CopyToAsync(memoryStream, ct);
memoryStream.Position = 0; // Ensure the stream is at the beginning
return memoryStream;
}
catch (RequestFailedException ex)
{
_logger.LogError($"Azure Storage request failed: {ex.Message}");
throw;
}
catch (Exception ex)
{
_logger.LogError($"An error occurred: {ex.Message}");
throw;
}
}
}

View File

@@ -1,33 +0,0 @@
users/
├── userId1/
│ ├── profile/
│ │ └── profilePicture.jpg
│ │ └── data.json
│ │
│ ├── posts/
│ │ ├── post1/
│ │ │ ├── image1.jpg
│ │ │ ├── video1.mp4
│ │ │ └── audio1.mp3
│ │ ├── post2/
│ │ │ ├── image2.jpg
│ │ │ └── video2.mp4
│ │ └── ...
├── userId2/
│ ├── profile/
│ │ └── profilePicture.jpg
│ │ └── data.json
│ │
│ ├── posts/
│ │ ├── post1/
│ │ │ ├── image1.jpg
│ │ │ ├── video1.mp4
│ │ │ └── audio1.mp3
│ │ ├── post2/
│ │ │ ├── image2.jpg
│ │ │ └── video2.mp4
│ │ └── ...
└── ...

View File

@@ -1,7 +0,0 @@
namespace Hutopy.Web.Common.BlobStorage;
public static class CommonFileNames
{
public static string ProfilePicture = "profilePicture";
public static string BannerPicture = "bannerPicture";
}

View File

@@ -1,7 +0,0 @@
namespace Hutopy.Web.Common.BlobStorage;
public static class ContainerNames
{
public const string Users = "users";
public const string Creators = "creators";
}

View File

@@ -1,49 +0,0 @@
using System.Text;
namespace Hutopy.Web.Common.BlobStorage;
public static class ContentTypes
{
private const string ImagePng = "image/png";
private const string ImageJpeg = "image/jpeg";
private const string ImageJpg = "image/jpg";
private const string TextHtml = "text/html";
private static readonly HashSet<string> AllowedContentTypes = [ImagePng, ImageJpeg, ImageJpg, TextHtml];
public static bool IsAllowed(
string contentType,
Stream fileStream)
{
return IsValidFileType(fileStream) && AllowedContentTypes.Contains(contentType);
}
private static bool IsValidFileType(
Stream fileStream)
{
byte[] buffer = new byte[512];
_ = fileStream.Read(buffer, 0, buffer.Length);
fileStream.Position = 0;
// PNG file signature: 89 50 4E 47 (in hex)
if (buffer[0] == 0x89 && buffer[1] == 0x50 && buffer[2] == 0x4E && buffer[3] == 0x47)
{
return true;
}
// JPEG file signature: FF D8 FF (in hex)
if (buffer[0] == 0xFF && buffer[1] == 0xD8 && buffer[2] == 0xFF)
{
return true;
}
// Check for HTML content by looking for "<!DOCTYPE html>" or "<html>" tags
string content = Encoding.UTF8.GetString(buffer);
if (content.Contains("<!DOCTYPE html>"))
{
return true;
}
return false;
}
}

View File

@@ -1,8 +0,0 @@
namespace Hutopy.Web.Common.BlobStorage;
public static class SubDirectoryNames
{
public static string Profile = "profile";
public static string Contents = "contents";
public static string Albums = "albums";
}

View File

@@ -1,94 +0,0 @@
namespace Hutopy.Web.Common;
/// <summary>
/// Adapted from https://raw.githubusercontent.com/uuidjs/uuid/main/src/v7.ts.
/// to match the uuid v7 generated on the client
/// </summary>
public static class GuidHelper
{
private class V7State
{
public long Msecs { get; set; } = long.MinValue;
public int Seq { get; set; }
}
private static readonly V7State State = new();
private static readonly Random Random = new();
public static Guid GenerateUuidV7()
{
byte[] randomValues = new byte[16];
Random.NextBytes(randomValues);
UpdateV7State(
State,
DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
randomValues);
var values = V7Bytes(randomValues, State.Msecs, State.Seq);
return new Guid(values);
}
private static void UpdateV7State(V7State state, long now, byte[] randomBytes)
{
if (now > state.Msecs)
{
state.Seq = (randomBytes[6] << 23) | (randomBytes[7] << 16) | (randomBytes[8] << 8) | randomBytes[9];
state.Msecs = now;
}
else
{
state.Seq = (state.Seq + 1) | 0;
if (state.Seq == 0)
{
state.Msecs++;
}
}
}
private static byte[] V7Bytes(byte[] randomBytes, long? msecs = null, int? seq = null, byte[]? buf = null, int offset = 0)
{
if (buf == null)
{
buf = new byte[16];
offset = 0;
}
// Defaults
msecs ??= DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
seq ??= ((randomBytes[6] & 0x7f) << 24) | (randomBytes[7] << 16) | (randomBytes[8] << 8) | randomBytes[9];
// byte 0-5: timestamp (48 bits)
buf[offset++] = (byte)((msecs.Value / 0x10000000000) & 0xff);
buf[offset++] = (byte)((msecs.Value / 0x100000000) & 0xff);
buf[offset++] = (byte)((msecs.Value / 0x1000000) & 0xff);
buf[offset++] = (byte)((msecs.Value / 0x10000) & 0xff);
buf[offset++] = (byte)((msecs.Value / 0x100) & 0xff);
buf[offset++] = (byte)(msecs.Value & 0xff);
// byte 6: `version` (4 bits) | sequence bits 28-31 (4 bits)
buf[offset++] = (byte)(0x70 | ((seq.Value >> 28) & 0x0f));
// byte 7: sequence bits 20-27 (8 bits)
buf[offset++] = (byte)((seq.Value >> 20) & 0xff);
// byte 8: `variant` (2 bits) | sequence bits 14-19 (6 bits)
buf[offset++] = (byte)(0x80 | ((seq.Value >> 14) & 0x3f));
// byte 9: sequence bits 6-13 (8 bits)
buf[offset++] = (byte)((seq.Value >> 6) & 0xff);
// byte 10: sequence bits 0-5 (6 bits) | random (2 bits)
buf[offset++] = (byte)(((seq.Value << 2) & 0xff) | (randomBytes[10] & 0x03));
// bytes 11-15: random (40 bits)
buf[offset++] = randomBytes[11];
buf[offset++] = randomBytes[12];
buf[offset++] = randomBytes[13];
buf[offset++] = randomBytes[14];
buf[offset] = randomBytes[15];
return buf;
}
}

View File

@@ -1,63 +0,0 @@
using System.Security.Claims;
namespace Hutopy.Web.Common.Security;
public static class ClaimsPrincipalExtensions
{
public static Guid GetUserId(this ClaimsPrincipal claims)
{
return (Guid)claims.GetRequiredClaim<Guid>(ClaimTypes.NameIdentifier);
}
public static string GetName(this ClaimsPrincipal claims)
{
return (string)claims.GetRequiredClaim<string>(ClaimTypes.Name);
}
public static string? GetAlias(this ClaimsPrincipal claims)
{
return (string?)claims.GetClaim<string?>(KnownClaims.Alias);
}
public static string? GetPortraitUrl(this ClaimsPrincipal claims)
{
return (string?)claims.GetClaim<string?>(KnownClaims.PortraitUrl);
}
public static string GetFirstName(this ClaimsPrincipal claims)
{
return (string)claims.GetRequiredClaim<string>(ClaimTypes.GivenName);
}
public static string GetLastName(this ClaimsPrincipal claims)
{
return (string)claims.GetRequiredClaim<string>(ClaimTypes.Surname);
}
public static string GetEmail(this ClaimsPrincipal claims)
{
return (string)claims.GetRequiredClaim<string>(ClaimTypes.Email);
}
private static object? GetClaim<TValue>(this ClaimsPrincipal claims, string key)
{
var claim = claims.FindFirst(key);
if (claim is null) return default;
return claims.GetRequiredClaim<TValue>(key);
}
private static object GetRequiredClaim<TValue>(this ClaimsPrincipal claims, string key)
{
var claim = claims.FindFirst(key);
if (claim is null) throw new MissingClaimException(key);
if (typeof(TValue) == typeof(Guid))
{
return Guid.Parse(claim.Value);
}
return Convert.ChangeType(claim.Value, typeof(TValue));
}
}

View File

@@ -1,53 +0,0 @@
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using Microsoft.IdentityModel.Tokens;
namespace Hutopy.Web.Common.Security;
public static class JwtTokenHelper
{
public static string GenerateJwtToken(
TimeSpan expiresIn,
string issuer,
string audience,
string key,
string userId,
string email,
string? alias,
string firstname,
string lastname,
string? portraitUrl)
{
var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(key));
var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);
var claims = new List<Claim>(new[]
{
new Claim(JwtRegisteredClaimNames.Sub, userId),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
new Claim(ClaimTypes.NameIdentifier, userId), new Claim(ClaimTypes.Email, email),
new Claim(ClaimTypes.Name, email), new Claim(ClaimTypes.GivenName, firstname),
new Claim(ClaimTypes.Surname, lastname)
});
if (alias is not null)
{
claims.Add(new(KnownClaims.Alias, alias));
}
if (portraitUrl is not null)
{
claims.Add(new(KnownClaims.PortraitUrl, portraitUrl));
}
var token = new JwtSecurityToken(
issuer: issuer,
audience: audience,
claims: claims,
expires: DateTime.Now.Add(expiresIn),
signingCredentials: credentials);
return new JwtSecurityTokenHandler().WriteToken(token);
}
}

View File

@@ -1,7 +0,0 @@
namespace Hutopy.Web.Common.Security;
public static class KnownClaims
{
public const string Alias = "alias";
public const string PortraitUrl = "portraitUrl";
}

View File

@@ -1,5 +0,0 @@
namespace Hutopy.Web.Common.Security;
public class MissingClaimException(
string claimName)
: Exception;

View File

@@ -1,76 +0,0 @@
using System.Security.Cryptography;
using System.Text;
namespace Hutopy.Web.Common.Security;
// If we need to add special characters we can alternate between 2 pools.
public static class PasswordGenerator
{
private const string LowerLetters = "abcdefghijklmnopqrstuvwxyz";
private const string UpperLetters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
private const string Numbers = "0123456789";
private const string SpecialCharacters = "!@#$%^&*()_+-=[];',./`~{}|:\"<>?";
private static readonly Random Random = new();
public static string Next(
int length = 15,
bool requireNumber = true,
bool requireLowercase = true,
bool requireCapital = true,
bool requireSpecialCharacter = true)
{
// Create pools based on the requirements
var characterPool = new StringBuilder();
if (requireNumber)
characterPool.Append(LowerLetters);
if (requireCapital)
characterPool.Append(UpperLetters);
if (requireNumber)
characterPool.Append(Numbers);
if (requireSpecialCharacter)
characterPool.Append(SpecialCharacters);
// Ensure that the length is within the specified bounds
var password = new char[length];
// Ensure at least one character from each required category is included
int index = 0;
if (requireLowercase)
password[index++] = LowerLetters[Random.Next(LowerLetters.Length)];
if (requireCapital)
password[index++] = UpperLetters[Random.Next(UpperLetters.Length)];
if (requireNumber)
password[index++] = Numbers[Random.Next(Numbers.Length)];
if (requireSpecialCharacter)
password[index++] = SpecialCharacters[Random.Next(SpecialCharacters.Length)];
// Fill the rest with the password
for (int i = index; i < length; i++)
{
password[i] = characterPool[RandomNumberGenerator.GetInt32(characterPool.Length)];
}
// Shuffle the password to randomize the placement of the required characters
Shuffle(password);
return new string(password);
}
private static void Shuffle(
char[] array)
{
for (int i = array.Length - 1; i > 0; i--)
{
int j = Random.Next(i + 1);
(array[i], array[j]) = (array[j], array[i]); // Swap elements
}
}
}

View File

@@ -1,14 +0,0 @@
using System.Security.Cryptography;
namespace Hutopy.Web.Common.Security;
public static class RefreshTokenGenerator
{
public static string Next()
{
var randomNumber = new byte[32];
using var rng = RandomNumberGenerator.Create();
rng.GetBytes(randomNumber);
return Convert.ToBase64String(randomNumber);
}
}

View File

@@ -1,64 +0,0 @@
using System.Text.RegularExpressions;
namespace Hutopy.Web.Common.YouTube;
public static class YouTubeUrlHelper
{
private static readonly Regex VideoIdRegex = new(
@"(?:youtube\.com/(?:[^/]+/.+/|(?:v|e(?:mbed)?)/|.*[?&]v=)|youtu\.be/)([^""&?/\s]{11})",
RegexOptions.Compiled | RegexOptions.IgnoreCase);
private static readonly Regex ShortUrlRegex = new(
@"^[a-zA-Z0-9_-]{11}$",
RegexOptions.Compiled);
/// <summary>
/// Extracts the video ID from a YouTube URL or returns the input if it's already a video ID.
/// </summary>
/// <param name="input">The YouTube URL or video ID</param>
/// <returns>The extracted video ID or null if invalid</returns>
public static string? ExtractVideoId(string? input)
{
if (string.IsNullOrWhiteSpace(input))
return null;
// If it's already a valid video ID, return it
if (IsValidVideoId(input))
return input;
// Try to extract video ID from URL
var match = VideoIdRegex.Match(input);
return match.Success ? match.Groups[1].Value : null;
}
/// <summary>
/// Validates if the input is a valid YouTube video ID.
/// </summary>
/// <param name="input">The video ID to validate</param>
/// <returns>True if the input is a valid video ID</returns>
public static bool IsValidVideoId(string? input)
{
if (string.IsNullOrWhiteSpace(input))
return false;
return ShortUrlRegex.IsMatch(input);
}
/// <summary>
/// Validates if the input is a valid YouTube URL or video ID.
/// </summary>
/// <param name="input">The URL or video ID to validate</param>
/// <returns>True if the input is a valid YouTube URL or video ID</returns>
public static bool IsValidYouTubeUrlOrId(string? input)
{
if (string.IsNullOrWhiteSpace(input))
return false;
// Check if it's a valid video ID
if (IsValidVideoId(input))
return true;
// Check if it's a valid YouTube URL
return VideoIdRegex.IsMatch(input);
}
}

View File

@@ -1,90 +0,0 @@
using System.Text;
using Azure.Identity;
using Hutopy.Web.Features.Users.Data;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.Facebook;
using Microsoft.AspNetCore.Authentication.Google;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Mvc;
using Microsoft.IdentityModel.Tokens;
namespace Hutopy.Web;
public static class DependencyInjection
{
public static IServiceCollection AddWebServices(this IServiceCollection services)
{
services.AddDatabaseDeveloperPageExceptionFilter();
services.AddHttpContextAccessor();
services.AddHealthChecks()
.AddDbContextCheck<ApplicationDbContext>();
services.AddHttpClient();
// Customise default API behaviour
services.Configure<ApiBehaviorOptions>(options =>
options.SuppressModelStateInvalidFilter = true);
services.AddEndpointsApiExplorer();
return services;
}
public static IServiceCollection AddAuthorizationAndAuthentication(this IServiceCollection services,
ConfigurationManager configuration)
{
var authenticationBuilder = services
.AddAuthentication(options =>
{
options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
});
var authJwt = configuration.GetSection("Authentication:Jwt");
if (authJwt.Exists())
{
authenticationBuilder.AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, jwtBearerOptions =>
{
jwtBearerOptions.Authority = "https://hutopy.com";
jwtBearerOptions.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidIssuer = authJwt["Issuer"],
ValidateAudience = true,
ValidAudience = authJwt["Audience"],
ValidateLifetime = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(authJwt["Key"] ??
throw new ArgumentNullException("The Jwt Key is missing.")))
};
});
}
var authGoogle = configuration.GetSection("Authentication:Google");
if (authGoogle.Exists())
{
authenticationBuilder.AddGoogle(GoogleDefaults.AuthenticationScheme, options =>
{
options.ClientId = authGoogle["ClientId"] ??
throw new ArgumentNullException("The Google ClientId is missing.");
options.ClientSecret = authGoogle["ClientSecret"] ??
throw new ArgumentNullException("The Google ClientSecret is missing.");
});
}
var authFacebook = configuration.GetSection("Authentication:Facebook");
if (authFacebook.Exists())
{
authenticationBuilder.AddFacebook(FacebookDefaults.AuthenticationScheme, options =>
{
options.ClientId = authFacebook["ClientId"] ??
throw new ArgumentNullException("The Facebook ClientId is missing.");
options.ClientSecret = authFacebook["ClientSecret"] ??
throw new ArgumentNullException("The Facebook ClientSecret is missing.");
});
}
return services;
}
}

View File

@@ -1,31 +0,0 @@
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 OriginalUrl { get; set; }
[MaxLength(2048)] public required string ThumbnailUrl { get; set; }
[MaxLength(255)] public string? Caption { get; set; }
public int Order { get; set; }
}

View File

@@ -1,22 +0,0 @@
using System.ComponentModel.DataAnnotations;
namespace Hutopy.Web.Features.Contents.Data;
public class Content
{
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 Guid CreatorId { get; set; }
public Creator Creator { get; init; } = null!;
[MaxLength(128)] public required string Title { get; set; }
[MaxLength(2048)] public string? ThumbnailUrl { get; set; } = "";
[MaxLength(2048)] public string Description { get; set; } = "";
[MaxLength(2048)] public string? HtmlFileUrl { get; set; } = "";
public IList<ContentReaction> Reactions { get; set; } = new List<ContentReaction>();
public string[]? Urls { get; init; }
}

View File

@@ -1,113 +0,0 @@
namespace Hutopy.Web.Features.Contents.Data;
public class ContentDbContext(
DbContextOptions<ContentDbContext> options)
: DbContext(options)
{
public const string SchemaName = "Content";
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)
{
modelBuilder.HasDefaultSchema(SchemaName);
modelBuilder
.Entity<Content>()
.Property(c => c.CreatedAt)
.ValueGeneratedOnAdd()
.HasDefaultValueSql("CURRENT_TIMESTAMP");
modelBuilder
.Entity<Content>()
.HasOne(c => c.Creator)
.WithMany()
.HasForeignKey(c => c.CreatorId)
.IsRequired(false);
modelBuilder
.Entity<Content>()
.OwnsMany(c => c.Reactions)
.ToTable("Reactions");
modelBuilder
.Entity<Content>()
.Property(c => c.ThumbnailUrl);
modelBuilder
.Entity<Slugs>()
.Property(x => x.NormalizedName)
.HasComputedColumnSql("LOWER( \"Content\".\"Slugs\".\"Name\")", stored: true);
modelBuilder
.Entity<Slugs>()
.HasIndex(x => x.NormalizedName)
.IsUnique();
modelBuilder
.Entity<Creator>()
.Property(c => c.IsDeleted)
.HasComputedColumnSql("\"DeletedAt\" IS NOT NULL", stored: true); // bool
modelBuilder
.Entity<Creator>()
.OwnsOne<Socials>(x => x.Socials)
.ToTable(nameof(Socials));
modelBuilder
.Entity<Creator>()
.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);
}
}

View File

@@ -1,32 +0,0 @@
namespace Hutopy.Web.Features.Contents.Data;
public static class InitializerExtensions
{
public static async Task InitialiseContentDbContextAsync(this WebApplication app)
{
using var scope = app.Services.CreateScope();
var initializer = scope.ServiceProvider.GetRequiredService<ContentDbContextInitializer>();
await initializer.InitialiseAsync();
}
}
public class ContentDbContextInitializer(
ILogger<ContentDbContextInitializer> logger,
ContentDbContext context
)
{
public async Task InitialiseAsync()
{
try
{
await context.Database.MigrateAsync();
}
catch (Exception ex)
{
logger.LogError(ex, "An error occurred while initialising the content database.");
throw;
}
}
}

View File

@@ -1,11 +0,0 @@
using System.ComponentModel.DataAnnotations;
using Hutopy.Web.Features.Contents.Data.Enums;
namespace Hutopy.Web.Features.Contents.Data;
public class ContentReaction
{
public required Reaction Reaction { get; set; }
public required Guid UserId { get; set; }
[MaxLength(128)] public required string UserName { get; set; }
}

View File

@@ -1,49 +0,0 @@
using System.ComponentModel.DataAnnotations;
namespace Hutopy.Web.Features.Contents.Data;
public class Creator
{
public Guid Id { get; set; }
public Guid CreatedBy { get; set; }
public DateTimeOffset CreatedAt { get; init; }
public Guid? DeletedBy { get; set; }
public DateTimeOffset? DeletedAt { get; set; }
/// <summary>
/// Softdelete flag (false by default, true once DeletedAt is set)
/// </summary>
public bool IsDeleted { get; private set; } // private set → EF updates it
[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 Presentation Presentation { get; set; } = new() { Description = "Welcome to my profile!" };
}
public class Socials
{
[MaxLength(2048)] public string? FacebookUrl { get; set; }
[MaxLength(2048)] public string? InstagramUrl { get; set; }
[MaxLength(2048)] public string? XUrl { get; set; }
[MaxLength(2048)] public string? LinkedInUrl { get; set; }
[MaxLength(2048)] public string? TikTokUrl { get; set; }
[MaxLength(2048)] public string? YoutubeUrl { get; set; }
[MaxLength(2048)] public string? RedditUrl { get; set; }
[MaxLength(2048)] public string? WebsiteUrl { get; set; }
}
public class Presentation
{
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; }
}

View File

@@ -1,13 +0,0 @@
namespace Hutopy.Web.Features.Contents.Data.Enums;
public enum Reaction
{
None = 0,
Like = 1,
Dislike = 2,
Love = 3,
Haha = 4,
Wow = 5,
Sad = 6,
Angry = 7
}

View File

@@ -1,285 +0,0 @@
// <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("20241020202641_Initial")]
partial class Initial
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasDefaultSchema("Content")
.HasAnnotation("ProductVersion", "8.0.10")
.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>("Title")
.IsRequired()
.HasMaxLength(128)
.HasColumnType("character varying(128)");
b.Property<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<DateTimeOffset>("CreatedAt")
.HasColumnType("timestamp with time zone");
b.Property<Guid>("CreatedBy")
.HasColumnType("uuid");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b.Property<string>("Title")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b.HasKey("Id");
b.ToTable("Creators", "Content");
});
modelBuilder.Entity("Hutopy.Web.Features.Contents.Data.Content", b =>
{
b.HasOne("Hutopy.Web.Features.Contents.Data.Creator", "Creator")
.WithMany()
.HasForeignKey("CreatedBy")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
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.Colors", "Colors", b1 =>
{
b1.Property<Guid>("CreatorId")
.HasColumnType("uuid");
b1.Property<string>("Background")
.IsRequired()
.HasMaxLength(9)
.HasColumnType("character varying(9)");
b1.Property<string>("Error")
.IsRequired()
.HasMaxLength(9)
.HasColumnType("character varying(9)");
b1.Property<string>("OnBackground")
.IsRequired()
.HasMaxLength(9)
.HasColumnType("character varying(9)");
b1.Property<string>("OnError")
.IsRequired()
.HasMaxLength(9)
.HasColumnType("character varying(9)");
b1.Property<string>("OnPrimary")
.IsRequired()
.HasMaxLength(9)
.HasColumnType("character varying(9)");
b1.Property<string>("OnSecondary")
.IsRequired()
.HasMaxLength(9)
.HasColumnType("character varying(9)");
b1.Property<string>("OnSurface")
.IsRequired()
.HasMaxLength(9)
.HasColumnType("character varying(9)");
b1.Property<string>("Primary")
.IsRequired()
.HasMaxLength(9)
.HasColumnType("character varying(9)");
b1.Property<string>("Secondary")
.IsRequired()
.HasMaxLength(9)
.HasColumnType("character varying(9)");
b1.Property<string>("Surface")
.IsRequired()
.HasMaxLength(9)
.HasColumnType("character varying(9)");
b1.HasKey("CreatorId");
b1.ToTable("Colors", "Content");
b1.WithOwner()
.HasForeignKey("CreatorId");
});
b.OwnsOne("Hutopy.Web.Features.Contents.Data.Images", "Images", b1 =>
{
b1.Property<Guid>("CreatorId")
.HasColumnType("uuid");
b1.Property<string>("Banner")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b1.Property<string>("Logo")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b1.HasKey("CreatorId");
b1.ToTable("Images", "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(255)
.HasColumnType("character varying(255)");
b1.Property<string>("InstagramUrl")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b1.Property<string>("LinkedInUrl")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b1.Property<string>("RedditUrl")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b1.Property<string>("TikTokUrl")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b1.Property<string>("WebsiteUrl")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b1.Property<string>("XUrl")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b1.Property<string>("YoutubeUrl")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b1.HasKey("CreatorId");
b1.ToTable("Socials", "Content");
b1.WithOwner()
.HasForeignKey("CreatorId");
});
b.Navigation("Colors")
.IsRequired();
b.Navigation("Images")
.IsRequired();
b.Navigation("Socials")
.IsRequired();
});
#pragma warning restore 612, 618
}
}
}

View File

@@ -1,197 +0,0 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
#nullable disable
namespace Hutopy.Web.Features.Contents.Data.Migrations
{
/// <inheritdoc />
public partial class Initial : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.EnsureSchema(
name: "Content");
migrationBuilder.CreateTable(
name: "Creators",
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),
Name = table.Column<string>(type: "character varying(255)", maxLength: 255, nullable: false),
Title = table.Column<string>(type: "character varying(255)", maxLength: 255, nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Creators", x => x.Id);
});
migrationBuilder.CreateTable(
name: "Colors",
schema: "Content",
columns: table => new
{
CreatorId = table.Column<Guid>(type: "uuid", nullable: false),
Primary = table.Column<string>(type: "character varying(9)", maxLength: 9, nullable: false),
Secondary = table.Column<string>(type: "character varying(9)", maxLength: 9, nullable: false),
Background = table.Column<string>(type: "character varying(9)", maxLength: 9, nullable: false),
Surface = table.Column<string>(type: "character varying(9)", maxLength: 9, nullable: false),
Error = table.Column<string>(type: "character varying(9)", maxLength: 9, nullable: false),
OnPrimary = table.Column<string>(type: "character varying(9)", maxLength: 9, nullable: false),
OnSecondary = table.Column<string>(type: "character varying(9)", maxLength: 9, nullable: false),
OnBackground = table.Column<string>(type: "character varying(9)", maxLength: 9, nullable: false),
OnSurface = table.Column<string>(type: "character varying(9)", maxLength: 9, nullable: false),
OnError = table.Column<string>(type: "character varying(9)", maxLength: 9, nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Colors", x => x.CreatorId);
table.ForeignKey(
name: "FK_Colors_Creators_CreatorId",
column: x => x.CreatorId,
principalSchema: "Content",
principalTable: "Creators",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "Contents",
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),
Title = table.Column<string>(type: "character varying(128)", maxLength: 128, nullable: false),
Description = table.Column<string>(type: "character varying(2048)", maxLength: 2048, nullable: false),
HtmlFileUrl = table.Column<string>(type: "character varying(2048)", maxLength: 2048, nullable: true),
Urls = table.Column<string[]>(type: "text[]", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Contents", x => x.Id);
table.ForeignKey(
name: "FK_Contents_Creators_CreatedBy",
column: x => x.CreatedBy,
principalSchema: "Content",
principalTable: "Creators",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "Images",
schema: "Content",
columns: table => new
{
CreatorId = table.Column<Guid>(type: "uuid", nullable: false),
Banner = table.Column<string>(type: "character varying(255)", maxLength: 255, nullable: true),
Logo = table.Column<string>(type: "character varying(255)", maxLength: 255, 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: "Socials",
schema: "Content",
columns: table => new
{
CreatorId = table.Column<Guid>(type: "uuid", nullable: false),
FacebookUrl = table.Column<string>(type: "character varying(255)", maxLength: 255, nullable: true),
InstagramUrl = table.Column<string>(type: "character varying(255)", maxLength: 255, nullable: true),
XUrl = table.Column<string>(type: "character varying(255)", maxLength: 255, nullable: true),
LinkedInUrl = table.Column<string>(type: "character varying(255)", maxLength: 255, nullable: true),
TikTokUrl = table.Column<string>(type: "character varying(255)", maxLength: 255, nullable: true),
YoutubeUrl = table.Column<string>(type: "character varying(255)", maxLength: 255, nullable: true),
RedditUrl = table.Column<string>(type: "character varying(255)", maxLength: 255, nullable: true),
WebsiteUrl = table.Column<string>(type: "character varying(255)", maxLength: 255, nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Socials", x => x.CreatorId);
table.ForeignKey(
name: "FK_Socials_Creators_CreatorId",
column: x => x.CreatorId,
principalSchema: "Content",
principalTable: "Creators",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "Reactions",
schema: "Content",
columns: table => new
{
ContentId = table.Column<Guid>(type: "uuid", nullable: false),
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
Reaction = table.Column<int>(type: "integer", nullable: false),
UserId = table.Column<Guid>(type: "uuid", nullable: false),
UserName = table.Column<string>(type: "character varying(128)", maxLength: 128, nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Reactions", x => new { x.ContentId, x.Id });
table.ForeignKey(
name: "FK_Reactions_Contents_ContentId",
column: x => x.ContentId,
principalSchema: "Content",
principalTable: "Contents",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateIndex(
name: "IX_Contents_CreatedBy",
schema: "Content",
table: "Contents",
column: "CreatedBy");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "Colors",
schema: "Content");
migrationBuilder.DropTable(
name: "Images",
schema: "Content");
migrationBuilder.DropTable(
name: "Reactions",
schema: "Content");
migrationBuilder.DropTable(
name: "Socials",
schema: "Content");
migrationBuilder.DropTable(
name: "Contents",
schema: "Content");
migrationBuilder.DropTable(
name: "Creators",
schema: "Content");
}
}
}

View File

@@ -1,289 +0,0 @@
// <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("20241201173048_AddThumbnailUrl")]
partial class AddThumbnailUrl
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasDefaultSchema("Content")
.HasAnnotation("ProductVersion", "8.0.10")
.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(512)
.HasColumnType("character varying(512)");
b.Property<string>("Title")
.IsRequired()
.HasMaxLength(128)
.HasColumnType("character varying(128)");
b.Property<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<DateTimeOffset>("CreatedAt")
.HasColumnType("timestamp with time zone");
b.Property<Guid>("CreatedBy")
.HasColumnType("uuid");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b.Property<string>("Title")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b.HasKey("Id");
b.ToTable("Creators", "Content");
});
modelBuilder.Entity("Hutopy.Web.Features.Contents.Data.Content", b =>
{
b.HasOne("Hutopy.Web.Features.Contents.Data.Creator", "Creator")
.WithMany()
.HasForeignKey("CreatedBy")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
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.Colors", "Colors", b1 =>
{
b1.Property<Guid>("CreatorId")
.HasColumnType("uuid");
b1.Property<string>("Background")
.IsRequired()
.HasMaxLength(9)
.HasColumnType("character varying(9)");
b1.Property<string>("Error")
.IsRequired()
.HasMaxLength(9)
.HasColumnType("character varying(9)");
b1.Property<string>("OnBackground")
.IsRequired()
.HasMaxLength(9)
.HasColumnType("character varying(9)");
b1.Property<string>("OnError")
.IsRequired()
.HasMaxLength(9)
.HasColumnType("character varying(9)");
b1.Property<string>("OnPrimary")
.IsRequired()
.HasMaxLength(9)
.HasColumnType("character varying(9)");
b1.Property<string>("OnSecondary")
.IsRequired()
.HasMaxLength(9)
.HasColumnType("character varying(9)");
b1.Property<string>("OnSurface")
.IsRequired()
.HasMaxLength(9)
.HasColumnType("character varying(9)");
b1.Property<string>("Primary")
.IsRequired()
.HasMaxLength(9)
.HasColumnType("character varying(9)");
b1.Property<string>("Secondary")
.IsRequired()
.HasMaxLength(9)
.HasColumnType("character varying(9)");
b1.Property<string>("Surface")
.IsRequired()
.HasMaxLength(9)
.HasColumnType("character varying(9)");
b1.HasKey("CreatorId");
b1.ToTable("Colors", "Content");
b1.WithOwner()
.HasForeignKey("CreatorId");
});
b.OwnsOne("Hutopy.Web.Features.Contents.Data.Images", "Images", b1 =>
{
b1.Property<Guid>("CreatorId")
.HasColumnType("uuid");
b1.Property<string>("Banner")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b1.Property<string>("Logo")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b1.HasKey("CreatorId");
b1.ToTable("Images", "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(255)
.HasColumnType("character varying(255)");
b1.Property<string>("InstagramUrl")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b1.Property<string>("LinkedInUrl")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b1.Property<string>("RedditUrl")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b1.Property<string>("TikTokUrl")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b1.Property<string>("WebsiteUrl")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b1.Property<string>("XUrl")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b1.Property<string>("YoutubeUrl")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b1.HasKey("CreatorId");
b1.ToTable("Socials", "Content");
b1.WithOwner()
.HasForeignKey("CreatorId");
});
b.Navigation("Colors")
.IsRequired();
b.Navigation("Images")
.IsRequired();
b.Navigation("Socials")
.IsRequired();
});
#pragma warning restore 612, 618
}
}
}

View File

@@ -1,31 +0,0 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Hutopy.Web.Features.Contents.Data.Migrations
{
/// <inheritdoc />
public partial class AddThumbnailUrl : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "ThumbnailUrl",
schema: "Content",
table: "Contents",
type: "character varying(512)",
maxLength: 512,
nullable: true);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "ThumbnailUrl",
schema: "Content",
table: "Contents");
}
}
}

View File

@@ -1,390 +0,0 @@
// <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("20241201182352_AddPresentationInfos")]
partial class AddPresentationInfos
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasDefaultSchema("Content")
.HasAnnotation("ProductVersion", "8.0.10")
.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(512)
.HasColumnType("character varying(512)");
b.Property<string>("Title")
.IsRequired()
.HasMaxLength(128)
.HasColumnType("character varying(128)");
b.Property<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<DateTimeOffset>("CreatedAt")
.HasColumnType("timestamp with time zone");
b.Property<Guid>("CreatedBy")
.HasColumnType("uuid");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b.Property<string>("Title")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b.HasKey("Id");
b.ToTable("Creators", "Content");
});
modelBuilder.Entity("Hutopy.Web.Features.Contents.Data.Content", b =>
{
b.HasOne("Hutopy.Web.Features.Contents.Data.Creator", "Creator")
.WithMany()
.HasForeignKey("CreatedBy")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
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.Colors", "Colors", b1 =>
{
b1.Property<Guid>("CreatorId")
.HasColumnType("uuid");
b1.Property<string>("Background")
.IsRequired()
.HasMaxLength(9)
.HasColumnType("character varying(9)");
b1.Property<string>("Error")
.IsRequired()
.HasMaxLength(9)
.HasColumnType("character varying(9)");
b1.Property<string>("OnBackground")
.IsRequired()
.HasMaxLength(9)
.HasColumnType("character varying(9)");
b1.Property<string>("OnError")
.IsRequired()
.HasMaxLength(9)
.HasColumnType("character varying(9)");
b1.Property<string>("OnPrimary")
.IsRequired()
.HasMaxLength(9)
.HasColumnType("character varying(9)");
b1.Property<string>("OnSecondary")
.IsRequired()
.HasMaxLength(9)
.HasColumnType("character varying(9)");
b1.Property<string>("OnSurface")
.IsRequired()
.HasMaxLength(9)
.HasColumnType("character varying(9)");
b1.Property<string>("Primary")
.IsRequired()
.HasMaxLength(9)
.HasColumnType("character varying(9)");
b1.Property<string>("Secondary")
.IsRequired()
.HasMaxLength(9)
.HasColumnType("character varying(9)");
b1.Property<string>("Surface")
.IsRequired()
.HasMaxLength(9)
.HasColumnType("character varying(9)");
b1.HasKey("CreatorId");
b1.ToTable("Colors", "Content");
b1.WithOwner()
.HasForeignKey("CreatorId");
});
b.OwnsOne("Hutopy.Web.Features.Contents.Data.Images", "Images", b1 =>
{
b1.Property<Guid>("CreatorId")
.HasColumnType("uuid");
b1.Property<string>("Banner")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b1.Property<string>("Logo")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
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(255)
.HasColumnType("character varying(255)");
b1.Property<string>("Image2Url")
.IsRequired()
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b1.Property<string>("Image3Url")
.IsRequired()
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b1.Property<string>("Image4Url")
.IsRequired()
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b1.Property<string>("ImagesSubtitle")
.IsRequired()
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b1.Property<string>("ImagesText")
.IsRequired()
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b1.Property<string>("MainImageText")
.IsRequired()
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b1.Property<string>("MainImageUrl")
.IsRequired()
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b1.Property<string>("MainVideoText")
.IsRequired()
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b1.Property<string>("PhoneNumber")
.IsRequired()
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b1.Property<string>("Title")
.IsRequired()
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b1.Property<string>("VideoSubtitle")
.IsRequired()
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b1.Property<string>("VideoSubtitleMain")
.IsRequired()
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b1.Property<string>("VideoText")
.IsRequired()
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b1.Property<string>("VideoUrl")
.IsRequired()
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b1.Property<string>("VideoUrlMain")
.IsRequired()
.HasMaxLength(255)
.HasColumnType("character varying(255)");
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(255)
.HasColumnType("character varying(255)");
b1.Property<string>("InstagramUrl")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b1.Property<string>("LinkedInUrl")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b1.Property<string>("RedditUrl")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b1.Property<string>("TikTokUrl")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b1.Property<string>("WebsiteUrl")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b1.Property<string>("XUrl")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b1.Property<string>("YoutubeUrl")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b1.HasKey("CreatorId");
b1.ToTable("Socials", "Content");
b1.WithOwner()
.HasForeignKey("CreatorId");
});
b.Navigation("Colors")
.IsRequired();
b.Navigation("Images")
.IsRequired();
b.Navigation("PresentationInfos")
.IsRequired();
b.Navigation("Socials")
.IsRequired();
});
#pragma warning restore 612, 618
}
}
}

View File

@@ -1,59 +0,0 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Hutopy.Web.Features.Contents.Data.Migrations
{
/// <inheritdoc />
public partial class AddPresentationInfos : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "PresentationInfos",
schema: "Content",
columns: table => new
{
CreatorId = table.Column<Guid>(type: "uuid", nullable: false),
PhoneNumber = table.Column<string>(type: "character varying(255)", maxLength: 255, nullable: false),
Email = table.Column<string>(type: "character varying(255)", maxLength: 255, nullable: false),
Title = table.Column<string>(type: "character varying(255)", maxLength: 255, nullable: false),
MainImageUrl = table.Column<string>(type: "character varying(255)", maxLength: 255, nullable: false),
MainImageText = table.Column<string>(type: "character varying(255)", maxLength: 255, nullable: false),
MainVideoText = table.Column<string>(type: "character varying(255)", maxLength: 255, nullable: false),
ImagesSubtitle = table.Column<string>(type: "character varying(255)", maxLength: 255, nullable: false),
Image1Url = table.Column<string>(type: "character varying(255)", maxLength: 255, nullable: false),
Image2Url = table.Column<string>(type: "character varying(255)", maxLength: 255, nullable: false),
Image3Url = table.Column<string>(type: "character varying(255)", maxLength: 255, nullable: false),
Image4Url = table.Column<string>(type: "character varying(255)", maxLength: 255, nullable: false),
ImagesText = table.Column<string>(type: "character varying(255)", maxLength: 255, nullable: false),
VideoSubtitle = table.Column<string>(type: "character varying(255)", maxLength: 255, nullable: false),
VideoSubtitleMain = table.Column<string>(type: "character varying(255)", maxLength: 255, nullable: false),
VideoUrlMain = table.Column<string>(type: "character varying(255)", maxLength: 255, nullable: false),
VideoUrl = table.Column<string>(type: "character varying(255)", maxLength: 255, nullable: false),
VideoText = table.Column<string>(type: "character varying(255)", maxLength: 255, 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);
});
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "PresentationInfos",
schema: "Content");
}
}
}

View File

@@ -1,390 +0,0 @@
// <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("20241202131957_LongerStringPresentationInfos")]
partial class LongerStringPresentationInfos
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasDefaultSchema("Content")
.HasAnnotation("ProductVersion", "8.0.10")
.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(512)
.HasColumnType("character varying(512)");
b.Property<string>("Title")
.IsRequired()
.HasMaxLength(128)
.HasColumnType("character varying(128)");
b.Property<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<DateTimeOffset>("CreatedAt")
.HasColumnType("timestamp with time zone");
b.Property<Guid>("CreatedBy")
.HasColumnType("uuid");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b.Property<string>("Title")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b.HasKey("Id");
b.ToTable("Creators", "Content");
});
modelBuilder.Entity("Hutopy.Web.Features.Contents.Data.Content", b =>
{
b.HasOne("Hutopy.Web.Features.Contents.Data.Creator", "Creator")
.WithMany()
.HasForeignKey("CreatedBy")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
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.Colors", "Colors", b1 =>
{
b1.Property<Guid>("CreatorId")
.HasColumnType("uuid");
b1.Property<string>("Background")
.IsRequired()
.HasMaxLength(9)
.HasColumnType("character varying(9)");
b1.Property<string>("Error")
.IsRequired()
.HasMaxLength(9)
.HasColumnType("character varying(9)");
b1.Property<string>("OnBackground")
.IsRequired()
.HasMaxLength(9)
.HasColumnType("character varying(9)");
b1.Property<string>("OnError")
.IsRequired()
.HasMaxLength(9)
.HasColumnType("character varying(9)");
b1.Property<string>("OnPrimary")
.IsRequired()
.HasMaxLength(9)
.HasColumnType("character varying(9)");
b1.Property<string>("OnSecondary")
.IsRequired()
.HasMaxLength(9)
.HasColumnType("character varying(9)");
b1.Property<string>("OnSurface")
.IsRequired()
.HasMaxLength(9)
.HasColumnType("character varying(9)");
b1.Property<string>("Primary")
.IsRequired()
.HasMaxLength(9)
.HasColumnType("character varying(9)");
b1.Property<string>("Secondary")
.IsRequired()
.HasMaxLength(9)
.HasColumnType("character varying(9)");
b1.Property<string>("Surface")
.IsRequired()
.HasMaxLength(9)
.HasColumnType("character varying(9)");
b1.HasKey("CreatorId");
b1.ToTable("Colors", "Content");
b1.WithOwner()
.HasForeignKey("CreatorId");
});
b.OwnsOne("Hutopy.Web.Features.Contents.Data.Images", "Images", b1 =>
{
b1.Property<Guid>("CreatorId")
.HasColumnType("uuid");
b1.Property<string>("Banner")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b1.Property<string>("Logo")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
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(2000)
.HasColumnType("character varying(2000)");
b1.Property<string>("Image2Url")
.IsRequired()
.HasMaxLength(2000)
.HasColumnType("character varying(2000)");
b1.Property<string>("Image3Url")
.IsRequired()
.HasMaxLength(2000)
.HasColumnType("character varying(2000)");
b1.Property<string>("Image4Url")
.IsRequired()
.HasMaxLength(2000)
.HasColumnType("character varying(2000)");
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(2000)
.HasColumnType("character varying(2000)");
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(2000)
.HasColumnType("character varying(2000)");
b1.Property<string>("VideoUrlMain")
.IsRequired()
.HasMaxLength(2000)
.HasColumnType("character varying(2000)");
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(255)
.HasColumnType("character varying(255)");
b1.Property<string>("InstagramUrl")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b1.Property<string>("LinkedInUrl")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b1.Property<string>("RedditUrl")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b1.Property<string>("TikTokUrl")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b1.Property<string>("WebsiteUrl")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b1.Property<string>("XUrl")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b1.Property<string>("YoutubeUrl")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b1.HasKey("CreatorId");
b1.ToTable("Socials", "Content");
b1.WithOwner()
.HasForeignKey("CreatorId");
});
b.Navigation("Colors")
.IsRequired();
b.Navigation("Images")
.IsRequired();
b.Navigation("PresentationInfos")
.IsRequired();
b.Navigation("Socials")
.IsRequired();
});
#pragma warning restore 612, 618
}
}
}

View File

@@ -1,348 +0,0 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Hutopy.Web.Features.Contents.Data.Migrations
{
/// <inheritdoc />
public partial class LongerStringPresentationInfos : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<string>(
name: "VideoUrlMain",
schema: "Content",
table: "PresentationInfos",
type: "character varying(2000)",
maxLength: 2000,
nullable: false,
oldClrType: typeof(string),
oldType: "character varying(255)",
oldMaxLength: 255);
migrationBuilder.AlterColumn<string>(
name: "VideoUrl",
schema: "Content",
table: "PresentationInfos",
type: "character varying(2000)",
maxLength: 2000,
nullable: false,
oldClrType: typeof(string),
oldType: "character varying(255)",
oldMaxLength: 255);
migrationBuilder.AlterColumn<string>(
name: "VideoText",
schema: "Content",
table: "PresentationInfos",
type: "character varying(10000)",
maxLength: 10000,
nullable: false,
oldClrType: typeof(string),
oldType: "character varying(255)",
oldMaxLength: 255);
migrationBuilder.AlterColumn<string>(
name: "VideoSubtitleMain",
schema: "Content",
table: "PresentationInfos",
type: "character varying(2000)",
maxLength: 2000,
nullable: false,
oldClrType: typeof(string),
oldType: "character varying(255)",
oldMaxLength: 255);
migrationBuilder.AlterColumn<string>(
name: "VideoSubtitle",
schema: "Content",
table: "PresentationInfos",
type: "character varying(2000)",
maxLength: 2000,
nullable: false,
oldClrType: typeof(string),
oldType: "character varying(255)",
oldMaxLength: 255);
migrationBuilder.AlterColumn<string>(
name: "Title",
schema: "Content",
table: "PresentationInfos",
type: "character varying(2000)",
maxLength: 2000,
nullable: false,
oldClrType: typeof(string),
oldType: "character varying(255)",
oldMaxLength: 255);
migrationBuilder.AlterColumn<string>(
name: "MainVideoText",
schema: "Content",
table: "PresentationInfos",
type: "character varying(10000)",
maxLength: 10000,
nullable: false,
oldClrType: typeof(string),
oldType: "character varying(255)",
oldMaxLength: 255);
migrationBuilder.AlterColumn<string>(
name: "MainImageUrl",
schema: "Content",
table: "PresentationInfos",
type: "character varying(2000)",
maxLength: 2000,
nullable: false,
oldClrType: typeof(string),
oldType: "character varying(255)",
oldMaxLength: 255);
migrationBuilder.AlterColumn<string>(
name: "MainImageText",
schema: "Content",
table: "PresentationInfos",
type: "character varying(10000)",
maxLength: 10000,
nullable: false,
oldClrType: typeof(string),
oldType: "character varying(255)",
oldMaxLength: 255);
migrationBuilder.AlterColumn<string>(
name: "ImagesText",
schema: "Content",
table: "PresentationInfos",
type: "character varying(10000)",
maxLength: 10000,
nullable: false,
oldClrType: typeof(string),
oldType: "character varying(255)",
oldMaxLength: 255);
migrationBuilder.AlterColumn<string>(
name: "ImagesSubtitle",
schema: "Content",
table: "PresentationInfos",
type: "character varying(2000)",
maxLength: 2000,
nullable: false,
oldClrType: typeof(string),
oldType: "character varying(255)",
oldMaxLength: 255);
migrationBuilder.AlterColumn<string>(
name: "Image4Url",
schema: "Content",
table: "PresentationInfos",
type: "character varying(2000)",
maxLength: 2000,
nullable: false,
oldClrType: typeof(string),
oldType: "character varying(255)",
oldMaxLength: 255);
migrationBuilder.AlterColumn<string>(
name: "Image3Url",
schema: "Content",
table: "PresentationInfos",
type: "character varying(2000)",
maxLength: 2000,
nullable: false,
oldClrType: typeof(string),
oldType: "character varying(255)",
oldMaxLength: 255);
migrationBuilder.AlterColumn<string>(
name: "Image2Url",
schema: "Content",
table: "PresentationInfos",
type: "character varying(2000)",
maxLength: 2000,
nullable: false,
oldClrType: typeof(string),
oldType: "character varying(255)",
oldMaxLength: 255);
migrationBuilder.AlterColumn<string>(
name: "Image1Url",
schema: "Content",
table: "PresentationInfos",
type: "character varying(2000)",
maxLength: 2000,
nullable: false,
oldClrType: typeof(string),
oldType: "character varying(255)",
oldMaxLength: 255);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<string>(
name: "VideoUrlMain",
schema: "Content",
table: "PresentationInfos",
type: "character varying(255)",
maxLength: 255,
nullable: false,
oldClrType: typeof(string),
oldType: "character varying(2000)",
oldMaxLength: 2000);
migrationBuilder.AlterColumn<string>(
name: "VideoUrl",
schema: "Content",
table: "PresentationInfos",
type: "character varying(255)",
maxLength: 255,
nullable: false,
oldClrType: typeof(string),
oldType: "character varying(2000)",
oldMaxLength: 2000);
migrationBuilder.AlterColumn<string>(
name: "VideoText",
schema: "Content",
table: "PresentationInfos",
type: "character varying(255)",
maxLength: 255,
nullable: false,
oldClrType: typeof(string),
oldType: "character varying(10000)",
oldMaxLength: 10000);
migrationBuilder.AlterColumn<string>(
name: "VideoSubtitleMain",
schema: "Content",
table: "PresentationInfos",
type: "character varying(255)",
maxLength: 255,
nullable: false,
oldClrType: typeof(string),
oldType: "character varying(2000)",
oldMaxLength: 2000);
migrationBuilder.AlterColumn<string>(
name: "VideoSubtitle",
schema: "Content",
table: "PresentationInfos",
type: "character varying(255)",
maxLength: 255,
nullable: false,
oldClrType: typeof(string),
oldType: "character varying(2000)",
oldMaxLength: 2000);
migrationBuilder.AlterColumn<string>(
name: "Title",
schema: "Content",
table: "PresentationInfos",
type: "character varying(255)",
maxLength: 255,
nullable: false,
oldClrType: typeof(string),
oldType: "character varying(2000)",
oldMaxLength: 2000);
migrationBuilder.AlterColumn<string>(
name: "MainVideoText",
schema: "Content",
table: "PresentationInfos",
type: "character varying(255)",
maxLength: 255,
nullable: false,
oldClrType: typeof(string),
oldType: "character varying(10000)",
oldMaxLength: 10000);
migrationBuilder.AlterColumn<string>(
name: "MainImageUrl",
schema: "Content",
table: "PresentationInfos",
type: "character varying(255)",
maxLength: 255,
nullable: false,
oldClrType: typeof(string),
oldType: "character varying(2000)",
oldMaxLength: 2000);
migrationBuilder.AlterColumn<string>(
name: "MainImageText",
schema: "Content",
table: "PresentationInfos",
type: "character varying(255)",
maxLength: 255,
nullable: false,
oldClrType: typeof(string),
oldType: "character varying(10000)",
oldMaxLength: 10000);
migrationBuilder.AlterColumn<string>(
name: "ImagesText",
schema: "Content",
table: "PresentationInfos",
type: "character varying(255)",
maxLength: 255,
nullable: false,
oldClrType: typeof(string),
oldType: "character varying(10000)",
oldMaxLength: 10000);
migrationBuilder.AlterColumn<string>(
name: "ImagesSubtitle",
schema: "Content",
table: "PresentationInfos",
type: "character varying(255)",
maxLength: 255,
nullable: false,
oldClrType: typeof(string),
oldType: "character varying(2000)",
oldMaxLength: 2000);
migrationBuilder.AlterColumn<string>(
name: "Image4Url",
schema: "Content",
table: "PresentationInfos",
type: "character varying(255)",
maxLength: 255,
nullable: false,
oldClrType: typeof(string),
oldType: "character varying(2000)",
oldMaxLength: 2000);
migrationBuilder.AlterColumn<string>(
name: "Image3Url",
schema: "Content",
table: "PresentationInfos",
type: "character varying(255)",
maxLength: 255,
nullable: false,
oldClrType: typeof(string),
oldType: "character varying(2000)",
oldMaxLength: 2000);
migrationBuilder.AlterColumn<string>(
name: "Image2Url",
schema: "Content",
table: "PresentationInfos",
type: "character varying(255)",
maxLength: 255,
nullable: false,
oldClrType: typeof(string),
oldType: "character varying(2000)",
oldMaxLength: 2000);
migrationBuilder.AlterColumn<string>(
name: "Image1Url",
schema: "Content",
table: "PresentationInfos",
type: "character varying(255)",
maxLength: 255,
nullable: false,
oldClrType: typeof(string),
oldType: "character varying(2000)",
oldMaxLength: 2000);
}
}
}

View File

@@ -1,400 +0,0 @@
// <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("20250108022601_AddComputedColumnAndIndex_CreatorName")]
partial class AddComputedColumnAndIndex_CreatorName
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasDefaultSchema("Content")
.HasAnnotation("ProductVersion", "8.0.10")
.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(512)
.HasColumnType("character varying(512)");
b.Property<string>("Title")
.IsRequired()
.HasMaxLength(128)
.HasColumnType("character varying(128)");
b.Property<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<DateTimeOffset>("CreatedAt")
.HasColumnType("timestamp with time zone");
b.Property<Guid>("CreatedBy")
.HasColumnType("uuid");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b.Property<string>("NormalizedName")
.IsRequired()
.ValueGeneratedOnAddOrUpdate()
.HasMaxLength(255)
.HasColumnType("character varying(255)")
.HasComputedColumnSql("LOWER( \"Content\".\"Creators\".\"Name\")", true);
b.Property<string>("Title")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b.HasKey("Id");
b.HasIndex("NormalizedName")
.IsUnique();
b.ToTable("Creators", "Content");
});
modelBuilder.Entity("Hutopy.Web.Features.Contents.Data.Content", b =>
{
b.HasOne("Hutopy.Web.Features.Contents.Data.Creator", "Creator")
.WithMany()
.HasForeignKey("CreatedBy")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
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.Colors", "Colors", b1 =>
{
b1.Property<Guid>("CreatorId")
.HasColumnType("uuid");
b1.Property<string>("Background")
.IsRequired()
.HasMaxLength(9)
.HasColumnType("character varying(9)");
b1.Property<string>("Error")
.IsRequired()
.HasMaxLength(9)
.HasColumnType("character varying(9)");
b1.Property<string>("OnBackground")
.IsRequired()
.HasMaxLength(9)
.HasColumnType("character varying(9)");
b1.Property<string>("OnError")
.IsRequired()
.HasMaxLength(9)
.HasColumnType("character varying(9)");
b1.Property<string>("OnPrimary")
.IsRequired()
.HasMaxLength(9)
.HasColumnType("character varying(9)");
b1.Property<string>("OnSecondary")
.IsRequired()
.HasMaxLength(9)
.HasColumnType("character varying(9)");
b1.Property<string>("OnSurface")
.IsRequired()
.HasMaxLength(9)
.HasColumnType("character varying(9)");
b1.Property<string>("Primary")
.IsRequired()
.HasMaxLength(9)
.HasColumnType("character varying(9)");
b1.Property<string>("Secondary")
.IsRequired()
.HasMaxLength(9)
.HasColumnType("character varying(9)");
b1.Property<string>("Surface")
.IsRequired()
.HasMaxLength(9)
.HasColumnType("character varying(9)");
b1.HasKey("CreatorId");
b1.ToTable("Colors", "Content");
b1.WithOwner()
.HasForeignKey("CreatorId");
});
b.OwnsOne("Hutopy.Web.Features.Contents.Data.Images", "Images", b1 =>
{
b1.Property<Guid>("CreatorId")
.HasColumnType("uuid");
b1.Property<string>("Banner")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b1.Property<string>("Logo")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
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(2000)
.HasColumnType("character varying(2000)");
b1.Property<string>("Image2Url")
.IsRequired()
.HasMaxLength(2000)
.HasColumnType("character varying(2000)");
b1.Property<string>("Image3Url")
.IsRequired()
.HasMaxLength(2000)
.HasColumnType("character varying(2000)");
b1.Property<string>("Image4Url")
.IsRequired()
.HasMaxLength(2000)
.HasColumnType("character varying(2000)");
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(2000)
.HasColumnType("character varying(2000)");
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(2000)
.HasColumnType("character varying(2000)");
b1.Property<string>("VideoUrlMain")
.IsRequired()
.HasMaxLength(2000)
.HasColumnType("character varying(2000)");
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(255)
.HasColumnType("character varying(255)");
b1.Property<string>("InstagramUrl")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b1.Property<string>("LinkedInUrl")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b1.Property<string>("RedditUrl")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b1.Property<string>("TikTokUrl")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b1.Property<string>("WebsiteUrl")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b1.Property<string>("XUrl")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b1.Property<string>("YoutubeUrl")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b1.HasKey("CreatorId");
b1.ToTable("Socials", "Content");
b1.WithOwner()
.HasForeignKey("CreatorId");
});
b.Navigation("Colors")
.IsRequired();
b.Navigation("Images")
.IsRequired();
b.Navigation("PresentationInfos")
.IsRequired();
b.Navigation("Socials")
.IsRequired();
});
#pragma warning restore 612, 618
}
}
}

View File

@@ -1,45 +0,0 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Hutopy.Web.Features.Contents.Data.Migrations
{
/// <inheritdoc />
public partial class AddComputedColumnAndIndex_CreatorName : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "NormalizedName",
schema: "Content",
table: "Creators",
type: "character varying(255)",
maxLength: 255,
nullable: false,
computedColumnSql: "LOWER( \"Content\".\"Creators\".\"Name\")",
stored: true);
migrationBuilder.CreateIndex(
name: "IX_Creators_NormalizedName",
schema: "Content",
table: "Creators",
column: "NormalizedName",
unique: true);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropIndex(
name: "IX_Creators_NormalizedName",
schema: "Content",
table: "Creators");
migrationBuilder.DropColumn(
name: "NormalizedName",
schema: "Content",
table: "Creators");
}
}
}

View File

@@ -1,403 +0,0 @@
// <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("20250108210552_Add_Verified_Creator")]
partial class Add_Verified_Creator
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasDefaultSchema("Content")
.HasAnnotation("ProductVersion", "8.0.10")
.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(512)
.HasColumnType("character varying(512)");
b.Property<string>("Title")
.IsRequired()
.HasMaxLength(128)
.HasColumnType("character varying(128)");
b.Property<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<DateTimeOffset>("CreatedAt")
.HasColumnType("timestamp with time zone");
b.Property<Guid>("CreatedBy")
.HasColumnType("uuid");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b.Property<string>("NormalizedName")
.IsRequired()
.ValueGeneratedOnAddOrUpdate()
.HasMaxLength(255)
.HasColumnType("character varying(255)")
.HasComputedColumnSql("LOWER( \"Content\".\"Creators\".\"Name\")", true);
b.Property<string>("Title")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b.Property<bool>("Verified")
.HasColumnType("boolean");
b.HasKey("Id");
b.HasIndex("NormalizedName")
.IsUnique();
b.ToTable("Creators", "Content");
});
modelBuilder.Entity("Hutopy.Web.Features.Contents.Data.Content", b =>
{
b.HasOne("Hutopy.Web.Features.Contents.Data.Creator", "Creator")
.WithMany()
.HasForeignKey("CreatedBy")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
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.Colors", "Colors", b1 =>
{
b1.Property<Guid>("CreatorId")
.HasColumnType("uuid");
b1.Property<string>("Background")
.IsRequired()
.HasMaxLength(9)
.HasColumnType("character varying(9)");
b1.Property<string>("Error")
.IsRequired()
.HasMaxLength(9)
.HasColumnType("character varying(9)");
b1.Property<string>("OnBackground")
.IsRequired()
.HasMaxLength(9)
.HasColumnType("character varying(9)");
b1.Property<string>("OnError")
.IsRequired()
.HasMaxLength(9)
.HasColumnType("character varying(9)");
b1.Property<string>("OnPrimary")
.IsRequired()
.HasMaxLength(9)
.HasColumnType("character varying(9)");
b1.Property<string>("OnSecondary")
.IsRequired()
.HasMaxLength(9)
.HasColumnType("character varying(9)");
b1.Property<string>("OnSurface")
.IsRequired()
.HasMaxLength(9)
.HasColumnType("character varying(9)");
b1.Property<string>("Primary")
.IsRequired()
.HasMaxLength(9)
.HasColumnType("character varying(9)");
b1.Property<string>("Secondary")
.IsRequired()
.HasMaxLength(9)
.HasColumnType("character varying(9)");
b1.Property<string>("Surface")
.IsRequired()
.HasMaxLength(9)
.HasColumnType("character varying(9)");
b1.HasKey("CreatorId");
b1.ToTable("Colors", "Content");
b1.WithOwner()
.HasForeignKey("CreatorId");
});
b.OwnsOne("Hutopy.Web.Features.Contents.Data.Images", "Images", b1 =>
{
b1.Property<Guid>("CreatorId")
.HasColumnType("uuid");
b1.Property<string>("Banner")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b1.Property<string>("Logo")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
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(2000)
.HasColumnType("character varying(2000)");
b1.Property<string>("Image2Url")
.IsRequired()
.HasMaxLength(2000)
.HasColumnType("character varying(2000)");
b1.Property<string>("Image3Url")
.IsRequired()
.HasMaxLength(2000)
.HasColumnType("character varying(2000)");
b1.Property<string>("Image4Url")
.IsRequired()
.HasMaxLength(2000)
.HasColumnType("character varying(2000)");
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(2000)
.HasColumnType("character varying(2000)");
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(2000)
.HasColumnType("character varying(2000)");
b1.Property<string>("VideoUrlMain")
.IsRequired()
.HasMaxLength(2000)
.HasColumnType("character varying(2000)");
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(255)
.HasColumnType("character varying(255)");
b1.Property<string>("InstagramUrl")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b1.Property<string>("LinkedInUrl")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b1.Property<string>("RedditUrl")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b1.Property<string>("TikTokUrl")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b1.Property<string>("WebsiteUrl")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b1.Property<string>("XUrl")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b1.Property<string>("YoutubeUrl")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b1.HasKey("CreatorId");
b1.ToTable("Socials", "Content");
b1.WithOwner()
.HasForeignKey("CreatorId");
});
b.Navigation("Colors")
.IsRequired();
b.Navigation("Images")
.IsRequired();
b.Navigation("PresentationInfos")
.IsRequired();
b.Navigation("Socials")
.IsRequired();
});
#pragma warning restore 612, 618
}
}
}

View File

@@ -1,31 +0,0 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Hutopy.Web.Features.Contents.Data.Migrations
{
/// <inheritdoc />
public partial class Add_Verified_Creator : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<bool>(
name: "Verified",
schema: "Content",
table: "Creators",
type: "boolean",
nullable: false,
defaultValue: false);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "Verified",
schema: "Content",
table: "Creators");
}
}
}

View File

@@ -1,406 +0,0 @@
// <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("20250109015556_Adds_AcceptDonation_Creator")]
partial class Adds_AcceptDonation_Creator
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasDefaultSchema("Content")
.HasAnnotation("ProductVersion", "8.0.10")
.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(512)
.HasColumnType("character varying(512)");
b.Property<string>("Title")
.IsRequired()
.HasMaxLength(128)
.HasColumnType("character varying(128)");
b.Property<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<string>("Name")
.IsRequired()
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b.Property<string>("NormalizedName")
.IsRequired()
.ValueGeneratedOnAddOrUpdate()
.HasMaxLength(255)
.HasColumnType("character varying(255)")
.HasComputedColumnSql("LOWER( \"Content\".\"Creators\".\"Name\")", true);
b.Property<string>("Title")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b.Property<bool>("Verified")
.HasColumnType("boolean");
b.HasKey("Id");
b.HasIndex("NormalizedName")
.IsUnique();
b.ToTable("Creators", "Content");
});
modelBuilder.Entity("Hutopy.Web.Features.Contents.Data.Content", b =>
{
b.HasOne("Hutopy.Web.Features.Contents.Data.Creator", "Creator")
.WithMany()
.HasForeignKey("CreatedBy")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
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.Colors", "Colors", b1 =>
{
b1.Property<Guid>("CreatorId")
.HasColumnType("uuid");
b1.Property<string>("Background")
.IsRequired()
.HasMaxLength(9)
.HasColumnType("character varying(9)");
b1.Property<string>("Error")
.IsRequired()
.HasMaxLength(9)
.HasColumnType("character varying(9)");
b1.Property<string>("OnBackground")
.IsRequired()
.HasMaxLength(9)
.HasColumnType("character varying(9)");
b1.Property<string>("OnError")
.IsRequired()
.HasMaxLength(9)
.HasColumnType("character varying(9)");
b1.Property<string>("OnPrimary")
.IsRequired()
.HasMaxLength(9)
.HasColumnType("character varying(9)");
b1.Property<string>("OnSecondary")
.IsRequired()
.HasMaxLength(9)
.HasColumnType("character varying(9)");
b1.Property<string>("OnSurface")
.IsRequired()
.HasMaxLength(9)
.HasColumnType("character varying(9)");
b1.Property<string>("Primary")
.IsRequired()
.HasMaxLength(9)
.HasColumnType("character varying(9)");
b1.Property<string>("Secondary")
.IsRequired()
.HasMaxLength(9)
.HasColumnType("character varying(9)");
b1.Property<string>("Surface")
.IsRequired()
.HasMaxLength(9)
.HasColumnType("character varying(9)");
b1.HasKey("CreatorId");
b1.ToTable("Colors", "Content");
b1.WithOwner()
.HasForeignKey("CreatorId");
});
b.OwnsOne("Hutopy.Web.Features.Contents.Data.Images", "Images", b1 =>
{
b1.Property<Guid>("CreatorId")
.HasColumnType("uuid");
b1.Property<string>("Banner")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b1.Property<string>("Logo")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
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(2000)
.HasColumnType("character varying(2000)");
b1.Property<string>("Image2Url")
.IsRequired()
.HasMaxLength(2000)
.HasColumnType("character varying(2000)");
b1.Property<string>("Image3Url")
.IsRequired()
.HasMaxLength(2000)
.HasColumnType("character varying(2000)");
b1.Property<string>("Image4Url")
.IsRequired()
.HasMaxLength(2000)
.HasColumnType("character varying(2000)");
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(2000)
.HasColumnType("character varying(2000)");
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(2000)
.HasColumnType("character varying(2000)");
b1.Property<string>("VideoUrlMain")
.IsRequired()
.HasMaxLength(2000)
.HasColumnType("character varying(2000)");
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(255)
.HasColumnType("character varying(255)");
b1.Property<string>("InstagramUrl")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b1.Property<string>("LinkedInUrl")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b1.Property<string>("RedditUrl")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b1.Property<string>("TikTokUrl")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b1.Property<string>("WebsiteUrl")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b1.Property<string>("XUrl")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b1.Property<string>("YoutubeUrl")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b1.HasKey("CreatorId");
b1.ToTable("Socials", "Content");
b1.WithOwner()
.HasForeignKey("CreatorId");
});
b.Navigation("Colors")
.IsRequired();
b.Navigation("Images")
.IsRequired();
b.Navigation("PresentationInfos")
.IsRequired();
b.Navigation("Socials")
.IsRequired();
});
#pragma warning restore 612, 618
}
}
}

View File

@@ -1,31 +0,0 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Hutopy.Web.Features.Contents.Data.Migrations
{
/// <inheritdoc />
public partial class Adds_AcceptDonation_Creator : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<bool>(
name: "AcceptDonation",
schema: "Content",
table: "Creators",
type: "boolean",
nullable: false,
defaultValue: false);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "AcceptDonation",
schema: "Content",
table: "Creators");
}
}
}

View File

@@ -1,442 +0,0 @@
// <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("20250131210849_AddSlug")]
partial class AddSlug
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasDefaultSchema("Content")
.HasAnnotation("ProductVersion", "8.0.10")
.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(512)
.HasColumnType("character varying(512)");
b.Property<string>("Title")
.IsRequired()
.HasMaxLength(128)
.HasColumnType("character varying(128)");
b.Property<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<Guid>("SlugsId")
.HasColumnType("uuid");
b.Property<string>("Title")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b.Property<bool>("Verified")
.HasColumnType("boolean");
b.HasKey("Id");
b.HasIndex("SlugsId");
b.ToTable("Creators", "Content");
});
modelBuilder.Entity("Hutopy.Web.Features.Contents.Data.Slugs", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<bool>("Active")
.HasColumnType("boolean");
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.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")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
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.HasOne("Hutopy.Web.Features.Contents.Data.Slugs", "Slugs")
.WithMany()
.HasForeignKey("SlugsId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.OwnsOne("Hutopy.Web.Features.Contents.Data.Colors", "Colors", b1 =>
{
b1.Property<Guid>("CreatorId")
.HasColumnType("uuid");
b1.Property<string>("Background")
.IsRequired()
.HasMaxLength(9)
.HasColumnType("character varying(9)");
b1.Property<string>("Error")
.IsRequired()
.HasMaxLength(9)
.HasColumnType("character varying(9)");
b1.Property<string>("OnBackground")
.IsRequired()
.HasMaxLength(9)
.HasColumnType("character varying(9)");
b1.Property<string>("OnError")
.IsRequired()
.HasMaxLength(9)
.HasColumnType("character varying(9)");
b1.Property<string>("OnPrimary")
.IsRequired()
.HasMaxLength(9)
.HasColumnType("character varying(9)");
b1.Property<string>("OnSecondary")
.IsRequired()
.HasMaxLength(9)
.HasColumnType("character varying(9)");
b1.Property<string>("OnSurface")
.IsRequired()
.HasMaxLength(9)
.HasColumnType("character varying(9)");
b1.Property<string>("Primary")
.IsRequired()
.HasMaxLength(9)
.HasColumnType("character varying(9)");
b1.Property<string>("Secondary")
.IsRequired()
.HasMaxLength(9)
.HasColumnType("character varying(9)");
b1.Property<string>("Surface")
.IsRequired()
.HasMaxLength(9)
.HasColumnType("character varying(9)");
b1.HasKey("CreatorId");
b1.ToTable("Colors", "Content");
b1.WithOwner()
.HasForeignKey("CreatorId");
});
b.OwnsOne("Hutopy.Web.Features.Contents.Data.Images", "Images", b1 =>
{
b1.Property<Guid>("CreatorId")
.HasColumnType("uuid");
b1.Property<string>("Banner")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b1.Property<string>("Logo")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
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(2000)
.HasColumnType("character varying(2000)");
b1.Property<string>("Image2Url")
.IsRequired()
.HasMaxLength(2000)
.HasColumnType("character varying(2000)");
b1.Property<string>("Image3Url")
.IsRequired()
.HasMaxLength(2000)
.HasColumnType("character varying(2000)");
b1.Property<string>("Image4Url")
.IsRequired()
.HasMaxLength(2000)
.HasColumnType("character varying(2000)");
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(2000)
.HasColumnType("character varying(2000)");
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(2000)
.HasColumnType("character varying(2000)");
b1.Property<string>("VideoUrlMain")
.IsRequired()
.HasMaxLength(2000)
.HasColumnType("character varying(2000)");
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(255)
.HasColumnType("character varying(255)");
b1.Property<string>("InstagramUrl")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b1.Property<string>("LinkedInUrl")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b1.Property<string>("RedditUrl")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b1.Property<string>("TikTokUrl")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b1.Property<string>("WebsiteUrl")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b1.Property<string>("XUrl")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b1.Property<string>("YoutubeUrl")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b1.HasKey("CreatorId");
b1.ToTable("Socials", "Content");
b1.WithOwner()
.HasForeignKey("CreatorId");
});
b.Navigation("Colors")
.IsRequired();
b.Navigation("Images")
.IsRequired();
b.Navigation("PresentationInfos")
.IsRequired();
b.Navigation("Slugs");
b.Navigation("Socials")
.IsRequired();
});
#pragma warning restore 612, 618
}
}
}

View File

@@ -1,159 +0,0 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Hutopy.Web.Features.Contents.Data.Migrations
{
/// <inheritdoc />
public partial class AddSlug : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropIndex(
name: "IX_Creators_NormalizedName",
schema: "Content",
table: "Creators");
migrationBuilder.DropColumn(
name: "NormalizedName",
schema: "Content",
table: "Creators");
// Add SlugsId column to Creators (temporary nullable to avoid issues while updating)
migrationBuilder.AddColumn<Guid>(
name: "SlugsId",
schema: "Content",
table: "Creators",
type: "uuid",
nullable: true);
// Create the Slugs table
migrationBuilder.CreateTable(
name: "Slugs",
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),
Name = table.Column<string>(type: "character varying(128)", maxLength: 128, nullable: false),
NormalizedName = table.Column<string>(type: "character varying(128)", maxLength: 128, nullable: false, computedColumnSql: "LOWER( \"Content\".\"Slugs\".\"Name\")", stored: true),
ReservedUntil = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false),
Active = table.Column<bool>(type: "boolean", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Slugs", x => x.Id);
});
// Create Slugs for existing Creators
migrationBuilder.Sql(@"
INSERT INTO ""Content"".""Slugs"" (""Id"", ""Name"", ""CreatedBy"", ""CreatedAt"", ""ReservedUntil"", ""Active"")
SELECT ""Id"", ""Name"", ""CreatedBy"", ""CreatedAt"", ""CreatedAt"", TRUE
FROM ""Content"".""Creators""
WHERE ""Name"" IS NOT NULL
");
// Update Creators to reference Slugs
migrationBuilder.Sql(@"
UPDATE ""Content"".""Creators""
SET ""SlugsId"" = (SELECT ""Id"" FROM ""Content"".""Slugs"" WHERE ""Content"".""Slugs"".""Name"" = ""Content"".""Creators"".""Name"")
WHERE ""Name"" IS NOT NULL
");
// Make SlugsId non-nullable
migrationBuilder.AlterColumn<Guid>(
name: "SlugsId",
schema: "Content",
table: "Creators",
type: "uuid",
nullable: false,
oldClrType: typeof(Guid),
oldType: "uuid",
oldNullable: true);
// Create index for SlugsId
migrationBuilder.CreateIndex(
name: "IX_Creators_SlugsId",
schema: "Content",
table: "Creators",
column: "SlugsId");
// Create index for NormalizedName in Slugs
migrationBuilder.CreateIndex(
name: "IX_Slugs_NormalizedName",
schema: "Content",
table: "Slugs",
column: "NormalizedName",
unique: true);
// Add foreign key constraint
migrationBuilder.AddForeignKey(
name: "FK_Creators_Slugs_SlugsId",
schema: "Content",
table: "Creators",
column: "SlugsId",
principalSchema: "Content",
principalTable: "Slugs",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
// Drop the Name column
migrationBuilder.DropColumn(
name: "Name",
schema: "Content",
table: "Creators");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_Creators_Slugs_SlugsId",
schema: "Content",
table: "Creators");
migrationBuilder.DropTable(
name: "Slugs",
schema: "Content");
migrationBuilder.DropIndex(
name: "IX_Creators_SlugsId",
schema: "Content",
table: "Creators");
migrationBuilder.DropColumn(
name: "SlugsId",
schema: "Content",
table: "Creators");
migrationBuilder.AddColumn<string>(
name: "Name",
schema: "Content",
table: "Creators",
type: "character varying(255)",
maxLength: 255,
nullable: false,
defaultValue: "");
migrationBuilder.AddColumn<string>(
name: "NormalizedName",
schema: "Content",
table: "Creators",
type: "character varying(255)",
maxLength: 255,
nullable: false,
computedColumnSql: "LOWER( \"Content\".\"Creators\".\"Name\")",
stored: true);
migrationBuilder.CreateIndex(
name: "IX_Creators_NormalizedName",
schema: "Content",
table: "Creators",
column: "NormalizedName",
unique: true);
}
}
}

View File

@@ -1,376 +0,0 @@
// <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("20250208043324_RemoveColors")]
partial class RemoveColors
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasDefaultSchema("Content")
.HasAnnotation("ProductVersion", "8.0.10")
.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(512)
.HasColumnType("character varying(512)");
b.Property<string>("Title")
.IsRequired()
.HasMaxLength(128)
.HasColumnType("character varying(128)");
b.Property<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<Guid>("SlugsId")
.HasColumnType("uuid");
b.Property<string>("Title")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b.Property<bool>("Verified")
.HasColumnType("boolean");
b.HasKey("Id");
b.HasIndex("SlugsId");
b.ToTable("Creators", "Content");
});
modelBuilder.Entity("Hutopy.Web.Features.Contents.Data.Slugs", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<bool>("Active")
.HasColumnType("boolean");
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.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")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
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.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 =>
{
b1.Property<Guid>("CreatorId")
.HasColumnType("uuid");
b1.Property<string>("Banner")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b1.Property<string>("Logo")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
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(2000)
.HasColumnType("character varying(2000)");
b1.Property<string>("Image2Url")
.IsRequired()
.HasMaxLength(2000)
.HasColumnType("character varying(2000)");
b1.Property<string>("Image3Url")
.IsRequired()
.HasMaxLength(2000)
.HasColumnType("character varying(2000)");
b1.Property<string>("Image4Url")
.IsRequired()
.HasMaxLength(2000)
.HasColumnType("character varying(2000)");
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(2000)
.HasColumnType("character varying(2000)");
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(2000)
.HasColumnType("character varying(2000)");
b1.Property<string>("VideoUrlMain")
.IsRequired()
.HasMaxLength(2000)
.HasColumnType("character varying(2000)");
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(255)
.HasColumnType("character varying(255)");
b1.Property<string>("InstagramUrl")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b1.Property<string>("LinkedInUrl")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b1.Property<string>("RedditUrl")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b1.Property<string>("TikTokUrl")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b1.Property<string>("WebsiteUrl")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b1.Property<string>("XUrl")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b1.Property<string>("YoutubeUrl")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b1.HasKey("CreatorId");
b1.ToTable("Socials", "Content");
b1.WithOwner()
.HasForeignKey("CreatorId");
});
b.Navigation("Images")
.IsRequired();
b.Navigation("PresentationInfos")
.IsRequired();
b.Navigation("Slugs");
b.Navigation("Socials")
.IsRequired();
});
#pragma warning restore 612, 618
}
}
}

View File

@@ -1,52 +0,0 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Hutopy.Web.Features.Contents.Data.Migrations
{
/// <inheritdoc />
public partial class RemoveColors : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "Colors",
schema: "Content");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "Colors",
schema: "Content",
columns: table => new
{
CreatorId = table.Column<Guid>(type: "uuid", nullable: false),
Background = table.Column<string>(type: "character varying(9)", maxLength: 9, nullable: false),
Error = table.Column<string>(type: "character varying(9)", maxLength: 9, nullable: false),
OnBackground = table.Column<string>(type: "character varying(9)", maxLength: 9, nullable: false),
OnError = table.Column<string>(type: "character varying(9)", maxLength: 9, nullable: false),
OnPrimary = table.Column<string>(type: "character varying(9)", maxLength: 9, nullable: false),
OnSecondary = table.Column<string>(type: "character varying(9)", maxLength: 9, nullable: false),
OnSurface = table.Column<string>(type: "character varying(9)", maxLength: 9, nullable: false),
Primary = table.Column<string>(type: "character varying(9)", maxLength: 9, nullable: false),
Secondary = table.Column<string>(type: "character varying(9)", maxLength: 9, nullable: false),
Surface = table.Column<string>(type: "character varying(9)", maxLength: 9, nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Colors", x => x.CreatorId);
table.ForeignKey(
name: "FK_Colors_Creators_CreatorId",
column: x => x.CreatorId,
principalSchema: "Content",
principalTable: "Creators",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
}
}
}

View File

@@ -1,376 +0,0 @@
// <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("20250402024746_EnsureUrlsAre1024Chars")]
partial class EnsureUrlsAre1024Chars
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasDefaultSchema("Content")
.HasAnnotation("ProductVersion", "8.0.14")
.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(1024)
.HasColumnType("character varying(1024)");
b.Property<string>("ThumbnailUrl")
.HasMaxLength(1024)
.HasColumnType("character varying(1024)");
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<Guid>("SlugsId")
.HasColumnType("uuid");
b.Property<string>("Title")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b.Property<bool>("Verified")
.HasColumnType("boolean");
b.HasKey("Id");
b.HasIndex("SlugsId");
b.ToTable("Creators", "Content");
});
modelBuilder.Entity("Hutopy.Web.Features.Contents.Data.Slugs", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<bool>("Active")
.HasColumnType("boolean");
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.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")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
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.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 =>
{
b1.Property<Guid>("CreatorId")
.HasColumnType("uuid");
b1.Property<string>("Banner")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b1.Property<string>("Logo")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
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(1024)
.HasColumnType("character varying(1024)");
b1.Property<string>("Image2Url")
.IsRequired()
.HasMaxLength(1024)
.HasColumnType("character varying(1024)");
b1.Property<string>("Image3Url")
.IsRequired()
.HasMaxLength(1024)
.HasColumnType("character varying(1024)");
b1.Property<string>("Image4Url")
.IsRequired()
.HasMaxLength(1024)
.HasColumnType("character varying(1024)");
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(1024)
.HasColumnType("character varying(1024)");
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(1024)
.HasColumnType("character varying(1024)");
b1.Property<string>("VideoUrlMain")
.IsRequired()
.HasMaxLength(1024)
.HasColumnType("character varying(1024)");
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(1024)
.HasColumnType("character varying(1024)");
b1.Property<string>("InstagramUrl")
.HasMaxLength(1024)
.HasColumnType("character varying(1024)");
b1.Property<string>("LinkedInUrl")
.HasMaxLength(1024)
.HasColumnType("character varying(1024)");
b1.Property<string>("RedditUrl")
.HasMaxLength(1024)
.HasColumnType("character varying(1024)");
b1.Property<string>("TikTokUrl")
.HasMaxLength(1024)
.HasColumnType("character varying(1024)");
b1.Property<string>("WebsiteUrl")
.HasMaxLength(1024)
.HasColumnType("character varying(1024)");
b1.Property<string>("XUrl")
.HasMaxLength(1024)
.HasColumnType("character varying(1024)");
b1.Property<string>("YoutubeUrl")
.HasMaxLength(1024)
.HasColumnType("character varying(1024)");
b1.HasKey("CreatorId");
b1.ToTable("Socials", "Content");
b1.WithOwner()
.HasForeignKey("CreatorId");
});
b.Navigation("Images")
.IsRequired();
b.Navigation("PresentationInfos")
.IsRequired();
b.Navigation("Slugs");
b.Navigation("Socials")
.IsRequired();
});
#pragma warning restore 612, 618
}
}
}

View File

@@ -1,412 +0,0 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Hutopy.Web.Features.Contents.Data.Migrations
{
/// <inheritdoc />
public partial class EnsureUrlsAre1024Chars : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<string>(
name: "YoutubeUrl",
schema: "Content",
table: "Socials",
type: "character varying(1024)",
maxLength: 1024,
nullable: true,
oldClrType: typeof(string),
oldType: "character varying(255)",
oldMaxLength: 255,
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "XUrl",
schema: "Content",
table: "Socials",
type: "character varying(1024)",
maxLength: 1024,
nullable: true,
oldClrType: typeof(string),
oldType: "character varying(255)",
oldMaxLength: 255,
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "WebsiteUrl",
schema: "Content",
table: "Socials",
type: "character varying(1024)",
maxLength: 1024,
nullable: true,
oldClrType: typeof(string),
oldType: "character varying(255)",
oldMaxLength: 255,
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "TikTokUrl",
schema: "Content",
table: "Socials",
type: "character varying(1024)",
maxLength: 1024,
nullable: true,
oldClrType: typeof(string),
oldType: "character varying(255)",
oldMaxLength: 255,
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "RedditUrl",
schema: "Content",
table: "Socials",
type: "character varying(1024)",
maxLength: 1024,
nullable: true,
oldClrType: typeof(string),
oldType: "character varying(255)",
oldMaxLength: 255,
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "LinkedInUrl",
schema: "Content",
table: "Socials",
type: "character varying(1024)",
maxLength: 1024,
nullable: true,
oldClrType: typeof(string),
oldType: "character varying(255)",
oldMaxLength: 255,
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "InstagramUrl",
schema: "Content",
table: "Socials",
type: "character varying(1024)",
maxLength: 1024,
nullable: true,
oldClrType: typeof(string),
oldType: "character varying(255)",
oldMaxLength: 255,
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "FacebookUrl",
schema: "Content",
table: "Socials",
type: "character varying(1024)",
maxLength: 1024,
nullable: true,
oldClrType: typeof(string),
oldType: "character varying(255)",
oldMaxLength: 255,
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "VideoUrl",
schema: "Content",
table: "PresentationInfos",
type: "character varying(1024)",
maxLength: 1024,
nullable: false,
oldClrType: typeof(string),
oldType: "character varying(2000)",
oldMaxLength: 2000);
migrationBuilder.AlterColumn<string>(
name: "VideoUrlMain",
schema: "Content",
table: "PresentationInfos",
type: "character varying(1024)",
maxLength: 1024,
nullable: false,
oldClrType: typeof(string),
oldType: "character varying(2000)",
oldMaxLength: 2000);
migrationBuilder.AlterColumn<string>(
name: "MainImageUrl",
schema: "Content",
table: "PresentationInfos",
type: "character varying(1024)",
maxLength: 1024,
nullable: false,
oldClrType: typeof(string),
oldType: "character varying(2000)",
oldMaxLength: 2000);
migrationBuilder.AlterColumn<string>(
name: "Image4Url",
schema: "Content",
table: "PresentationInfos",
type: "character varying(1024)",
maxLength: 1024,
nullable: false,
oldClrType: typeof(string),
oldType: "character varying(2000)",
oldMaxLength: 2000);
migrationBuilder.AlterColumn<string>(
name: "Image3Url",
schema: "Content",
table: "PresentationInfos",
type: "character varying(1024)",
maxLength: 1024,
nullable: false,
oldClrType: typeof(string),
oldType: "character varying(2000)",
oldMaxLength: 2000);
migrationBuilder.AlterColumn<string>(
name: "Image2Url",
schema: "Content",
table: "PresentationInfos",
type: "character varying(1024)",
maxLength: 1024,
nullable: false,
oldClrType: typeof(string),
oldType: "character varying(2000)",
oldMaxLength: 2000);
migrationBuilder.AlterColumn<string>(
name: "Image1Url",
schema: "Content",
table: "PresentationInfos",
type: "character varying(1024)",
maxLength: 1024,
nullable: false,
oldClrType: typeof(string),
oldType: "character varying(2000)",
oldMaxLength: 2000);
migrationBuilder.AlterColumn<string>(
name: "ThumbnailUrl",
schema: "Content",
table: "Contents",
type: "character varying(1024)",
maxLength: 1024,
nullable: true,
oldClrType: typeof(string),
oldType: "character varying(512)",
oldMaxLength: 512,
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "HtmlFileUrl",
schema: "Content",
table: "Contents",
type: "character varying(1024)",
maxLength: 1024,
nullable: true,
oldClrType: typeof(string),
oldType: "character varying(2048)",
oldMaxLength: 2048,
oldNullable: true);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<string>(
name: "YoutubeUrl",
schema: "Content",
table: "Socials",
type: "character varying(255)",
maxLength: 255,
nullable: true,
oldClrType: typeof(string),
oldType: "character varying(1024)",
oldMaxLength: 1024,
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "XUrl",
schema: "Content",
table: "Socials",
type: "character varying(255)",
maxLength: 255,
nullable: true,
oldClrType: typeof(string),
oldType: "character varying(1024)",
oldMaxLength: 1024,
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "WebsiteUrl",
schema: "Content",
table: "Socials",
type: "character varying(255)",
maxLength: 255,
nullable: true,
oldClrType: typeof(string),
oldType: "character varying(1024)",
oldMaxLength: 1024,
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "TikTokUrl",
schema: "Content",
table: "Socials",
type: "character varying(255)",
maxLength: 255,
nullable: true,
oldClrType: typeof(string),
oldType: "character varying(1024)",
oldMaxLength: 1024,
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "RedditUrl",
schema: "Content",
table: "Socials",
type: "character varying(255)",
maxLength: 255,
nullable: true,
oldClrType: typeof(string),
oldType: "character varying(1024)",
oldMaxLength: 1024,
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "LinkedInUrl",
schema: "Content",
table: "Socials",
type: "character varying(255)",
maxLength: 255,
nullable: true,
oldClrType: typeof(string),
oldType: "character varying(1024)",
oldMaxLength: 1024,
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "InstagramUrl",
schema: "Content",
table: "Socials",
type: "character varying(255)",
maxLength: 255,
nullable: true,
oldClrType: typeof(string),
oldType: "character varying(1024)",
oldMaxLength: 1024,
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "FacebookUrl",
schema: "Content",
table: "Socials",
type: "character varying(255)",
maxLength: 255,
nullable: true,
oldClrType: typeof(string),
oldType: "character varying(1024)",
oldMaxLength: 1024,
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "VideoUrl",
schema: "Content",
table: "PresentationInfos",
type: "character varying(2000)",
maxLength: 2000,
nullable: false,
oldClrType: typeof(string),
oldType: "character varying(1024)",
oldMaxLength: 1024);
migrationBuilder.AlterColumn<string>(
name: "VideoUrlMain",
schema: "Content",
table: "PresentationInfos",
type: "character varying(2000)",
maxLength: 2000,
nullable: false,
oldClrType: typeof(string),
oldType: "character varying(1024)",
oldMaxLength: 1024);
migrationBuilder.AlterColumn<string>(
name: "MainImageUrl",
schema: "Content",
table: "PresentationInfos",
type: "character varying(2000)",
maxLength: 2000,
nullable: false,
oldClrType: typeof(string),
oldType: "character varying(1024)",
oldMaxLength: 1024);
migrationBuilder.AlterColumn<string>(
name: "Image4Url",
schema: "Content",
table: "PresentationInfos",
type: "character varying(2000)",
maxLength: 2000,
nullable: false,
oldClrType: typeof(string),
oldType: "character varying(1024)",
oldMaxLength: 1024);
migrationBuilder.AlterColumn<string>(
name: "Image3Url",
schema: "Content",
table: "PresentationInfos",
type: "character varying(2000)",
maxLength: 2000,
nullable: false,
oldClrType: typeof(string),
oldType: "character varying(1024)",
oldMaxLength: 1024);
migrationBuilder.AlterColumn<string>(
name: "Image2Url",
schema: "Content",
table: "PresentationInfos",
type: "character varying(2000)",
maxLength: 2000,
nullable: false,
oldClrType: typeof(string),
oldType: "character varying(1024)",
oldMaxLength: 1024);
migrationBuilder.AlterColumn<string>(
name: "Image1Url",
schema: "Content",
table: "PresentationInfos",
type: "character varying(2000)",
maxLength: 2000,
nullable: false,
oldClrType: typeof(string),
oldType: "character varying(1024)",
oldMaxLength: 1024);
migrationBuilder.AlterColumn<string>(
name: "ThumbnailUrl",
schema: "Content",
table: "Contents",
type: "character varying(512)",
maxLength: 512,
nullable: true,
oldClrType: typeof(string),
oldType: "character varying(1024)",
oldMaxLength: 1024,
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "HtmlFileUrl",
schema: "Content",
table: "Contents",
type: "character varying(2048)",
maxLength: 2048,
nullable: true,
oldClrType: typeof(string),
oldType: "character varying(1024)",
oldMaxLength: 1024,
oldNullable: true);
}
}
}

View File

@@ -1,376 +0,0 @@
// <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("20250403035555_UrlsTo2048Chars")]
partial class UrlsTo2048Chars
{
/// <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<Guid>("SlugsId")
.HasColumnType("uuid");
b.Property<string>("Title")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b.Property<bool>("Verified")
.HasColumnType("boolean");
b.HasKey("Id");
b.HasIndex("SlugsId");
b.ToTable("Creators", "Content");
});
modelBuilder.Entity("Hutopy.Web.Features.Contents.Data.Slugs", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<bool>("Active")
.HasColumnType("boolean");
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.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")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
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.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 =>
{
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("Slugs");
b.Navigation("Socials")
.IsRequired();
});
#pragma warning restore 612, 618
}
}
}

View File

@@ -1,460 +0,0 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Hutopy.Web.Features.Contents.Data.Migrations
{
/// <inheritdoc />
public partial class UrlsTo2048Chars : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<string>(
name: "YoutubeUrl",
schema: "Content",
table: "Socials",
type: "character varying(2048)",
maxLength: 2048,
nullable: true,
oldClrType: typeof(string),
oldType: "character varying(1024)",
oldMaxLength: 1024,
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "XUrl",
schema: "Content",
table: "Socials",
type: "character varying(2048)",
maxLength: 2048,
nullable: true,
oldClrType: typeof(string),
oldType: "character varying(1024)",
oldMaxLength: 1024,
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "WebsiteUrl",
schema: "Content",
table: "Socials",
type: "character varying(2048)",
maxLength: 2048,
nullable: true,
oldClrType: typeof(string),
oldType: "character varying(1024)",
oldMaxLength: 1024,
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "TikTokUrl",
schema: "Content",
table: "Socials",
type: "character varying(2048)",
maxLength: 2048,
nullable: true,
oldClrType: typeof(string),
oldType: "character varying(1024)",
oldMaxLength: 1024,
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "RedditUrl",
schema: "Content",
table: "Socials",
type: "character varying(2048)",
maxLength: 2048,
nullable: true,
oldClrType: typeof(string),
oldType: "character varying(1024)",
oldMaxLength: 1024,
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "LinkedInUrl",
schema: "Content",
table: "Socials",
type: "character varying(2048)",
maxLength: 2048,
nullable: true,
oldClrType: typeof(string),
oldType: "character varying(1024)",
oldMaxLength: 1024,
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "InstagramUrl",
schema: "Content",
table: "Socials",
type: "character varying(2048)",
maxLength: 2048,
nullable: true,
oldClrType: typeof(string),
oldType: "character varying(1024)",
oldMaxLength: 1024,
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "FacebookUrl",
schema: "Content",
table: "Socials",
type: "character varying(2048)",
maxLength: 2048,
nullable: true,
oldClrType: typeof(string),
oldType: "character varying(1024)",
oldMaxLength: 1024,
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "VideoUrlMain",
schema: "Content",
table: "PresentationInfos",
type: "character varying(2048)",
maxLength: 2048,
nullable: false,
oldClrType: typeof(string),
oldType: "character varying(1024)",
oldMaxLength: 1024);
migrationBuilder.AlterColumn<string>(
name: "VideoUrl",
schema: "Content",
table: "PresentationInfos",
type: "character varying(2048)",
maxLength: 2048,
nullable: false,
oldClrType: typeof(string),
oldType: "character varying(1024)",
oldMaxLength: 1024);
migrationBuilder.AlterColumn<string>(
name: "MainImageUrl",
schema: "Content",
table: "PresentationInfos",
type: "character varying(2048)",
maxLength: 2048,
nullable: false,
oldClrType: typeof(string),
oldType: "character varying(1024)",
oldMaxLength: 1024);
migrationBuilder.AlterColumn<string>(
name: "Image4Url",
schema: "Content",
table: "PresentationInfos",
type: "character varying(2048)",
maxLength: 2048,
nullable: false,
oldClrType: typeof(string),
oldType: "character varying(1024)",
oldMaxLength: 1024);
migrationBuilder.AlterColumn<string>(
name: "Image3Url",
schema: "Content",
table: "PresentationInfos",
type: "character varying(2048)",
maxLength: 2048,
nullable: false,
oldClrType: typeof(string),
oldType: "character varying(1024)",
oldMaxLength: 1024);
migrationBuilder.AlterColumn<string>(
name: "Image2Url",
schema: "Content",
table: "PresentationInfos",
type: "character varying(2048)",
maxLength: 2048,
nullable: false,
oldClrType: typeof(string),
oldType: "character varying(1024)",
oldMaxLength: 1024);
migrationBuilder.AlterColumn<string>(
name: "Image1Url",
schema: "Content",
table: "PresentationInfos",
type: "character varying(2048)",
maxLength: 2048,
nullable: false,
oldClrType: typeof(string),
oldType: "character varying(1024)",
oldMaxLength: 1024);
migrationBuilder.AlterColumn<string>(
name: "Logo",
schema: "Content",
table: "Images",
type: "character varying(2048)",
maxLength: 2048,
nullable: true,
oldClrType: typeof(string),
oldType: "character varying(255)",
oldMaxLength: 255,
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "Banner",
schema: "Content",
table: "Images",
type: "character varying(2048)",
maxLength: 2048,
nullable: true,
oldClrType: typeof(string),
oldType: "character varying(255)",
oldMaxLength: 255,
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "ThumbnailUrl",
schema: "Content",
table: "Contents",
type: "character varying(2048)",
maxLength: 2048,
nullable: true,
oldClrType: typeof(string),
oldType: "character varying(1024)",
oldMaxLength: 1024,
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "HtmlFileUrl",
schema: "Content",
table: "Contents",
type: "character varying(2048)",
maxLength: 2048,
nullable: true,
oldClrType: typeof(string),
oldType: "character varying(1024)",
oldMaxLength: 1024,
oldNullable: true);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<string>(
name: "YoutubeUrl",
schema: "Content",
table: "Socials",
type: "character varying(1024)",
maxLength: 1024,
nullable: true,
oldClrType: typeof(string),
oldType: "character varying(2048)",
oldMaxLength: 2048,
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "XUrl",
schema: "Content",
table: "Socials",
type: "character varying(1024)",
maxLength: 1024,
nullable: true,
oldClrType: typeof(string),
oldType: "character varying(2048)",
oldMaxLength: 2048,
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "WebsiteUrl",
schema: "Content",
table: "Socials",
type: "character varying(1024)",
maxLength: 1024,
nullable: true,
oldClrType: typeof(string),
oldType: "character varying(2048)",
oldMaxLength: 2048,
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "TikTokUrl",
schema: "Content",
table: "Socials",
type: "character varying(1024)",
maxLength: 1024,
nullable: true,
oldClrType: typeof(string),
oldType: "character varying(2048)",
oldMaxLength: 2048,
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "RedditUrl",
schema: "Content",
table: "Socials",
type: "character varying(1024)",
maxLength: 1024,
nullable: true,
oldClrType: typeof(string),
oldType: "character varying(2048)",
oldMaxLength: 2048,
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "LinkedInUrl",
schema: "Content",
table: "Socials",
type: "character varying(1024)",
maxLength: 1024,
nullable: true,
oldClrType: typeof(string),
oldType: "character varying(2048)",
oldMaxLength: 2048,
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "InstagramUrl",
schema: "Content",
table: "Socials",
type: "character varying(1024)",
maxLength: 1024,
nullable: true,
oldClrType: typeof(string),
oldType: "character varying(2048)",
oldMaxLength: 2048,
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "FacebookUrl",
schema: "Content",
table: "Socials",
type: "character varying(1024)",
maxLength: 1024,
nullable: true,
oldClrType: typeof(string),
oldType: "character varying(2048)",
oldMaxLength: 2048,
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "VideoUrlMain",
schema: "Content",
table: "PresentationInfos",
type: "character varying(1024)",
maxLength: 1024,
nullable: false,
oldClrType: typeof(string),
oldType: "character varying(2048)",
oldMaxLength: 2048);
migrationBuilder.AlterColumn<string>(
name: "VideoUrl",
schema: "Content",
table: "PresentationInfos",
type: "character varying(1024)",
maxLength: 1024,
nullable: false,
oldClrType: typeof(string),
oldType: "character varying(2048)",
oldMaxLength: 2048);
migrationBuilder.AlterColumn<string>(
name: "MainImageUrl",
schema: "Content",
table: "PresentationInfos",
type: "character varying(1024)",
maxLength: 1024,
nullable: false,
oldClrType: typeof(string),
oldType: "character varying(2048)",
oldMaxLength: 2048);
migrationBuilder.AlterColumn<string>(
name: "Image4Url",
schema: "Content",
table: "PresentationInfos",
type: "character varying(1024)",
maxLength: 1024,
nullable: false,
oldClrType: typeof(string),
oldType: "character varying(2048)",
oldMaxLength: 2048);
migrationBuilder.AlterColumn<string>(
name: "Image3Url",
schema: "Content",
table: "PresentationInfos",
type: "character varying(1024)",
maxLength: 1024,
nullable: false,
oldClrType: typeof(string),
oldType: "character varying(2048)",
oldMaxLength: 2048);
migrationBuilder.AlterColumn<string>(
name: "Image2Url",
schema: "Content",
table: "PresentationInfos",
type: "character varying(1024)",
maxLength: 1024,
nullable: false,
oldClrType: typeof(string),
oldType: "character varying(2048)",
oldMaxLength: 2048);
migrationBuilder.AlterColumn<string>(
name: "Image1Url",
schema: "Content",
table: "PresentationInfos",
type: "character varying(1024)",
maxLength: 1024,
nullable: false,
oldClrType: typeof(string),
oldType: "character varying(2048)",
oldMaxLength: 2048);
migrationBuilder.AlterColumn<string>(
name: "Logo",
schema: "Content",
table: "Images",
type: "character varying(255)",
maxLength: 255,
nullable: true,
oldClrType: typeof(string),
oldType: "character varying(2048)",
oldMaxLength: 2048,
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "Banner",
schema: "Content",
table: "Images",
type: "character varying(255)",
maxLength: 255,
nullable: true,
oldClrType: typeof(string),
oldType: "character varying(2048)",
oldMaxLength: 2048,
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "ThumbnailUrl",
schema: "Content",
table: "Contents",
type: "character varying(1024)",
maxLength: 1024,
nullable: true,
oldClrType: typeof(string),
oldType: "character varying(2048)",
oldMaxLength: 2048,
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "HtmlFileUrl",
schema: "Content",
table: "Contents",
type: "character varying(1024)",
maxLength: 1024,
nullable: true,
oldClrType: typeof(string),
oldType: "character varying(2048)",
oldMaxLength: 2048,
oldNullable: true);
}
}
}

View File

@@ -1,387 +0,0 @@
// <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("20250415064846_AddsCreatorDeletionAudits")]
partial class AddsCreatorDeletionAudits
{
/// <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<Guid>("SlugsId")
.HasColumnType("uuid");
b.Property<string>("Title")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b.Property<bool>("Verified")
.HasColumnType("boolean");
b.HasKey("Id");
b.HasIndex("SlugsId");
b.ToTable("Creators", "Content");
});
modelBuilder.Entity("Hutopy.Web.Features.Contents.Data.Slugs", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<bool>("Active")
.HasColumnType("boolean");
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.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")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
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.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 =>
{
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("Slugs");
b.Navigation("Socials")
.IsRequired();
});
#pragma warning restore 612, 618
}
}
}

View File

@@ -1,57 +0,0 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Hutopy.Web.Features.Contents.Data.Migrations
{
/// <inheritdoc />
public partial class AddsCreatorDeletionAudits : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<DateTimeOffset>(
name: "DeletedAt",
schema: "Content",
table: "Creators",
type: "timestamp with time zone",
nullable: true);
migrationBuilder.AddColumn<Guid>(
name: "DeletedBy",
schema: "Content",
table: "Creators",
type: "uuid",
nullable: true);
migrationBuilder.AddColumn<bool>(
name: "IsDeleted",
schema: "Content",
table: "Creators",
type: "boolean",
nullable: false,
computedColumnSql: "\"DeletedAt\" IS NOT NULL",
stored: true);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "IsDeleted",
schema: "Content",
table: "Creators");
migrationBuilder.DropColumn(
name: "DeletedAt",
schema: "Content",
table: "Creators");
migrationBuilder.DropColumn(
name: "DeletedBy",
schema: "Content",
table: "Creators");
}
}
}

View File

@@ -1,385 +0,0 @@
// <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("20250415065154_AddsDeleteToContentQueryFilter")]
partial class AddsDeleteToContentQueryFilter
{
/// <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<Guid>("SlugsId")
.HasColumnType("uuid");
b.Property<string>("Title")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b.Property<bool>("Verified")
.HasColumnType("boolean");
b.HasKey("Id");
b.HasIndex("SlugsId");
b.ToTable("Creators", "Content");
});
modelBuilder.Entity("Hutopy.Web.Features.Contents.Data.Slugs", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<bool>("Active")
.HasColumnType("boolean");
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.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.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 =>
{
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("Slugs");
b.Navigation("Socials")
.IsRequired();
});
#pragma warning restore 612, 618
}
}
}

View File

@@ -1,47 +0,0 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Hutopy.Web.Features.Contents.Data.Migrations
{
/// <inheritdoc />
public partial class AddsDeleteToContentQueryFilter : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_Contents_Creators_CreatedBy",
schema: "Content",
table: "Contents");
migrationBuilder.AddForeignKey(
name: "FK_Contents_Creators_CreatedBy",
schema: "Content",
table: "Contents",
column: "CreatedBy",
principalSchema: "Content",
principalTable: "Creators",
principalColumn: "Id");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_Contents_Creators_CreatedBy",
schema: "Content",
table: "Contents");
migrationBuilder.AddForeignKey(
name: "FK_Contents_Creators_CreatedBy",
schema: "Content",
table: "Contents",
column: "CreatedBy",
principalSchema: "Content",
principalTable: "Creators",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
}
}
}

View File

@@ -1,382 +0,0 @@
// <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
}
}
}

View File

@@ -1,111 +0,0 @@
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);
}
}
}

View File

@@ -1,385 +0,0 @@
// <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("20250415080713_AddContentCreatorId")]
partial class AddContentCreatorId
{
/// <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<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("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.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
}
}
}

View File

@@ -1,82 +0,0 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Hutopy.Web.Features.Contents.Data.Migrations
{
/// <inheritdoc />
public partial class AddContentCreatorId : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_Contents_Creators_CreatedBy",
schema: "Content",
table: "Contents");
migrationBuilder.DropIndex(
name: "IX_Contents_CreatedBy",
schema: "Content",
table: "Contents");
migrationBuilder.AddColumn<Guid>(
name: "CreatorId",
schema: "Content",
table: "Contents",
type: "uuid",
nullable: false,
defaultValue: new Guid("00000000-0000-0000-0000-000000000000"));
migrationBuilder.CreateIndex(
name: "IX_Contents_CreatorId",
schema: "Content",
table: "Contents",
column: "CreatorId");
migrationBuilder.AddForeignKey(
name: "FK_Contents_Creators_CreatorId",
schema: "Content",
table: "Contents",
column: "CreatorId",
principalSchema: "Content",
principalTable: "Creators",
principalColumn: "Id");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_Contents_Creators_CreatorId",
schema: "Content",
table: "Contents");
migrationBuilder.DropIndex(
name: "IX_Contents_CreatorId",
schema: "Content",
table: "Contents");
migrationBuilder.DropColumn(
name: "CreatorId",
schema: "Content",
table: "Contents");
migrationBuilder.CreateIndex(
name: "IX_Contents_CreatedBy",
schema: "Content",
table: "Contents",
column: "CreatedBy");
migrationBuilder.AddForeignKey(
name: "FK_Contents_Creators_CreatedBy",
schema: "Content",
table: "Contents",
column: "CreatedBy",
principalSchema: "Content",
principalTable: "Creators",
principalColumn: "Id");
}
}
}

View File

@@ -1,301 +0,0 @@
// <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
}
}
}

View File

@@ -1,137 +0,0 @@
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);
});
}
}
}

View File

@@ -1,407 +0,0 @@
// <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
}
}
}

View File

@@ -1,81 +0,0 @@
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");
}
}
}

View File

@@ -1,399 +0,0 @@
// <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
}
}
}

View File

@@ -1,44 +0,0 @@
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);
}
}
}

View File

@@ -1,398 +0,0 @@
// <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("20250425043506_CreatorDescriptionToText")]
partial class CreatorDescriptionToText
{
/// <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()
.HasColumnType("text");
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
}
}
}

View File

@@ -1,38 +0,0 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Hutopy.Web.Features.Contents.Data.Migrations
{
/// <inheritdoc />
public partial class CreatorDescriptionToText : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<string>(
name: "Description",
schema: "Content",
table: "Presentation",
type: "text",
nullable: false,
oldClrType: typeof(string),
oldType: "character varying(2000)",
oldMaxLength: 2000);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<string>(
name: "Description",
schema: "Content",
table: "Presentation",
type: "character varying(2000)",
maxLength: 2000,
nullable: false,
oldClrType: typeof(string),
oldType: "text");
}
}
}

View File

@@ -1,403 +0,0 @@
// <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("20250526174825_AddThumbnailUrlToPhoto")]
partial class AddThumbnailUrlToPhoto
{
/// <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>("OriginalUrl")
.IsRequired()
.HasMaxLength(2048)
.HasColumnType("character varying(2048)");
b.Property<string>("ThumbnailUrl")
.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()
.HasColumnType("text");
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
}
}
}

View File

@@ -1,44 +0,0 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Hutopy.Web.Features.Contents.Data.Migrations
{
/// <inheritdoc />
public partial class AddThumbnailUrlToPhoto : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.RenameColumn(
name: "PhotoUrl",
schema: "Content",
table: "AlbumPhotos",
newName: "OriginalUrl");
migrationBuilder.AddColumn<string>(
name: "ThumbnailUrl",
schema: "Content",
table: "AlbumPhotos",
type: "character varying(2048)",
maxLength: 2048,
nullable: false,
defaultValue: "");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "ThumbnailUrl",
schema: "Content",
table: "AlbumPhotos");
migrationBuilder.RenameColumn(
name: "OriginalUrl",
schema: "Content",
table: "AlbumPhotos",
newName: "PhotoUrl");
}
}
}

View File

@@ -1,400 +0,0 @@
// <auto-generated />
using System;
using Hutopy.Web.Features.Contents.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
#nullable disable
namespace Hutopy.Web.Features.Contents.Data.Migrations
{
[DbContext(typeof(ContentDbContext))]
partial class ContentDbContextModelSnapshot : ModelSnapshot
{
protected override void BuildModel(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>("OriginalUrl")
.IsRequired()
.HasMaxLength(2048)
.HasColumnType("character varying(2048)");
b.Property<string>("ThumbnailUrl")
.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()
.HasColumnType("text");
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
}
}
}

View File

@@ -1,41 +0,0 @@
namespace Hutopy.Web.Features.Contents.Data;
public class SlugPurger(ContentDbContext context)
{
private static readonly SemaphoreSlim _semaphore = new(1, 1);
private static DateTimeOffset _lastPurgeTime = DateTimeOffset.MinValue;
private static readonly TimeSpan _minTimeBetweenPurges = TimeSpan.FromSeconds(10);
public async Task PurgeExpiredSlugsAsync(CancellationToken ct)
{
// Try to acquire the semaphore
if (!await _semaphore.WaitAsync(0, ct))
{
// Another purge operation is in progress, skip this one
return;
}
try
{
var now = DateTimeOffset.UtcNow;
if (now - _lastPurgeTime < _minTimeBetweenPurges)
{
// Not enough time has passed since the last purge
return;
}
// Delete expired slugs that are not in use
await context
.Slugs
.Where(s => s.ReservedUntil < now && s.UsedBy == null)
.ExecuteDeleteAsync(ct);
// Update the last purge time regardless of whether we found expired slugs or not
_lastPurgeTime = now;
}
finally
{
_semaphore.Release();
}
}
}

View File

@@ -1,14 +0,0 @@
using System.ComponentModel.DataAnnotations;
namespace Hutopy.Web.Features.Contents.Data;
public class Slugs
{
public Guid Id { get; set; }
public Guid CreatedBy { get; set; }
public DateTimeOffset CreatedAt { get; init; }
public Guid? UsedBy { get; set; }
[MaxLength(128)] public string Name { get; set; } = null!;
[MaxLength(128)] public string NormalizedName { get; set; } = null!;
public DateTimeOffset ReservedUntil { get; set; }
}

View File

@@ -1,19 +0,0 @@
using Hutopy.Web.Features.Contents.Data;
using Hutopy.Web.Features.Contents.Handlers;
namespace Hutopy.Web.Features.Contents;
public static class DependencyInjection
{
public static WebApplicationBuilder AddContentModule(
this WebApplicationBuilder builder,
Action<DbContextOptionsBuilder>? configureAction = null)
{
builder.Services.AddDbContext<ContentDbContext>(configureAction);
builder.Services.AddScoped<ContentDbContextInitializer>();
builder.Services.Configure<ContentOptions>(builder.Configuration.GetSection(ContentOptions.ConfigurationSection));
builder.Services.AddScoped<SlugPurger>();
return builder;
}
}

View File

@@ -1,43 +0,0 @@
using Hutopy.Web.Features.Contents.Data;
using Hutopy.Web.Features.Memberships.Events;
namespace Hutopy.Web.Features.Contents.EventHandlers;
[UsedImplicitly]
public class StripeAccountConfiguredHandler(
ILogger<StripeAccountConfiguredHandler> logger,
IServiceScopeFactory scopeFactory)
: IEventHandler<StripeAccountConfigured>
{
public async Task HandleAsync(
StripeAccountConfigured eventModel,
CancellationToken ct)
{
using var scope = scopeFactory.CreateScope();
await using var dbContext = scope.ServiceProvider.GetRequiredService<ContentDbContext>();
var creator = await dbContext.FindAsync<Creator>(
[eventModel.CreatorId],
cancellationToken: ct);
if (creator is null)
{
logger.LogError(
"Creator with id {CreatorId} was not found.",
eventModel.CreatorId);
return;
}
creator.AcceptDonation = !string.IsNullOrWhiteSpace(eventModel.StripeAccountId);
var rows = await dbContext.SaveChangesAsync(ct);
if (rows is 0 or > 1)
{
logger.LogError(
"An error occured while updating Creator with id {CreatorId}: rows:{Rows}",
eventModel.CreatorId,
rows);
}
}
}

View File

@@ -1,194 +0,0 @@
using Hutopy.Web.Features.Contents.Data;
using Hutopy.Web.Common.Security;
using Hutopy.Web.Common.BlobStorage;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Processing;
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 OriginalUrl,
string ThumbnailUrl);
[PublicAPI]
public sealed class AddPhotoToAlbumRequestValidator : Validator<AddPhotoToAlbumRequest>
{
private const int MaxFileSizeBytes = 10 * 1024 * 1024; // 10MB
private static readonly string[] AllowedImageTypes =
{
"image/jpeg",
"image/png",
"image/gif",
"image/webp"
};
public AddPhotoToAlbumRequestValidator()
{
RuleFor(x => x.AlbumId)
.NotNull()
.NotEmpty();
RuleFor(x => x.PhotoId)
.NotNull()
.NotEmpty();
RuleFor(x => x.File)
.NotNull()
.NotEmpty()
.Must(file => AllowedImageTypes.Contains(file.ContentType))
.WithMessage("File must be a valid image (JPEG, PNG, GIF, or WebP)")
.Must(file => file.Length <= MaxFileSizeBytes)
.WithMessage($"File size must not exceed {MaxFileSizeBytes / 1024 / 1024}MB");
RuleFor(x => x.Caption)
.MaximumLength(255);
}
}
[PublicAPI]
public class AddPhotoToAlbumHandler(
ContentDbContext context,
AzureBlobStorage blobStorage)
: Endpoint<AddPhotoToAlbumRequest, AddPhotoToAlbumResponse>
{
private const int MaxThumbnailWidth = 500;
private const int MaxThumbnailHeight = 500;
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();
// Fetch the album we want to add photos to
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;
}
try
{
var (originalUrl, thumbnailUrl) = await ProcessAndUploadImage(request, ct);
// Get the next order number
var nextOrder = await context
.AlbumPhotos
.Where(p => p.AlbumId == request.AlbumId)
.MaxAsync(p => (int?)p.Order, ct) ?? 0;
// Create the album photo
var photo = new AlbumPhoto
{
Id = request.PhotoId,
CreatedBy = userId,
AlbumId = request.AlbumId,
OriginalUrl = originalUrl,
ThumbnailUrl = thumbnailUrl,
Caption = request.Caption,
Order = nextOrder + 1
};
context.AlbumPhotos.Add(photo);
await context.SaveChangesAsync(ct);
await SendOkAsync(
new AddPhotoToAlbumResponse(photo.Id, originalUrl, thumbnailUrl),
ct);
}
catch (UnknownImageFormatException)
{
await SendStringAsync("Invalid image format", 400, cancellation: ct);
}
catch (Exception ex)
{
await SendStringAsync("Error processing image", 500, cancellation: ct);
}
}
private async Task<(string originalUrl, string thumbnailUrl)> ProcessAndUploadImage(
AddPhotoToAlbumRequest request,
CancellationToken ct)
{
var originalFileName = Path.GetFileName(request.File.FileName);
var nameWithoutExt = Path.GetFileNameWithoutExtension(originalFileName);
var extension = Path.GetExtension(originalFileName);
var filenameOriginal = $"{nameWithoutExt}{extension}";
var filenameThumbnail = $"{nameWithoutExt}.thumbnail{extension}";
var blobOriginal = $"{SubDirectoryNames.Albums}/{request.AlbumId}/{filenameOriginal}";
var blobThumbnail = $"{SubDirectoryNames.Albums}/{request.AlbumId}/{filenameThumbnail}";
// Process the original image
await using var originalStream = request.File.OpenReadStream();
using var image = await Image.LoadAsync(originalStream, ct);
// Calculate target size while preserving the original aspect ratio
var originalWidth = image.Width;
var originalHeight = image.Height;
double ratioX = (double)MaxThumbnailWidth / originalWidth;
double ratioY = (double)MaxThumbnailHeight / originalHeight;
double ratio = Math.Min(ratioX, ratioY);
int newWidth = (int)(originalWidth * ratio);
int newHeight = (int)(originalHeight * ratio);
// Create thumbnail
using var thumbnailStream = new MemoryStream();
image.Mutate(x => x.Resize(newWidth, newHeight));
await image.SaveAsync(thumbnailStream, image.Metadata.DecodedImageFormat!, ct);
thumbnailStream.Position = 0;
// Upload both versions
var originalUrl = await blobStorage.UploadFileAsync(
ContainerNames.Creators,
blobOriginal,
request.File.OpenReadStream(),
request.File.ContentType,
ct);
var thumbnailUrl = await blobStorage.UploadFileAsync(
ContainerNames.Creators,
blobThumbnail,
thumbnailStream,
request.File.ContentType,
ct);
return (originalUrl, thumbnailUrl);
}
}

View File

@@ -1,91 +0,0 @@
using Hutopy.Web.Features.Contents.Data;
using Hutopy.Web.Features.Contents.Data.Enums;
namespace Hutopy.Web.Features.Contents.Handlers;
[PublicAPI]
public sealed class AddReactionRequest
{
public required Guid ContentId { get; set; }
public required string Reaction { get; set; }
public required Guid UserId { get; set; }
public required string UserName { get; set; }
}
[PublicAPI]
internal sealed class AddReactionRequestValidator
: Validator<AddReactionRequest>
{
public AddReactionRequestValidator()
{
RuleFor(r => r.Reaction)
.NotNull()
.Must(BeAValidReaction)
.WithMessage("'{PropertyValue}' is not a valid reaction.");
}
private bool BeAValidReaction(string reaction)
{
return Enum.TryParse(typeof(Reaction), reaction, true, out _);
}
}
[PublicAPI]
public class AddReaction(
ContentDbContext context)
: Endpoint<AddReactionRequest>
{
public override void Configure()
{
Post("/api/content/reaction");
Options(o => o.WithTags("Contents"));
}
public override async Task HandleAsync(
AddReactionRequest req,
CancellationToken ct)
{
var content = await context.Contents.SingleAsync(x => x.Id == req.ContentId, ct);
Reaction? reactionEnum;
if (Enum.TryParse(req.Reaction, true, out Reaction result))
{
reactionEnum = result;
}
else
{
reactionEnum = null;
}
var currentReaction = content.Reactions.SingleOrDefault(x => x.UserId == req.UserId);
// Already reacted or reaction didn't change, do nothing
if (currentReaction != null && currentReaction.Reaction == reactionEnum)
{
return;
}
// User has already reacted, remove the existing reaction
if (currentReaction != null)
{
content.Reactions.Remove(currentReaction);
}
// If the new reaction is valid, add or update the reaction
if (reactionEnum.HasValue)
{
var reaction = new ContentReaction
{
Reaction = reactionEnum.Value,
UserId = req.UserId,
UserName = req.UserName
};
content.Reactions.Add(reaction);
}
await context.SaveChangesAsync(ct);
}
}

View File

@@ -1,59 +0,0 @@
using Hutopy.Web.Common.BlobStorage;
using Hutopy.Web.Features.Contents.Data;
namespace Hutopy.Web.Features.Contents.Handlers;
[PublicAPI]
public record ChangeBannerRequest(
Guid CreatorId,
IFormFile File);
[PublicAPI]
public record ChangeBannerResponse(
string BlobUrl);
[PublicAPI]
public class ChangeBannerHandler(
ContentDbContext context,
AzureBlobStorage blobStorage)
: Endpoint<ChangeBannerRequest, ChangeBannerResponse>
{
public override void Configure()
{
Post("/api/creators/{CreatorId}/banner");
Options(o => o.WithTags("Creators"));
AllowFileUploads();
}
public override async Task HandleAsync(
ChangeBannerRequest request,
CancellationToken ct)
{
var creator = await context
.Creators
.SingleOrDefaultAsync(
c => c.Id == request.CreatorId,
cancellationToken: ct);
if (creator is null)
{
await SendNotFoundAsync(ct);
return;
}
var blobUrl = await blobStorage.UploadFileAsync(
ContainerNames.Creators,
$"{request.CreatorId}/{SubDirectoryNames.Profile}/{CommonFileNames.BannerPicture}",
request.File.OpenReadStream(),
request.File.ContentType,
ct);
creator.BannerUrl = $"{blobUrl}?t={DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()}";
await context.SaveChangesAsync(ct);
await SendOkAsync(
new ChangeBannerResponse(blobUrl),
ct);
}
}

View File

@@ -1,70 +0,0 @@
using FluentValidation;
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 ChangeEmailRequest(
Guid CreatorId,
string? Email);
[PublicAPI]
public sealed class ChangeEmailRequestValidator : Validator<ChangeEmailRequest>
{
public ChangeEmailRequestValidator()
{
RuleFor(x => x.CreatorId)
.NotEmpty()
.WithMessage("Creator ID is required");
RuleFor(x => x.Email)
.Must(email => email == null || !string.IsNullOrWhiteSpace(email))
.WithMessage("Email cannot be empty if provided");
}
}
[PublicAPI]
public class ChangeEmailHandler(
ContentDbContext context)
: Endpoint<ChangeEmailRequest>
{
public override void Configure()
{
Post("/api/creators/{CreatorId}/email");
Options(o => o.WithTags("Creators"));
}
public override async Task HandleAsync(
ChangeEmailRequest request,
CancellationToken ct)
{
var creator = await context
.Creators
.Include(c => c.Presentation)
.SingleOrDefaultAsync(
c => c.Id == request.CreatorId,
cancellationToken: ct);
if (creator is null)
{
await SendNotFoundAsync(ct);
return;
}
// Check if the current user is the creator
if (creator.CreatedBy != User.GetUserId())
{
await SendUnauthorizedAsync(ct);
return;
}
creator.Presentation.Email = request.Email?.Trim();
await context.SaveChangesAsync(ct);
await SendOkAsync(ct);
}
}

View File

@@ -1,74 +0,0 @@
using Hutopy.Web.Common.BlobStorage;
using Hutopy.Web.Features.Contents.Data;
namespace Hutopy.Web.Features.Contents.Handlers;
[PublicAPI]
public record ChangeLogoRequest(
Guid CreatorId,
IFormFile File);
[PublicAPI]
public record ChangeLogoResponse(
string BlobUrl);
[PublicAPI]
public sealed class ChangeLogoRequestValidator : Validator<ChangeLogoRequest>
{
public ChangeLogoRequestValidator()
{
RuleFor(x => x.CreatorId)
.NotNull()
.NotEmpty();
RuleFor(x => x.File)
.NotNull()
.NotEmpty();
}
}
[PublicAPI]
public class ChangeLogoHandler(
ContentDbContext context,
AzureBlobStorage blobStorage)
: Endpoint<ChangeLogoRequest>
{
public override void Configure()
{
Post("/api/creators/{CreatorId}/logo");
Options(o => o.WithTags("Creators"));
AllowFileUploads();
}
public override async Task HandleAsync(
ChangeLogoRequest request,
CancellationToken ct)
{
var creator = await context
.Creators
.SingleOrDefaultAsync(
c => c.Id == request.CreatorId,
cancellationToken: ct);
if (creator is null)
{
await SendNotFoundAsync(ct);
return;
}
var blobUrl = await blobStorage.UploadFileAsync(
ContainerNames.Creators,
$"{request.CreatorId}/{SubDirectoryNames.Profile}/{CommonFileNames.ProfilePicture}",
request.File.OpenReadStream(),
request.File.ContentType,
ct);
creator.PortraitUrl = $"{blobUrl}?t={DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()}";
await context.SaveChangesAsync(ct);
await SendOkAsync(
new ChangeLogoResponse(blobUrl),
ct);
}
}

View File

@@ -1,49 +0,0 @@
using Hutopy.Web.Features.Contents.Data;
namespace Hutopy.Web.Features.Contents.Handlers;
[PublicAPI]
public record ChangeNameRequest(
Guid CreatorId,
string Name);
[PublicAPI]
internal sealed class ChangeNameRequestValidator
: Validator<ChangeNameRequest>
{
public ChangeNameRequestValidator()
{
RuleFor(r => r.Name)
.NotNull().WithMessage("You should specify the Name")
.NotEmpty().WithMessage("You should specify a valid/not empty Name");
}
}
[PublicAPI]
public class ChangeNameHandler(
ContentDbContext context)
: Endpoint<ChangeNameRequest>
{
public override void Configure()
{
Post("/api/creators/{CreatorId}/name");
Options(o => o.WithTags("Creators"));
}
public override async Task HandleAsync(
ChangeNameRequest request,
CancellationToken ct)
{
var creator = await context
.Creators
.SingleAsync(
c => c.Id == request.CreatorId,
cancellationToken: ct);
creator.Name = request.Name;
await context.SaveChangesAsync(ct);
await SendOkAsync(ct);
}
}

View File

@@ -1,70 +0,0 @@
using FluentValidation;
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 ChangePhoneNumberRequest(
Guid CreatorId,
string? PhoneNumber);
[PublicAPI]
public sealed class ChangePhoneNumberRequestValidator : Validator<ChangePhoneNumberRequest>
{
public ChangePhoneNumberRequestValidator()
{
RuleFor(x => x.CreatorId)
.NotEmpty()
.WithMessage("Creator ID is required");
RuleFor(x => x.PhoneNumber)
.Must(phone => phone == null || !string.IsNullOrWhiteSpace(phone))
.WithMessage("Phone number cannot be empty if provided");
}
}
[PublicAPI]
public class ChangePhoneNumberHandler(
ContentDbContext context)
: Endpoint<ChangePhoneNumberRequest>
{
public override void Configure()
{
Post("/api/creators/{CreatorId}/phone");
Options(o => o.WithTags("Creators"));
}
public override async Task HandleAsync(
ChangePhoneNumberRequest request,
CancellationToken ct)
{
var creator = await context
.Creators
.Include(c => c.Presentation)
.SingleOrDefaultAsync(
c => c.Id == request.CreatorId,
cancellationToken: ct);
if (creator is null)
{
await SendNotFoundAsync(ct);
return;
}
// Check if the current user is the creator
if (creator.CreatedBy != User.GetUserId())
{
await SendUnauthorizedAsync(ct);
return;
}
creator.Presentation.PhoneNumber = request.PhoneNumber?.Trim();
await context.SaveChangesAsync(ct);
await SendOkAsync(ct);
}
}

View File

@@ -1,71 +0,0 @@
using Hutopy.Web.Common.YouTube;
using Hutopy.Web.Features.Contents.Data;
namespace Hutopy.Web.Features.Contents.Handlers;
[PublicAPI]
public record ChangePresentationInfosRequest(
Guid CreatorId,
string Description,
string? VideoUrl);
[PublicAPI]
public sealed class ChangePresentationInfosRequestValidator : Validator<ChangePresentationInfosRequest>
{
public ChangePresentationInfosRequestValidator()
{
RuleFor(x => x.CreatorId)
.NotEmpty()
.WithMessage("Creator ID is required");
RuleFor(x => x.Description)
.NotEmpty()
.WithMessage("Description is required")
.MaximumLength(2000)
.WithMessage("Description cannot exceed 2000 characters");
RuleFor(x => x.VideoUrl)
.Must(url => url == null || YouTubeUrlHelper.IsValidYouTubeUrlOrId(url))
.WithMessage("Invalid YouTube URL or video ID format");
}
}
[PublicAPI]
public class ChangePresentationInfosHandler(
ContentDbContext context)
: Endpoint<ChangePresentationInfosRequest>
{
public override void Configure()
{
Post("/api/creators/{CreatorId}/presentation-infos");
Options(o => o.WithTags("Creators"));
}
public override async Task HandleAsync(
ChangePresentationInfosRequest request,
CancellationToken ct)
{
var creator = await context
.Creators
.Include(c => c.Presentation)
.SingleOrDefaultAsync(
c => c.Id == request.CreatorId,
cancellationToken: ct);
if (creator is null)
{
await SendNotFoundAsync(ct);
return;
}
// Update the presentation info with the new values
creator.Presentation.Description = request.Description.Trim();
creator.Presentation.VideoUrl = request.VideoUrl != null
? YouTubeUrlHelper.ExtractVideoId(request.VideoUrl.Trim())
: null;
await context.SaveChangesAsync(ct);
await SendOkAsync(ct);
}
}

View File

@@ -1,97 +0,0 @@
using Hutopy.Web.Common.Security;
using Hutopy.Web.Features.Contents.Data;
namespace Hutopy.Web.Features.Contents.Handlers;
[PublicAPI]
public record ChangeSlugRequest(
Guid CreatorId,
Guid SlugReservationId);
[PublicAPI]
internal sealed class ChangeSlugRequestValidator
: Validator<ChangeSlugRequest>
{
public ChangeSlugRequestValidator()
{
RuleFor(r => r.CreatorId)
.NotNull().WithMessage("You should specify the CreatorId")
.NotEmpty().WithMessage("You should specify a valid/not empty CreatorId");
RuleFor(r => r.SlugReservationId)
.NotNull().WithMessage("You should specify the SlugReservationId")
.NotEmpty().WithMessage("You should specify a valid/not empty SlugReservationId");
}
}
[PublicAPI]
public class ChangeSlugHandler(
ContentDbContext context)
: Endpoint<ChangeSlugRequest>
{
public override void Configure()
{
Put("/api/creators/{CreatorId}/slug");
Options(o => o.WithTags("Creators"));
}
public override async Task HandleAsync(
ChangeSlugRequest request,
CancellationToken ct)
{
await using var transaction = await context.Database.BeginTransactionAsync(ct);
try
{
var creator = await context
.Creators
.SingleAsync(
c => c.Id == request.CreatorId,
cancellationToken: ct);
if (creator.CreatedBy != User.GetUserId())
{
await SendUnauthorizedAsync(ct);
return;
}
var reservation = await context
.Slugs
.FirstOrDefaultAsync(
s => s.Id == request.SlugReservationId,
ct);
if (reservation is null)
{
await SendNotFoundAsync(ct);
return;
}
var previousReservation = await context
.Slugs
.FirstOrDefaultAsync(
s => s.UsedBy == request.CreatorId,
ct);
if (previousReservation is null)
{
await SendErrorsAsync(cancellation: ct);
return;
}
context.Remove(previousReservation);
reservation.UsedBy = creator.Id;
creator.Slug = reservation.NormalizedName;
await context.SaveChangesAsync(ct);
await transaction.CommitAsync(ct);
await SendOkAsync(ct);
}
catch
{
await transaction.RollbackAsync(ct);
}
}
}

View File

@@ -1,50 +0,0 @@
using Hutopy.Web.Features.Contents.Data;
namespace Hutopy.Web.Features.Contents.Handlers;
[PublicAPI]
public record ChangeSocialsRequest(
Guid CreatorId,
string? FacebookUrl,
string? InstagramUrl,
string? XUrl,
string? LinkedInUrl,
string? TikTokUrl,
string? YoutubeUrl,
string? RedditUrl,
string? WebsiteUrl);
[PublicAPI]
public class ChangeSocialsHandler(
ContentDbContext context)
: Endpoint<ChangeSocialsRequest>
{
public override void Configure()
{
Post("/api/creators/{CreatorId}/socials");
Options(o => o.WithTags("Creators"));
}
public override async Task HandleAsync(ChangeSocialsRequest request, CancellationToken ct)
{
var creator = await context
.Creators
.Include(c => c.Socials)
.SingleAsync(
c => c.Id == request.CreatorId,
cancellationToken: ct);
creator.Socials.FacebookUrl = request.FacebookUrl;
creator.Socials.InstagramUrl = request.InstagramUrl;
creator.Socials.XUrl = request.XUrl;
creator.Socials.LinkedInUrl = request.LinkedInUrl;
creator.Socials.TikTokUrl = request.TikTokUrl;
creator.Socials.YoutubeUrl = request.YoutubeUrl;
creator.Socials.RedditUrl = request.RedditUrl;
creator.Socials.WebsiteUrl = request.WebsiteUrl;
await context.SaveChangesAsync(ct);
await SendOkAsync(ct);
}
}

View File

@@ -1,37 +0,0 @@
using Hutopy.Web.Features.Contents.Data;
namespace Hutopy.Web.Features.Contents.Handlers;
[PublicAPI]
public record ChangeTitleRequest(
Guid CreatorId,
string? Title);
[PublicAPI]
public class ChangeTitleHandler(
ContentDbContext context)
: Endpoint<ChangeTitleRequest>
{
public override void Configure()
{
Post("/api/creators/{CreatorId}/title");
Options(o => o.WithTags("Creators"));
}
public override async Task HandleAsync(
ChangeTitleRequest request,
CancellationToken ct)
{
var creator = await context
.Creators
.SingleAsync(
c => c.Id == request.CreatorId,
cancellationToken: ct);
creator.Title = request.Title;
await context.SaveChangesAsync(ct);
await SendOkAsync(ct);
}
}

View File

@@ -1,8 +0,0 @@
namespace Hutopy.Web.Features.Contents.Handlers;
public class ContentOptions
{
public const string ConfigurationSection = "Contents";
public TimeSpan SlugReservationDuration { get; set; }
}

View File

@@ -1,75 +0,0 @@
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);
}
}

View File

@@ -1,156 +0,0 @@
using System.Collections.Concurrent;
using Hutopy.Web.Common.BlobStorage;
using Hutopy.Web.Common.Security;
using Hutopy.Web.Features.Contents.Data;
namespace Hutopy.Web.Features.Contents.Handlers;
[PublicAPI]
public record PostContentRequest(
Guid Id,
Guid CreatorId,
string Title,
string Description,
IFormFileCollection? Files,
IFormFile? Thumbnail,
string[]? ExternalUrls);
[PublicAPI]
public sealed class PostContentRequestValidator : Validator<PostContentRequest>
{
public PostContentRequestValidator()
{
RuleFor(r => r.Id)
.NotNull().WithMessage("You should specify the Id")
.NotEmpty().WithMessage("You should specify a valid/not empty Id");
RuleFor(r => r.CreatorId)
.NotNull().WithMessage("You should specify the CreatorId")
.NotEmpty().WithMessage("You should specify a valid/not empty CreatorId");
RuleFor(r => r.Title)
.NotNull().WithMessage("You should specify the Title")
.NotEmpty().WithMessage("You should specify a valid/not empty Title");
RuleFor(r => r.Description)
.NotNull().WithMessage("You should specify the Description")
.NotEmpty().WithMessage("You should specify a valid/not empty Description");
RuleForEach(r => r.ExternalUrls)
.Must(url => Uri.IsWellFormedUriString(url, UriKind.Absolute) &&
(url.StartsWith("http://") || url.StartsWith("https://")))
.WithMessage("External URL must be a valid HTTP/HTTPS URL");
RuleFor(r => r.Thumbnail)
.Must(file => file == null || file.ContentType.StartsWith("image/"))
.WithMessage("Thumbnail must be an image");
}
}
public sealed class PostContent(
AzureBlobStorage blobStorage,
ContentDbContext context)
: Endpoint<PostContentRequest>
{
public override void Configure()
{
Post("/api/contents");
Options(o => o.WithTags("Contents"));
AllowFileUploads();
}
public override async Task HandleAsync(PostContentRequest req, CancellationToken ct)
{
var urls = new ConcurrentBag<string>();
string? thumbnailUrl = null;
await using var transaction = await context.Database.BeginTransactionAsync(ct);
try
{
if (req.Files is not null)
{
await Parallel.ForEachAsync(req.Files, ct, async (file, ict) =>
{
try
{
var contentUrl = await SaveFileAsync(req.CreatorId, req.Id, file, ict);
urls.Add(contentUrl);
}
catch (Exception ex)
{
Logger.LogError("Failed to upload file {FileName}: {Message}", file.FileName, ex.Message);
}
});
}
if (req.ExternalUrls is not null)
{
foreach (var externalUrl in req.ExternalUrls.Where(url => !string.IsNullOrWhiteSpace(url)))
{
urls.Add(externalUrl);
}
}
if (req.Thumbnail is not null)
{
try
{
thumbnailUrl = await SaveFileAsync(req.CreatorId, req.Id, req.Thumbnail, ct, isThumbnail: true);
}
catch (Exception ex)
{
Logger.LogError("Error uploading thumbnail: {Message}", ex.Message);
}
}
await context.Contents.AddAsync(new Content
{
Id = req.Id,
CreatedBy = User.GetUserId(),
Title = req.Title,
Description = req.Description,
Urls = urls.IsEmpty ? null : urls.ToArray(),
ThumbnailUrl = thumbnailUrl,
}, ct);
await context.SaveChangesAsync(ct);
await transaction.CommitAsync(ct);
await SendOkAsync(new { Message = "Content published successfully!" }, ct);
}
catch (Exception ex)
{
await transaction.RollbackAsync(ct);
Logger.LogError("Transaction failed: {Message}", ex.Message);
throw;
}
}
private async Task<string> SaveFileAsync(
Guid creatorId,
Guid contentId,
IFormFile file,
CancellationToken ct = default,
bool isThumbnail = false)
{
var blobName = isThumbnail
? $"{creatorId}/{SubDirectoryNames.Contents}/{contentId}/thumbnail-{file.FileName}"
: $"{creatorId}/{SubDirectoryNames.Contents}/{contentId}/{file.FileName}";
return await blobStorage.UploadFileAsync(
ContainerNames.Creators,
blobName,
file.OpenReadStream(),
file.ContentType,
ct: ct);
}
}

View File

@@ -1,110 +0,0 @@
using System.Text;
using Hutopy.Web.Common.BlobStorage;
using Hutopy.Web.Common.Security;
using Hutopy.Web.Features.Contents.Data;
using Hutopy.Web.Features.Contents.Handlers.Models;
namespace Hutopy.Web.Features.Contents.Handlers;
[PublicAPI]
public record PostContentFromHtmlRequest(
Guid Id,
Guid CreatorId,
string Title,
string HtmlContent
);
[PublicAPI]
public sealed class PostContentFromHtmlRequestValidator : Validator<PostContentFromHtmlRequest>
{
public PostContentFromHtmlRequestValidator()
{
RuleFor(r => r.Id)
.NotNull().WithMessage("You should specify the Id")
.NotEmpty().WithMessage("You should specify a valid/not empty Id");
RuleFor(r => r.CreatorId)
.NotNull().WithMessage("You should specify the CreatorId")
.NotEmpty().WithMessage("You should specify a valid/not empty CreatorId");
RuleFor(r => r.Title)
.NotNull().WithMessage("You should specify the Title")
.NotEmpty().WithMessage("You should specify a valid/not empty Title");
}
}
public sealed class PostContentHtml(
AzureBlobStorage blobStorage,
ContentDbContext context)
: Endpoint<PostContentFromHtmlRequest>
{
public override void Configure()
{
Post("/api/contents/html");
Options(o => o.WithTags("Contents"));
AllowFileUploads();
}
public override async Task HandleAsync(
PostContentFromHtmlRequest req,
CancellationToken ct)
{
var htmlFileUrl = await SaveHtmlContentAsHtmlFileAsync(
req.CreatorId,
req.Id,
req.HtmlContent,
ct);
await context.Contents.AddAsync(
new Content { Id = req.Id, CreatedBy = User.GetUserId(), Title = req.Title, HtmlFileUrl = htmlFileUrl },
ct);
await context.SaveChangesAsync(ct);
var content = await context
.Contents
.Select(c => new ContentModel
{
Id = c.Id,
CreatedBy = c.CreatedBy,
CreatedByName = c.Creator.Name,
CreatedByPortraitUrl = c.Creator.PortraitUrl,
CreatedAt = c.CreatedAt,
DeletedBy = c.DeletedBy,
DeletedAt = c.DeletedAt,
Title = c.Title,
Description = c.Description,
Urls = c.Urls,
ThumbnailUrl = c.ThumbnailUrl,
HtmlFileUrl = htmlFileUrl
})
.SingleOrDefaultAsync(
c => c.Id == req.Id,
cancellationToken: ct);
await SendOkAsync(content, ct);
}
private async Task<string> SaveHtmlContentAsHtmlFileAsync(
Guid creatorId,
Guid contentId,
string htmlContent,
CancellationToken ct = default)
{
var fileName = $"{contentId}.html";
var filePath = $"{creatorId}/{SubDirectoryNames.Contents}/{fileName}";
// Convert the HTML string into a stream
using var stream = new MemoryStream(Encoding.UTF8.GetBytes(htmlContent));
// Upload the stream as an HTML file
var url = await blobStorage.UploadFileAsync(
ContainerNames.Creators,
filePath,
stream,
"text/html",
ct: ct);
return url;
}
}

View File

@@ -1,82 +0,0 @@
using Hutopy.Web.Common.Security;
using Hutopy.Web.Features.Contents.Data;
namespace Hutopy.Web.Features.Contents.Handlers;
[PublicAPI]
public record CreateCreatorRequest(
Guid SlugReservationId,
Guid CreatorId);
[PublicAPI]
public sealed class CreateCreatorRequestValidator : Validator<CreateCreatorRequest>
{
public CreateCreatorRequestValidator()
{
RuleFor(r => r.SlugReservationId)
.NotNull()
.NotEmpty()
.WithMessage("You should specify a valid SlugReservationId");
RuleFor(r => r.CreatorId)
.NotNull()
.NotEmpty()
.WithMessage("You should specify a valid CreatorId");
}
}
[PublicAPI]
public sealed class CreateCreatorHandler(
ContentDbContext context)
: Endpoint<CreateCreatorRequest>
{
public override void Configure()
{
Post("/api/creators");
Options(o => o.WithTags("Creators"));
}
public override async Task HandleAsync(
CreateCreatorRequest req,
CancellationToken ct)
{
await using var transaction = await context.Database.BeginTransactionAsync(ct);
try
{
var slug = await context
.Slugs
.SingleAsync(s => s.Id == req.SlugReservationId, ct);
if (slug.UsedBy is not null
|| slug.ReservedUntil < DateTimeOffset.UtcNow
|| slug.CreatedBy != User.GetUserId())
{
await SendErrorsAsync(500, ct);
return;
}
slug.UsedBy = req.CreatorId;
await context.Creators.AddAsync(
new Creator
{
Id = req.CreatorId,
CreatedBy = User.GetUserId(),
Name = slug.Name,
Slug = slug.NormalizedName
},
ct);
await context.SaveChangesAsync(ct);
await transaction.CommitAsync(ct);
await SendOkAsync(ct);
}
catch (Exception e)
{
await transaction.RollbackAsync(ct);
}
}
}

View File

@@ -1,60 +0,0 @@
using Hutopy.Web.Common;
using Hutopy.Web.Common.Security;
using Hutopy.Web.Features.Contents.Data;
namespace Hutopy.Web.Features.Contents.Handlers;
[PublicAPI]
public record DeleteContentRequest(
Guid ContentId);
[PublicAPI]
public sealed class DeleteContentRequestValidator : Validator<DeleteContentRequest>
{
public DeleteContentRequestValidator()
{
RuleFor(r => r.ContentId)
.NotNull().WithMessage("You should specify the ContentId")
.NotEmpty().WithMessage("You should specify a valid/not empty ContentId");
}
}
public sealed class DeleteContent(
ContentDbContext context)
: Endpoint<DeleteContentRequest>
{
public override void Configure()
{
Delete("/api/contents/{ContentId}");
Options(o => o.WithTags("Contents"));
}
public override async Task HandleAsync(
DeleteContentRequest req,
CancellationToken ct)
{
var content = await context.Contents.FindAsync(
[req.ContentId],
ct);
if (content is null)
{
await SendNotFoundAsync(ct);
return;
}
var userId = HttpContext.User.GetUserId();
if (content.CreatedBy != userId)
{
await SendForbiddenAsync(ct);
return;
}
content.DeletedAt = DateTimeOffset.UtcNow;
content.DeletedBy = userId;
await context.SaveChangesAsync(ct);
await SendOkAsync(ct);
}
}

View File

@@ -1,87 +0,0 @@
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 OriginalUrl,
string ThumbnailUrl,
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()
{
AllowAnonymous();
Get("/api/albums/{AlbumId}");
Options(o => o.WithTags("Albums"));
}
public override async Task HandleAsync(
GetAlbumRequest request,
CancellationToken ct)
{
var album = await context
.Albums
.Include(a => a.Photos.OrderBy(p => p.Order))
.SingleOrDefaultAsync(
a => a.Id == request.AlbumId,
cancellationToken: ct);
if (album is null)
{
await SendNotFoundAsync(ct);
return;
}
var photos = album.Photos
.Select(p => new AlbumPhotoDto(
p.Id,
p.OriginalUrl,
p.ThumbnailUrl,
p.Caption,
p.Order,
p.CreatedAt))
.ToList();
await SendOkAsync(
new GetAlbumResponse(
album.Id,
album.Title,
photos,
album.CreatedAt),
ct);
}
}

View File

@@ -1,58 +0,0 @@
using Hutopy.Web.Features.Contents.Data;
using Hutopy.Web.Features.Contents.Handlers.Models;
namespace Hutopy.Web.Features.Contents.Handlers;
[PublicAPI]
public sealed class GetContentRequest
{
public Guid ContentId { get; set; }
}
[PublicAPI]
public class GetContent(
ContentDbContext context)
: Endpoint<GetContentRequest, ContentModel>
{
public override void Configure()
{
Get("/api/contents/{ContentId:guid}");
Options(o => o.WithTags("Contents"));
AllowAnonymous();
}
public override async Task HandleAsync(
GetContentRequest req,
CancellationToken ct)
{
var content = await context
.Contents
.Select(c => new ContentModel
{
Id = c.Id,
CreatedBy = c.CreatedBy,
CreatedByName = c.Creator.Name,
CreatedByPortraitUrl = c.Creator.PortraitUrl,
CreatedAt = c.CreatedAt,
DeletedBy = c.DeletedBy,
DeletedAt = c.DeletedAt,
Title = c.Title,
Description = c.Description,
Urls = c.Urls,
ThumbnailUrl = c.ThumbnailUrl,
HtmlFileUrl = c.HtmlFileUrl ?? "",
Reactions = c.Reactions.Select(x => new ReactionModel
{
Reaction = x.Reaction.ToString(), UserId = x.UserId, UserName = x.UserName
}).ToList()
})
.SingleOrDefaultAsync(
c => c.Id == req.ContentId,
cancellationToken: ct);
if (content is null)
await SendNotFoundAsync(cancellation: ct);
else
await SendAsync(content, cancellation: ct);
}
}

View File

@@ -1,67 +0,0 @@
using Hutopy.Web.Features.Contents.Data;
using Hutopy.Web.Features.Contents.Handlers.Models;
namespace Hutopy.Web.Features.Contents.Handlers;
[PublicAPI]
public sealed class GetContentsByCreatorRequest
{
public Guid CreatorId { get; set; }
[BindFrom("page_size")] public int PageSize { get; set; } = 10;
[BindFrom("last_id")] public Guid? LastId { get; set; }
}
[PublicAPI]
public class GetContentsByCreatorHandler(
ContentDbContext context)
: Endpoint<GetContentsByCreatorRequest, List<ContentModel>>
{
public override void Configure()
{
Get("/api/contents/creator/{CreatorId:guid}");
Options(o => o.WithTags("Contents"));
AllowAnonymous();
}
public override async Task HandleAsync(
GetContentsByCreatorRequest req,
CancellationToken ct)
{
var query = context.Contents
.Where(c => c.CreatedBy == req.CreatorId && c.DeletedAt == null)
.OrderByDescending(c => c.CreatedAt);
if (req.LastId.HasValue)
{
query = query.Where(c => c.Id > req.LastId.Value)
.OrderByDescending(c => c.CreatedAt);
}
var content = await query
.Select(c => new ContentModel
{
Id = c.Id,
CreatedBy = c.CreatedBy,
CreatedByName = c.Creator.Name,
CreatedByPortraitUrl = c.Creator.PortraitUrl,
CreatedAt = c.CreatedAt,
DeletedBy = c.DeletedBy,
DeletedAt = c.DeletedAt,
Title = c.Title,
Description = c.Description,
Urls = c.Urls,
ThumbnailUrl = c.ThumbnailUrl,
HtmlFileUrl = c.HtmlFileUrl ?? "",
Reactions = c.Reactions.Select(x => new ReactionModel
{
Reaction = x.Reaction.ToString(),
UserId = x.UserId,
UserName = x.UserName
}).ToList()
})
.Take(req.PageSize)
.ToListAsync(ct);
await SendAsync(content, cancellation: ct);
}
}

View File

@@ -1,48 +0,0 @@
using Hutopy.Web.Features.Contents.Data;
namespace Hutopy.Web.Features.Contents.Handlers;
[PublicAPI]
public sealed class GetCreatorByIdRequest
{
public required Guid CreatorId { get; set; }
}
[UsedImplicitly]
public sealed class GetCreatorByIdRequestValidator
: Validator<GetCreatorByIdRequest>
{
public GetCreatorByIdRequestValidator()
{
RuleFor(r => r.CreatorId)
.NotNull().WithMessage("You should specify the CreatorId")
.NotEmpty().WithMessage("You should specify a valid/not empty CreatorId");
}
}
[PublicAPI]
public class GetCreatorByIdHandler(
ContentDbContext context)
: Endpoint<GetCreatorByIdRequest, Creator>
{
public override void Configure()
{
Get("/api/creators/{CreatorId}");
Options((o => o.WithTags("Creators")));
AllowAnonymous();
}
public override async Task HandleAsync(
GetCreatorByIdRequest req,
CancellationToken ct)
{
var creator = await context
.Creators
.FindAsync(
[req.CreatorId],
cancellationToken: ct);
if (creator is null) await SendNotFoundAsync(ct);
else await SendAsync(creator, cancellation: ct);
}
}

View File

@@ -1,105 +0,0 @@
using Hutopy.Web.Common.Security;
using Hutopy.Web.Features.Contents.Data;
namespace Hutopy.Web.Features.Contents.Handlers;
[PublicAPI]
public sealed class GetCreatorBySlugRequest
{
public required string Name { get; set; }
}
[PublicAPI]
public record GetCreatorBySlugResponse
{
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]
public sealed class GetCreatorBySlugRequestValidator
: Validator<GetCreatorBySlugRequest>
{
public GetCreatorBySlugRequestValidator()
{
RuleFor(r => r.Name)
.NotNull().WithMessage("You should specify the Name")
.NotEmpty().WithMessage("You should specify a valid/not empty Name");
}
}
[PublicAPI]
public class GetCreatorBySlugHandler(
ContentDbContext context)
: Endpoint<GetCreatorBySlugRequest, GetCreatorBySlugResponse>
{
public override void Configure()
{
Get("/api/creators/@{Name}");
Options((o => o.WithTags("Creators")));
AllowAnonymous();
}
public override async Task HandleAsync(
GetCreatorBySlugRequest req,
CancellationToken ct)
{
var creatorName = req.Name.ToLower();
var response = await context
.Creators
.IgnoreQueryFilters()
.Where(c => EF.Functions.ILike(c.Slug, creatorName))
.AsNoTracking()
.Select(c => new GetCreatorBySlugResponse
{
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 (response is null)
{
await SendNotFoundAsync(ct);
return;
}
bool isOwner = User.Identity?.IsAuthenticated == true
&& User.GetUserId() == response.CreatedBy;
if (response.IsDeleted && !isOwner)
{
await SendNotFoundAsync(ct);
}
else
{
await SendAsync(response, cancellation: ct);
}
}
}

View File

@@ -1,64 +0,0 @@
using Hutopy.Web.Common.Security;
using Hutopy.Web.Features.Contents.Data;
namespace Hutopy.Web.Features.Contents.Handlers;
[PublicAPI]
public sealed class GetCreatorProfileResponse
{
public Guid Id { get; set; }
public Guid CreatedBy { get; set; }
public DateTimeOffset CreatedAt { get; set; }
public Guid? DeletedBy { get; set; }
public DateTimeOffset? DeletedAt { get; set; }
public bool IsDeleted { get; set; }
public required string Name { get; set; }
public required string Slug { get; set; }
public string? Title { get; set; }
public bool Verified { get; set; }
public bool AcceptDonation { get; set; }
public required Presentation Presentation { get; set; }
public required Socials Socials { get; set; }
}
[PublicAPI]
public class GetCreatorProfileHandler(
ContentDbContext context)
: EndpointWithoutRequest<GetCreatorProfileResponse>
{
public override void Configure()
{
Get("/api/creators/profile");
Options((o => o.WithTags("Creators")));
}
public override async Task HandleAsync(
CancellationToken ct)
{
var creator = await context
.Creators
.IgnoreQueryFilters()
.Where(c => c.Id == HttpContext.User.GetUserId())
.AsNoTracking()
.Select(c => new GetCreatorProfileResponse
{
Id = c.Id,
CreatedBy = c.CreatedBy,
CreatedAt = c.CreatedAt,
DeletedBy = c.DeletedBy,
DeletedAt = c.DeletedAt,
IsDeleted = c.IsDeleted,
Name = c.Name,
Slug = c.Slug,
Title = c.Title,
Verified = c.Verified,
AcceptDonation = c.AcceptDonation,
Presentation = c.Presentation,
Socials = c.Socials,
})
.SingleOrDefaultAsync(ct);
if (creator is null) await SendNotFoundAsync(ct);
else await SendAsync(creator, cancellation: ct);
}
}

View File

@@ -1,65 +0,0 @@
using Hutopy.Web.Features.Contents.Data;
using Hutopy.Web.Features.Contents.Handlers.Models;
namespace Hutopy.Web.Features.Contents.Handlers;
[PublicAPI]
public sealed class GetFeaturedContentsRequest
{
[BindFrom("page_size")] public int PageSize { get; set; } = 10;
[BindFrom("last_id")] public Guid? LastId { get; set; }
}
[PublicAPI]
public class GetFeaturedContentsHandler(
ContentDbContext context)
: Endpoint<GetFeaturedContentsRequest, List<ContentModel>>
{
public override void Configure()
{
Get("/api/contents/featured");
Options(o => o.WithTags("Contents"));
AllowAnonymous();
}
public override async Task HandleAsync(
GetFeaturedContentsRequest req,
CancellationToken ct)
{
var query = context.Contents
.Where(c => c.DeletedAt == null);
if (req.LastId.HasValue)
{
query = query.Where(c => c.Id > req.LastId.Value);
}
query = query.OrderByDescending(x => x.Reactions.Count);
var content = await query
.Select(c => new ContentModel
{
Id = c.Id,
CreatedBy = c.CreatedBy,
CreatedByName = c.Creator.Name,
CreatedByPortraitUrl = c.Creator.PortraitUrl,
CreatedAt = c.CreatedAt,
DeletedBy = c.DeletedBy,
DeletedAt = c.DeletedAt,
Title = c.Title,
Description = c.Description,
Urls = c.Urls,
ThumbnailUrl = c.ThumbnailUrl,
Reactions = c.Reactions.Select(x => new ReactionModel
{
Reaction = x.Reaction.ToString(),
UserId = x.UserId,
UserName = x.UserName
}).ToList()
})
.Take(req.PageSize)
.ToListAsync(ct);
await SendAsync(content, cancellation: ct);
}
}

View File

@@ -1,86 +0,0 @@
using Hutopy.Web.Common.BlobStorage;
namespace Hutopy.Web.Features.Contents.Handlers;
[PublicAPI]
public record InsertImagesRequest(
Guid Id,
Guid CreatorId,
IFormFileCollection? Files
);
[PublicAPI]
public sealed class InsertImagesRequestValidator : Validator<InsertImagesRequest>
{
public InsertImagesRequestValidator()
{
RuleFor(r => r.Id)
.NotNull().WithMessage("You should specify the Id")
.NotEmpty().WithMessage("You should specify a valid/not empty Id");
RuleFor(r => r.CreatorId)
.NotNull().WithMessage("You should specify the CreatorId")
.NotEmpty().WithMessage("You should specify a valid/not empty CreatorId");
}
}
public sealed class InsertImages(
AzureBlobStorage blobStorage)
: Endpoint<InsertImagesRequest>
{
public override void Configure()
{
Post("/api/content/insert-image/");
Options(o => o.WithTags("Contents"));
AllowFileUploads();
}
public override async Task HandleAsync(
InsertImagesRequest req,
CancellationToken ct)
{
var urls = new List<string>();
if (req.Files is not null)
{
await Parallel.ForEachAsync(
req.Files,
ct,
async (
file,
ict) =>
{
try
{
var contentUrl = await SaveFileAsync(
req.CreatorId,
req.Id,
file,
ict);
urls.Add(contentUrl);
}
catch (Exception ex)
{
Logger.LogError("{ErrorMessage}", ex.Message);
}
});
}
await SendOkAsync(urls, ct);
}
private async Task<string> SaveFileAsync(
Guid creatorId,
Guid contentId,
IFormFile file,
CancellationToken ct = default)
{
var url = await blobStorage.UploadFileAsync(
ContainerNames.Creators,
$"{creatorId}/{SubDirectoryNames.Contents}/{contentId}/{file.FileName}",
file.OpenReadStream(),
file.ContentType,
ct: ct);
return url;
}
}

View File

@@ -1,19 +0,0 @@
namespace Hutopy.Web.Features.Contents.Handlers.Models;
[PublicAPI]
public class ContentModel
{
public required Guid Id { get; init; }
public required Guid CreatedBy { get; init; }
public required string CreatedByName { get; init; }
public required string? CreatedByPortraitUrl { get; init; }
public required DateTimeOffset CreatedAt { get; init; }
public Guid? DeletedBy { get; init; }
public DateTimeOffset? DeletedAt { get; init; }
public required string Title { get; init; }
public required string Description { get; init; }
public string HtmlFileUrl { get; init; } = "";
public required string[]? Urls { get; init; }
public string? ThumbnailUrl { get; init; }
public IList<ReactionModel>? Reactions { get; set; } = new List<ReactionModel>();
}

View File

@@ -1,7 +0,0 @@
namespace Hutopy.Web.Features.Contents.Handlers.Models;
[PublicAPI]
public record FollowModel(
Guid CreatorId,
string CreatorName,
string? CreatorPortraitUrl);

View File

@@ -1,8 +0,0 @@
namespace Hutopy.Web.Features.Contents.Handlers.Models;
public class ReactionModel
{
public required string Reaction { get; set; }
public required Guid UserId { get; set; }
public required string UserName { get; set; }
}

View File

@@ -1,69 +0,0 @@
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);
}
}

View File

@@ -1,63 +0,0 @@
using Hutopy.Web.Common.Security;
using Hutopy.Web.Features.Contents.Data;
namespace Hutopy.Web.Features.Contents.Handlers;
[PublicAPI]
public record RemoveCreatorRequest(
string CreatorSlug);
[UsedImplicitly]
public sealed class RemoveCreatorRequestValidator : Validator<RemoveCreatorRequest>
{
public RemoveCreatorRequestValidator()
{
RuleFor(r => r.CreatorSlug)
.NotNull()
.NotEmpty()
.WithMessage("You should specify a valid CreatorSlug");
}
}
[PublicAPI]
public sealed class RemoveCreatorHandler(
ContentDbContext context)
: Endpoint<RemoveCreatorRequest>
{
public override void Configure()
{
Delete("/api/creators/@{CreatorSlug}");
Options(o => o.WithTags("Creators"));
}
public override async Task HandleAsync(
RemoveCreatorRequest req,
CancellationToken ct)
{
var creatorSlug = req.CreatorSlug.ToLower();
var creator = await context
.Creators
.Where(c => EF.Functions.ILike(c.Slug, creatorSlug))
.SingleOrDefaultAsync(cancellationToken: ct);
if (creator is null)
{
await SendNotFoundAsync(ct);
return;
}
if (creator.CreatedBy != User.GetUserId())
{
await SendUnauthorizedAsync(ct);
return;
}
creator.DeletedAt = DateTimeOffset.UtcNow;
creator.DeletedBy = User.GetUserId();
await context.SaveChangesAsync(ct);
await SendOkAsync(ct);
}
}

View File

@@ -1,76 +0,0 @@
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);
}
}

View File

@@ -1,36 +0,0 @@
using Hutopy.Web.Features.Contents.Data;
namespace Hutopy.Web.Features.Contents.Handlers;
[PublicAPI]
public sealed class RemoveReactionRequest
{
public required Guid ContentId { get; set; }
public required Guid UserId { get; set; }
}
[PublicAPI]
public class RemoveReaction(
ContentDbContext context)
: Endpoint<RemoveReactionRequest>
{
public override void Configure()
{
Post("/api/content/reaction/remove");
Options(o => o.WithTags("Contents"));
}
public override async Task HandleAsync(
RemoveReactionRequest req,
CancellationToken ct)
{
var content = await context.Contents
.SingleAsync(x => x.Id == req.ContentId, ct);
var reaction = content.Reactions.Single(x => x.UserId == req.UserId);
content.Reactions.Remove(reaction);
await context.SaveChangesAsync(ct);
}
}

Some files were not shown because too many files have changed in this diff Show More