Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 466458e230 | |||
| 60fcc70e98 | |||
| 141d32f591 | |||
| 38e765203d |
@@ -0,0 +1,8 @@
|
|||||||
|
namespace LiteCharms.Features.MidrandBooks.Seed.Configuration;
|
||||||
|
|
||||||
|
public class CdnSettings
|
||||||
|
{
|
||||||
|
public string? BaseCdn { get; set; }
|
||||||
|
|
||||||
|
public string[]? BookCovers { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,158 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>net10.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<UserSecretsId>5c3bc894-8654-4691-99e8-f90d3414843f</UserSecretsId>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<!-- Quartz Scheduler-->
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Bogus" Version="35.6.5" />
|
||||||
|
<PackageReference Include="Meziantou.Analyzer" Version="3.0.96">
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
</PackageReference>
|
||||||
|
<PackageReference Include="OpenTelemetry" Version="1.15.3" />
|
||||||
|
<PackageReference Include="Quartz" Version="3.18.1" />
|
||||||
|
<PackageReference Include="Quartz.Plugins" Version="3.18.1" />
|
||||||
|
<PackageReference Include="Quartz.Plugins.TimeZoneConverter" Version="3.18.1" />
|
||||||
|
<PackageReference Include="Quartz.Serialization.SystemTextJson" Version="3.18.1" />
|
||||||
|
<PackageReference Include="Quartz.AspNetCore" Version="3.18.1" />
|
||||||
|
<PackageReference Include="Quartz.Extensions.DependencyInjection" Version="3.18.1" />
|
||||||
|
|
||||||
|
<!-- Global Usings -->
|
||||||
|
<Using Include="Quartz" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<!-- Configuration -->
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Configuration" Version="10.0.8" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="10.0.8" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="10.0.8" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="10.0.8" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="10.0.8" />
|
||||||
|
|
||||||
|
<!-- Global Usings -->
|
||||||
|
<Using Include="Microsoft.Extensions.Configuration" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<!-- Health Checks -->
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="AspNetCore.HealthChecks.UI.Client" Version="9.0.0" />
|
||||||
|
<PackageReference Include="AspNetCore.HealthChecks.UI" Version="9.0.0" />
|
||||||
|
<PackageReference Include="AspNetCore.HealthChecks.UI.Core" Version="9.0.0" />
|
||||||
|
<PackageReference Include="AspNetCore.HealthChecks.UI.Data" Version="9.0.0" />
|
||||||
|
<PackageReference Include="AspNetCore.HealthChecks.UI.InMemory.Storage" Version="9.0.0" />
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="10.0.8" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="10.0.8" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks" Version="10.0.8" />
|
||||||
|
|
||||||
|
<!-- Global Usings -->
|
||||||
|
<Using Include="Microsoft.Extensions.Diagnostics.HealthChecks" />
|
||||||
|
<Using Include="Microsoft.AspNetCore.Diagnostics.HealthChecks" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<!-- Open Telemetry -->
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.15.3" />
|
||||||
|
<PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.15.3" />
|
||||||
|
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.15.2" />
|
||||||
|
<PackageReference Include="OpenTelemetry.Instrumentation.Http" Version="1.15.1" />
|
||||||
|
<PackageReference Include="OpenTelemetry.Instrumentation.Runtime" Version="1.15.1" />
|
||||||
|
<PackageReference Include="OpenTelemetry.Exporter.Console" Version="1.15.3" />
|
||||||
|
|
||||||
|
<!-- Global Usings -->
|
||||||
|
<Using Include="OpenTelemetry.Resources" />
|
||||||
|
<Using Include="OpenTelemetry.Exporter" />
|
||||||
|
<Using Include="OpenTelemetry.Logs" />
|
||||||
|
<Using Include="OpenTelemetry.Metrics" />
|
||||||
|
<Using Include="OpenTelemetry.Trace" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<!-- Database -->
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="10.0.8" />
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="10.0.8">
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
</PackageReference>
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="10.0.8" />
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="10.0.8">
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
</PackageReference>
|
||||||
|
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="10.0.1" />
|
||||||
|
|
||||||
|
<!-- Global Usings -->
|
||||||
|
<Using Include="Npgsql" />
|
||||||
|
<Using Include="Microsoft.EntityFrameworkCore" />
|
||||||
|
<Using Include="Microsoft.EntityFrameworkCore.Design" />
|
||||||
|
<Using Include="Microsoft.EntityFrameworkCore.Metadata.Builders" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<!-- Email -->
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="MailKit" Version="4.16.0" />
|
||||||
|
<PackageReference Include="MimeKit" Version="4.16.0" />
|
||||||
|
|
||||||
|
<!-- Global Usings-->
|
||||||
|
<Using Include="MimeKit" />
|
||||||
|
<Using Include="MailKit.Net.Smtp" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<!-- CQRS -->
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="FluentResults" Version="4.0.0" />
|
||||||
|
<PackageReference Include="Mediator.Abstractions" Version="3.0.2" />
|
||||||
|
|
||||||
|
<!-- Global Usings -->
|
||||||
|
<Using Include="FluentResults" />
|
||||||
|
<Using Include="Mediator" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<!-- Amazon S3 SDK -->
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="AWSSDK.Extensions.NetCore.Setup" Version="4.0.4.1" />
|
||||||
|
<PackageReference Include="AWSSDK.S3" Version="4.0.23.4" />
|
||||||
|
<ProjectReference Include="..\LiteCharms.Features\LiteCharms.Features.csproj" />
|
||||||
|
|
||||||
|
<!-- global Usings -->
|
||||||
|
<Using Include="Amazon.S3" />
|
||||||
|
<Using Include="Amazon.S3.Model" />
|
||||||
|
<Using Include="Amazon.Runtime" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<!-- Shared Usings -->
|
||||||
|
<ItemGroup>
|
||||||
|
<Using Include="Bogus" />
|
||||||
|
<Using Include="System.Globalization" />
|
||||||
|
<Using Include="System.Reflection" />
|
||||||
|
<Using Include="Microsoft.AspNetCore.Builder" />
|
||||||
|
<Using Include="Microsoft.Extensions.Hosting" />
|
||||||
|
<Using Include="System.Text" />
|
||||||
|
<Using Include="System.Text.Json" />
|
||||||
|
<Using Include="System.Threading.Channels" />
|
||||||
|
<Using Include="System.Collections.ObjectModel" />
|
||||||
|
<Using Include="System.Diagnostics" />
|
||||||
|
<Using Include="System.Diagnostics.Metrics" />
|
||||||
|
<Using Include="Microsoft.Extensions.DependencyInjection" />
|
||||||
|
<Using Include="System.Security.Cryptography" />
|
||||||
|
<Using Include="Microsoft.Extensions.Options" />
|
||||||
|
<Using Include="Microsoft.Extensions.Logging" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\LiteCharms.Features.MidrandBooks\LiteCharms.Features.MidrandBooks.csproj" />
|
||||||
|
<ProjectReference Include="..\LiteCharms.Features\LiteCharms.Features.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<None Update="appsettings.json">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,190 @@
|
|||||||
|
using LiteCharms.Features.MidrandBooks.AuthorBooks;
|
||||||
|
using LiteCharms.Features.MidrandBooks.Authors;
|
||||||
|
using LiteCharms.Features.MidrandBooks.Products;
|
||||||
|
using LiteCharms.Features.MidrandBooks.Seed.Configuration;
|
||||||
|
|
||||||
|
namespace LiteCharms.Features.MidrandBooks.Seed;
|
||||||
|
|
||||||
|
public class ProductsSeederService(ProductService productService, AuthorService authorService, BooksService booksService,
|
||||||
|
IOptions<CdnSettings> options, ILogger<ProductsSeederService> logger) : BackgroundService
|
||||||
|
{
|
||||||
|
private readonly CdnSettings cdnSettings = options.Value;
|
||||||
|
|
||||||
|
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
||||||
|
{
|
||||||
|
logger.LogInformation("Product Seeding started");
|
||||||
|
|
||||||
|
if (cdnSettings.BookCovers is null || cdnSettings.BookCovers.Length == 0)
|
||||||
|
{
|
||||||
|
logger.LogWarning("No book covers found in CDN settings. Seeding aborted.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize Bogus Faker engine
|
||||||
|
var faker = new Faker();
|
||||||
|
var culture = CultureInfo.InvariantCulture;
|
||||||
|
|
||||||
|
// Ensure repeatable data sets if run multiple times by anchoring the seed
|
||||||
|
Randomizer.Seed = new Random(42);
|
||||||
|
|
||||||
|
foreach (var bookCover in cdnSettings.BookCovers)
|
||||||
|
{
|
||||||
|
if (stoppingToken.IsCancellationRequested) break;
|
||||||
|
|
||||||
|
// Generate beautifully mixed eclectic topics on the fly
|
||||||
|
var bookTopic = faker.PickRandom(
|
||||||
|
// --- Tech & IT ---
|
||||||
|
"C# 12 & Modern .NET Architecture",
|
||||||
|
"PostgreSQL Database Optimization",
|
||||||
|
"Docker & Kubernetes in Production",
|
||||||
|
"Domain-Driven Design Paradigms",
|
||||||
|
"Artificial Intelligence with Python",
|
||||||
|
|
||||||
|
// --- Sci-Fi & Fantasy ---
|
||||||
|
"The Chronicles of the Quantum Nebula",
|
||||||
|
"Legends of the Lost Cybernetic Kingdom",
|
||||||
|
"Parallel Dimensions and Rogue Time Streams",
|
||||||
|
"The Last Android in Neo-Johannesburg",
|
||||||
|
|
||||||
|
// --- Thrillers, Mystery & Crime ---
|
||||||
|
"The Midnight Code Cryptograph",
|
||||||
|
"Shadows in the Highveld",
|
||||||
|
"The Silent Witness of Midrand",
|
||||||
|
"Deception on the 14th Floor",
|
||||||
|
|
||||||
|
// --- Business, Finance & Wealth ---
|
||||||
|
"Mastering the South African Tech Market",
|
||||||
|
"The Modern Entrepreneur's Blueprint",
|
||||||
|
"Generational Wealth and Venture Capital",
|
||||||
|
"Negotiation Tactics for High-Stakes Deals",
|
||||||
|
|
||||||
|
// --- Self-Help & Personal Growth ---
|
||||||
|
"The Art of Relentless Focus",
|
||||||
|
"Building High-Performance Habits",
|
||||||
|
"The Mindfulness Guide for Software Engineers",
|
||||||
|
"Unlocking Creative Flow Under Pressure"
|
||||||
|
);
|
||||||
|
|
||||||
|
// Defensive Length Processing to avoid Entity Framework / Postgres string truncation crashes
|
||||||
|
var rawTitle = $"{faker.Company.CatchPhrase()} with {bookTopic}";
|
||||||
|
var bookTitle = rawTitle.Length > 255 ? rawTitle[..252] + "..." : rawTitle;
|
||||||
|
|
||||||
|
var rawSummary = $"A comprehensive guide to mastering {bookTopic}. Learn modern implementation techniques through real-world software engineering paradigms.";
|
||||||
|
var bookSummary = rawSummary.Length > 512 ? rawSummary[..509] + "..." : rawSummary;
|
||||||
|
|
||||||
|
// Generating a single concise paragraph ensures a rich text description falling safely well under 1024
|
||||||
|
var rawDescription = faker.Lorem.Paragraph(3);
|
||||||
|
var bookDescription = rawDescription.Length > 1024 ? rawDescription[..1021] + "..." : rawDescription;
|
||||||
|
|
||||||
|
var authorFirstName = faker.Name.FirstName();
|
||||||
|
var authorLastName = faker.Name.LastName();
|
||||||
|
var publisherCompany = faker.Company.CompanyName();
|
||||||
|
|
||||||
|
// Step 1: Add Product
|
||||||
|
var productCreateResult = await productService.CreateProductAsync(new Products.Models.CreateProduct
|
||||||
|
{
|
||||||
|
Name = bookTitle,
|
||||||
|
Summary = bookSummary,
|
||||||
|
Description = bookDescription,
|
||||||
|
ImageUrl = $"{cdnSettings.BaseCdn}{bookCover}",
|
||||||
|
Type = ProductTypes.Book,
|
||||||
|
Metadata = new Models.ProductMetadata
|
||||||
|
{
|
||||||
|
CopyrightInfo = $"© {DateTime.UtcNow.Year} {publisherCompany}. All rights reserved.",
|
||||||
|
ManufactureDate = faker.Date.Past(3).ToString("yyyy-MM-dd", culture),
|
||||||
|
Manufacturer = $"{authorFirstName} {authorLastName} / {publisherCompany}",
|
||||||
|
SerialNumber = faker.Phone.PhoneNumber("978-##########")
|
||||||
|
},
|
||||||
|
Categories = ["Coding", "Computers", "IT"]
|
||||||
|
}, stoppingToken);
|
||||||
|
|
||||||
|
if (productCreateResult.IsFailed)
|
||||||
|
{
|
||||||
|
logger.LogError("Failed to create product: {Error}", productCreateResult.Errors[0].Message);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 2: Enable product so it can show on the shop
|
||||||
|
var enableProductResult = await productService.UpdateProductStatusAsync(productId: productCreateResult.Value, isEnabled: true, stoppingToken);
|
||||||
|
|
||||||
|
if (enableProductResult.IsFailed)
|
||||||
|
{
|
||||||
|
logger.LogError("Failed to enable created product: {Error}", enableProductResult.Errors[0].Message);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 3: Create Product Price
|
||||||
|
var productPriceCreateResult = await productService.CreateProductPriceAsync(productId: productCreateResult.Value, request: new Products.Models.CreateProductPrice
|
||||||
|
{
|
||||||
|
// Generates fair, dynamic prices in Rands between R150 and R650, snapped neatly to integers
|
||||||
|
Amount = Math.Round(faker.Random.Decimal(150m, 650m), 2),
|
||||||
|
Discount = 0.0m
|
||||||
|
}, stoppingToken);
|
||||||
|
|
||||||
|
if (productPriceCreateResult.IsFailed)
|
||||||
|
{
|
||||||
|
logger.LogError("Failed to create product price: {Error}", productPriceCreateResult.Errors[0].Message);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 4: Create Author
|
||||||
|
var authorCreateResult = await authorService.CreateAuthorAsync(request: new Authors.Models.CreateAuthor
|
||||||
|
{
|
||||||
|
Name = authorFirstName,
|
||||||
|
LastName = authorLastName,
|
||||||
|
Company = publisherCompany,
|
||||||
|
VatNumber = faker.Random.Bool() ? faker.Phone.PhoneNumber("4#########") : "",
|
||||||
|
PublisherType = faker.PickRandom<PublisherTypes>(),
|
||||||
|
Email = faker.Internet.Email(authorFirstName, authorLastName),
|
||||||
|
Website = faker.Internet.Url(),
|
||||||
|
ImageUrl = faker.Internet.Avatar(),
|
||||||
|
SocialMedia =
|
||||||
|
[
|
||||||
|
new Models.SocialMedia
|
||||||
|
{
|
||||||
|
Name = "LinkedIn",
|
||||||
|
ImageUrl = "https://cdn.example.com/icons/linkedin.png",
|
||||||
|
Type = SocialMediaTypes.LinkedIn,
|
||||||
|
Url = $"https://linkedin.com/in/{authorFirstName.ToLower(culture)}-{authorLastName.ToLower(culture)}"
|
||||||
|
},
|
||||||
|
new Models.SocialMedia
|
||||||
|
{
|
||||||
|
Name = "GitHub",
|
||||||
|
ImageUrl = "https://cdn.example.com/icons/github.png",
|
||||||
|
Type = SocialMediaTypes.GitHub,
|
||||||
|
Url = $"https://github.com/tech-{authorFirstName.ToLower(culture)}"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
Biography = $"{authorFirstName} {authorLastName} is a veteran technologist and systems architect with over a decade of domain expertise. " + faker.Lorem.Paragraph(2),
|
||||||
|
ThumbnailImageUrl = null
|
||||||
|
}, stoppingToken);
|
||||||
|
|
||||||
|
if (authorCreateResult.IsFailed)
|
||||||
|
{
|
||||||
|
logger.LogError("Failed to create author: {Error}", authorCreateResult.Errors[0].Message);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 5: Create Author-Book link (product linkage)
|
||||||
|
var authorBookCreateResult = await booksService.CreateBookAsync(authorId: authorCreateResult.Value, productId: productCreateResult.Value, stoppingToken);
|
||||||
|
|
||||||
|
if (authorBookCreateResult.IsFailed)
|
||||||
|
{
|
||||||
|
logger.LogError("Failed to create author-book linkage: {Error}", authorBookCreateResult.Errors[0].Message);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
var enableAuthorBookResult = await booksService.UpdateBookStatusAsync(bookId: authorBookCreateResult.Value, isEnabled: true, stoppingToken);
|
||||||
|
|
||||||
|
if (enableAuthorBookResult.IsFailed)
|
||||||
|
{
|
||||||
|
logger.LogError("Failed to enable author-book link: {Error}", enableAuthorBookResult.Errors[0].Message);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.LogInformation("Successfully seeded book product: {Title}", bookTitle);
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.LogInformation("Product Seeding completed successfully.");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
using LiteCharms.Features.MidrandBooks.Extensions;
|
||||||
|
using LiteCharms.Features.MidrandBooks.Seed;
|
||||||
|
using LiteCharms.Features.MidrandBooks.Seed.Configuration;
|
||||||
|
|
||||||
|
var builder = Host.CreateApplicationBuilder(args);
|
||||||
|
|
||||||
|
builder.Configuration
|
||||||
|
.AddJsonFile("appsettings.json")
|
||||||
|
.AddUserSecrets(typeof(Program).Assembly);
|
||||||
|
|
||||||
|
builder.Services
|
||||||
|
.AddLogging()
|
||||||
|
.AddShopServices()
|
||||||
|
.AddHostedService<ProductsSeederService>()
|
||||||
|
.AddMidrandShopDatabase(builder.Configuration);
|
||||||
|
|
||||||
|
builder.Services.Configure<CdnSettings>(options => builder.Configuration.GetSection(nameof(CdnSettings)).Bind(options));
|
||||||
|
|
||||||
|
using var host = builder.Build();
|
||||||
|
|
||||||
|
await host.RunAsync();
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
{
|
||||||
|
"CdnSettings": {
|
||||||
|
"BaseCdn": "https://bookshop.cdn.khongisa.co.za/design/",
|
||||||
|
"BookCovers": [
|
||||||
|
"144e0314-0bd8-4e2c-8814-2b34608c0600_1764780116467.webp",
|
||||||
|
"2bf1f9a2-7b25-4fcf-9aa7-08941ea21e6c_1764838499686.webp",
|
||||||
|
"3cd172b9-416e-4b3a-b613-7ff0a3aecc4c_1764780129459.webp",
|
||||||
|
"762947b6-63ac-436e-98fb-91dd94de1d82_1764780126141.webp",
|
||||||
|
"7b42f23f-666c-4dd9-82e1-9b928e1b4db7_1764780186376.webp",
|
||||||
|
"8e281eea-8910-473d-b650-43f539995d9e_1764780152316.webp",
|
||||||
|
"91d18e2c-6ee6-44b4-84a5-8692db5dbfe4_1764780114484.webp",
|
||||||
|
"94fdf403-4d10-4cb4-a537-fc914a1f5ba8_1764780198423.webp",
|
||||||
|
"9b881786-75e1-47f7-9bc9-27188d46d1ec_1764780122458.webp",
|
||||||
|
"c417236d-a628-45eb-82c2-ec1cb0326e4f_1765006317965.webp",
|
||||||
|
"clpqjsgi71jpr1i6392e449l2.webp",
|
||||||
|
"clps1mk9f0m1z1i32grvq17tg.webp",
|
||||||
|
"clq550xxy2dab1ywb6mdv4acv.webp",
|
||||||
|
"clq5535o52dj51yw557ml49c1.webp",
|
||||||
|
"clq55455w2dcm1yvd8d8258d8.webp",
|
||||||
|
"clq558fkh2djy1ywbghwcawnh.webp",
|
||||||
|
"clq55cvqh2dqi1yyratl123wq.webp",
|
||||||
|
"clrhnk94e115k1y00bg8h9ixb.webp",
|
||||||
|
"d44a3c04-f124-4f0b-8301-3841ae2fd439_1764780121224.webp",
|
||||||
|
"e6ba52f208914285bcdf1966cfb08f6f.jpg",
|
||||||
|
"fa9cbbe6-f947-4f83-8e98-61d2661f43e0_1764841636705.webp"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -162,8 +162,5 @@
|
|||||||
<Using Include="Microsoft.Extensions.Options" />
|
<Using Include="Microsoft.Extensions.Options" />
|
||||||
<Using Include="Microsoft.Extensions.Logging" />
|
<Using Include="Microsoft.Extensions.Logging" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
|
||||||
<Folder Include="Postgres\Migrations\" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
+1
-46
@@ -12,7 +12,7 @@ using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
|||||||
namespace LiteCharms.Features.MidrandBooks.Postgres.Migrations
|
namespace LiteCharms.Features.MidrandBooks.Postgres.Migrations
|
||||||
{
|
{
|
||||||
[DbContext(typeof(MidrandBooksDbContext))]
|
[DbContext(typeof(MidrandBooksDbContext))]
|
||||||
[Migration("20260528052014_Init")]
|
[Migration("20260529070104_Init")]
|
||||||
partial class Init
|
partial class Init
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@@ -649,40 +649,6 @@ namespace LiteCharms.Features.MidrandBooks.Postgres.Migrations
|
|||||||
b.ToTable("Prices", (string)null);
|
b.ToTable("Prices", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("LiteCharms.Features.MidrandBooks.Products.Models.ProductPrice", b =>
|
|
||||||
{
|
|
||||||
b.Property<long>("Id")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("bigint");
|
|
||||||
|
|
||||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
|
|
||||||
|
|
||||||
b.Property<decimal>("Amount")
|
|
||||||
.HasColumnType("numeric");
|
|
||||||
|
|
||||||
b.Property<DateTime>("CreatedAt")
|
|
||||||
.HasColumnType("timestamp with time zone");
|
|
||||||
|
|
||||||
b.Property<decimal>("Discount")
|
|
||||||
.HasColumnType("numeric");
|
|
||||||
|
|
||||||
b.Property<bool>("Enabled")
|
|
||||||
.HasColumnType("boolean");
|
|
||||||
|
|
||||||
b.Property<long>("ProductId")
|
|
||||||
.HasColumnType("bigint");
|
|
||||||
|
|
||||||
b.Property<DateTime?>("UpdatedAt")
|
|
||||||
.HasColumnType("timestamp with time zone");
|
|
||||||
|
|
||||||
b.HasKey("Id");
|
|
||||||
|
|
||||||
b.HasIndex("ProductId")
|
|
||||||
.IsUnique();
|
|
||||||
|
|
||||||
b.ToTable("ProductPrice");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("LiteCharms.Features.MidrandBooks.AuthorBooks.Entities.AuthorBook", b =>
|
modelBuilder.Entity("LiteCharms.Features.MidrandBooks.AuthorBooks.Entities.AuthorBook", b =>
|
||||||
{
|
{
|
||||||
b.HasOne("LiteCharms.Features.MidrandBooks.Authors.Entities.Author", "Author")
|
b.HasOne("LiteCharms.Features.MidrandBooks.Authors.Entities.Author", "Author")
|
||||||
@@ -931,15 +897,6 @@ namespace LiteCharms.Features.MidrandBooks.Postgres.Migrations
|
|||||||
b.Navigation("Product");
|
b.Navigation("Product");
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("LiteCharms.Features.MidrandBooks.Products.Models.ProductPrice", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("LiteCharms.Features.MidrandBooks.Products.Entities.Product", null)
|
|
||||||
.WithOne("Price")
|
|
||||||
.HasForeignKey("LiteCharms.Features.MidrandBooks.Products.Models.ProductPrice", "ProductId")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired();
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("LiteCharms.Features.MidrandBooks.AuthorBooks.Entities.AuthorBook", b =>
|
modelBuilder.Entity("LiteCharms.Features.MidrandBooks.AuthorBooks.Entities.AuthorBook", b =>
|
||||||
{
|
{
|
||||||
b.Navigation("Pages");
|
b.Navigation("Pages");
|
||||||
@@ -973,8 +930,6 @@ namespace LiteCharms.Features.MidrandBooks.Postgres.Migrations
|
|||||||
|
|
||||||
modelBuilder.Entity("LiteCharms.Features.MidrandBooks.Products.Entities.Product", b =>
|
modelBuilder.Entity("LiteCharms.Features.MidrandBooks.Products.Entities.Product", b =>
|
||||||
{
|
{
|
||||||
b.Navigation("Price");
|
|
||||||
|
|
||||||
b.Navigation("Prices");
|
b.Navigation("Prices");
|
||||||
});
|
});
|
||||||
#pragma warning restore 612, 618
|
#pragma warning restore 612, 618
|
||||||
-33
@@ -259,30 +259,6 @@ namespace LiteCharms.Features.MidrandBooks.Postgres.Migrations
|
|||||||
onDelete: ReferentialAction.Restrict);
|
onDelete: ReferentialAction.Restrict);
|
||||||
});
|
});
|
||||||
|
|
||||||
//migrationBuilder.CreateTable(
|
|
||||||
// name: "ProductPrice",
|
|
||||||
// columns: table => new
|
|
||||||
// {
|
|
||||||
// Id = table.Column<long>(type: "bigint", nullable: false)
|
|
||||||
// .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
|
||||||
// CreatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
|
|
||||||
// UpdatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
|
|
||||||
// ProductId = table.Column<long>(type: "bigint", nullable: false),
|
|
||||||
// Amount = table.Column<decimal>(type: "numeric", nullable: false),
|
|
||||||
// Discount = table.Column<decimal>(type: "numeric", nullable: false),
|
|
||||||
// Enabled = table.Column<bool>(type: "boolean", nullable: false)
|
|
||||||
// },
|
|
||||||
// constraints: table =>
|
|
||||||
// {
|
|
||||||
// table.PrimaryKey("PK_ProductPrice", x => x.Id);
|
|
||||||
// table.ForeignKey(
|
|
||||||
// name: "FK_ProductPrice_Products_ProductId",
|
|
||||||
// column: x => x.ProductId,
|
|
||||||
// principalTable: "Products",
|
|
||||||
// principalColumn: "Id",
|
|
||||||
// onDelete: ReferentialAction.Cascade);
|
|
||||||
// });
|
|
||||||
|
|
||||||
migrationBuilder.CreateTable(
|
migrationBuilder.CreateTable(
|
||||||
name: "Shippings",
|
name: "Shippings",
|
||||||
columns: table => new
|
columns: table => new
|
||||||
@@ -427,12 +403,6 @@ namespace LiteCharms.Features.MidrandBooks.Postgres.Migrations
|
|||||||
table: "Prices",
|
table: "Prices",
|
||||||
column: "ProductId");
|
column: "ProductId");
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
|
||||||
name: "IX_ProductPrice_ProductId",
|
|
||||||
table: "ProductPrice",
|
|
||||||
column: "ProductId",
|
|
||||||
unique: true);
|
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
migrationBuilder.CreateIndex(
|
||||||
name: "IX_Refunds_OrderId",
|
name: "IX_Refunds_OrderId",
|
||||||
table: "Refunds",
|
table: "Refunds",
|
||||||
@@ -467,9 +437,6 @@ namespace LiteCharms.Features.MidrandBooks.Postgres.Migrations
|
|||||||
migrationBuilder.DropTable(
|
migrationBuilder.DropTable(
|
||||||
name: "OrderItems");
|
name: "OrderItems");
|
||||||
|
|
||||||
migrationBuilder.DropTable(
|
|
||||||
name: "ProductPrice");
|
|
||||||
|
|
||||||
migrationBuilder.DropTable(
|
migrationBuilder.DropTable(
|
||||||
name: "Refunds");
|
name: "Refunds");
|
||||||
|
|
||||||
+6
-51
@@ -57,7 +57,7 @@ namespace LiteCharms.Features.MidrandBooks.Postgres.Migrations
|
|||||||
|
|
||||||
b.HasIndex("ProductId");
|
b.HasIndex("ProductId");
|
||||||
|
|
||||||
b.ToTable("Books", (string)null);
|
b.ToTable("Books");
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("LiteCharms.Features.MidrandBooks.Authors.Entities.Author", b =>
|
modelBuilder.Entity("LiteCharms.Features.MidrandBooks.Authors.Entities.Author", b =>
|
||||||
@@ -454,7 +454,7 @@ namespace LiteCharms.Features.MidrandBooks.Postgres.Migrations
|
|||||||
|
|
||||||
b.HasKey("Id");
|
b.HasKey("Id");
|
||||||
|
|
||||||
b.ToTable("ShippingProviders", (string)null);
|
b.ToTable("ShippingProviders");
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("LiteCharms.Features.MidrandBooks.Pages.Entities.BookPage", b =>
|
modelBuilder.Entity("LiteCharms.Features.MidrandBooks.Pages.Entities.BookPage", b =>
|
||||||
@@ -646,40 +646,6 @@ namespace LiteCharms.Features.MidrandBooks.Postgres.Migrations
|
|||||||
b.ToTable("Prices", (string)null);
|
b.ToTable("Prices", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("LiteCharms.Features.MidrandBooks.Products.Models.ProductPrice", b =>
|
|
||||||
{
|
|
||||||
b.Property<long>("Id")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("bigint");
|
|
||||||
|
|
||||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
|
|
||||||
|
|
||||||
b.Property<decimal>("Amount")
|
|
||||||
.HasColumnType("numeric");
|
|
||||||
|
|
||||||
b.Property<DateTime>("CreatedAt")
|
|
||||||
.HasColumnType("timestamp with time zone");
|
|
||||||
|
|
||||||
b.Property<decimal>("Discount")
|
|
||||||
.HasColumnType("numeric");
|
|
||||||
|
|
||||||
b.Property<bool>("Enabled")
|
|
||||||
.HasColumnType("boolean");
|
|
||||||
|
|
||||||
b.Property<long>("ProductId")
|
|
||||||
.HasColumnType("bigint");
|
|
||||||
|
|
||||||
b.Property<DateTime?>("UpdatedAt")
|
|
||||||
.HasColumnType("timestamp with time zone");
|
|
||||||
|
|
||||||
b.HasKey("Id");
|
|
||||||
|
|
||||||
b.HasIndex("ProductId")
|
|
||||||
.IsUnique();
|
|
||||||
|
|
||||||
b.ToTable("ProductPrice", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("LiteCharms.Features.MidrandBooks.AuthorBooks.Entities.AuthorBook", b =>
|
modelBuilder.Entity("LiteCharms.Features.MidrandBooks.AuthorBooks.Entities.AuthorBook", b =>
|
||||||
{
|
{
|
||||||
b.HasOne("LiteCharms.Features.MidrandBooks.Authors.Entities.Author", "Author")
|
b.HasOne("LiteCharms.Features.MidrandBooks.Authors.Entities.Author", "Author")
|
||||||
@@ -718,7 +684,7 @@ namespace LiteCharms.Features.MidrandBooks.Postgres.Migrations
|
|||||||
|
|
||||||
b1.HasKey("AuthorId", "__synthesizedOrdinal");
|
b1.HasKey("AuthorId", "__synthesizedOrdinal");
|
||||||
|
|
||||||
b1.ToTable("Authors", (string)null);
|
b1.ToTable("Authors");
|
||||||
|
|
||||||
b1
|
b1
|
||||||
.ToJson("SocialMedia")
|
.ToJson("SocialMedia")
|
||||||
@@ -772,7 +738,7 @@ namespace LiteCharms.Features.MidrandBooks.Postgres.Migrations
|
|||||||
|
|
||||||
b1.HasKey("CustomerId", "__synthesizedOrdinal");
|
b1.HasKey("CustomerId", "__synthesizedOrdinal");
|
||||||
|
|
||||||
b1.ToTable("Customers", (string)null);
|
b1.ToTable("Customers");
|
||||||
|
|
||||||
b1
|
b1
|
||||||
.ToJson("SocialMedia")
|
.ToJson("SocialMedia")
|
||||||
@@ -862,7 +828,7 @@ namespace LiteCharms.Features.MidrandBooks.Postgres.Migrations
|
|||||||
|
|
||||||
b1.HasKey("BookPageId", "__synthesizedOrdinal");
|
b1.HasKey("BookPageId", "__synthesizedOrdinal");
|
||||||
|
|
||||||
b1.ToTable("BookPages", (string)null);
|
b1.ToTable("BookPages");
|
||||||
|
|
||||||
b1
|
b1
|
||||||
.ToJson("References")
|
.ToJson("References")
|
||||||
@@ -904,7 +870,7 @@ namespace LiteCharms.Features.MidrandBooks.Postgres.Migrations
|
|||||||
|
|
||||||
b1.HasKey("ProductId");
|
b1.HasKey("ProductId");
|
||||||
|
|
||||||
b1.ToTable("Products", (string)null);
|
b1.ToTable("Products");
|
||||||
|
|
||||||
b1
|
b1
|
||||||
.ToJson("Metadata")
|
.ToJson("Metadata")
|
||||||
@@ -928,15 +894,6 @@ namespace LiteCharms.Features.MidrandBooks.Postgres.Migrations
|
|||||||
b.Navigation("Product");
|
b.Navigation("Product");
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("LiteCharms.Features.MidrandBooks.Products.Models.ProductPrice", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("LiteCharms.Features.MidrandBooks.Products.Entities.Product", null)
|
|
||||||
.WithOne("Price")
|
|
||||||
.HasForeignKey("LiteCharms.Features.MidrandBooks.Products.Models.ProductPrice", "ProductId")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired();
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("LiteCharms.Features.MidrandBooks.AuthorBooks.Entities.AuthorBook", b =>
|
modelBuilder.Entity("LiteCharms.Features.MidrandBooks.AuthorBooks.Entities.AuthorBook", b =>
|
||||||
{
|
{
|
||||||
b.Navigation("Pages");
|
b.Navigation("Pages");
|
||||||
@@ -970,8 +927,6 @@ namespace LiteCharms.Features.MidrandBooks.Postgres.Migrations
|
|||||||
|
|
||||||
modelBuilder.Entity("LiteCharms.Features.MidrandBooks.Products.Entities.Product", b =>
|
modelBuilder.Entity("LiteCharms.Features.MidrandBooks.Products.Entities.Product", b =>
|
||||||
{
|
{
|
||||||
b.Navigation("Price");
|
|
||||||
|
|
||||||
b.Navigation("Prices");
|
b.Navigation("Prices");
|
||||||
});
|
});
|
||||||
#pragma warning restore 612, 618
|
#pragma warning restore 612, 618
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ public sealed class ProductConfiguration : IEntityTypeConfiguration<Product>
|
|||||||
{
|
{
|
||||||
public void Configure(EntityTypeBuilder<Product> builder)
|
public void Configure(EntityTypeBuilder<Product> builder)
|
||||||
{
|
{
|
||||||
|
builder.Ignore(p => p.Price);
|
||||||
|
|
||||||
builder.ToTable("Products");
|
builder.ToTable("Products");
|
||||||
|
|
||||||
builder.HasKey(f => f.Id);
|
builder.HasKey(f => f.Id);
|
||||||
|
|||||||
@@ -93,7 +93,8 @@ public enum SocialMediaTypes : int
|
|||||||
YouTube = 5,
|
YouTube = 5,
|
||||||
Pinterest = 6,
|
Pinterest = 6,
|
||||||
Reddit = 7,
|
Reddit = 7,
|
||||||
Tumblr = 8
|
Tumblr = 8,
|
||||||
|
GitHub = 9
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum EmailStatuses : int
|
public enum EmailStatuses : int
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
<Project Path="LiteCharms.Features/LiteCharms.Features.csproj" />
|
<Project Path="LiteCharms.Features/LiteCharms.Features.csproj" />
|
||||||
</Folder>
|
</Folder>
|
||||||
<Folder Name="/tests/">
|
<Folder Name="/tests/">
|
||||||
|
<Project Path="LiteCharms.Features.MidrandBooks.Seed/LiteCharms.Features.MidrandBooks.Seed.csproj" Id="aa80643a-28dc-431f-b163-053a94e5c77c" />
|
||||||
<Project Path="LiteCharms.Features.MidrandBooks.Tests/LiteCharms.Features.MidrandBooks.Tests.csproj" Id="cac2f738-dbb5-4538-8565-3c2bd6f65259" />
|
<Project Path="LiteCharms.Features.MidrandBooks.Tests/LiteCharms.Features.MidrandBooks.Tests.csproj" Id="cac2f738-dbb5-4538-8565-3c2bd6f65259" />
|
||||||
<Project Path="LiteCharms.Features.TechShop.Tests/LiteCharms.Features.TechShop.Tests.csproj" Id="0e0967c2-7f28-4668-a387-2fc437ab066f" />
|
<Project Path="LiteCharms.Features.TechShop.Tests/LiteCharms.Features.TechShop.Tests.csproj" Id="0e0967c2-7f28-4668-a387-2fc437ab066f" />
|
||||||
<Project Path="LiteCharms.Features.Tests/LiteCharms.Features.Tests.csproj" Id="0696323f-7148-4ab9-9145-68b7b5df5415" />
|
<Project Path="LiteCharms.Features.Tests/LiteCharms.Features.Tests.csproj" Id="0696323f-7148-4ab9-9145-68b7b5df5415" />
|
||||||
|
|||||||
Reference in New Issue
Block a user