Seeding, cleanup, fix nginx proxying
This commit is contained in:
@@ -43,7 +43,16 @@ http {
|
|||||||
add_header X-Content-Type-Options nosniff always;
|
add_header X-Content-Type-Options nosniff always;
|
||||||
|
|
||||||
location /api/ {
|
location /api/ {
|
||||||
proxy_pass http://webapi/;
|
proxy_pass http://webapi;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /swagger {
|
||||||
|
proxy_pass http://webapi;
|
||||||
proxy_http_version 1.1;
|
proxy_http_version 1.1;
|
||||||
proxy_set_header Host $host;
|
proxy_set_header Host $host;
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
|||||||
@@ -17,10 +17,4 @@
|
|||||||
<ProjectReference Include="..\Imprink.Domain\Imprink.Domain.csproj" />
|
<ProjectReference Include="..\Imprink.Domain\Imprink.Domain.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<Folder Include="Users\Create\" />
|
|
||||||
<Folder Include="Users\Delete\" />
|
|
||||||
<Folder Include="Users\Query\" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ using Imprink.Application.Products.Dtos;
|
|||||||
using Imprink.Domain.Common.Models;
|
using Imprink.Domain.Common.Models;
|
||||||
using MediatR;
|
using MediatR;
|
||||||
|
|
||||||
namespace Imprink.Application.Products.Query;
|
namespace Imprink.Application.Products;
|
||||||
|
|
||||||
public class GetProductsQuery : IRequest<PagedResultDto<ProductDto>>
|
public class GetProductsQuery : IRequest<PagedResultDto<ProductDto>>
|
||||||
{
|
{
|
||||||
@@ -6,10 +6,6 @@
|
|||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<Folder Include="Exceptions\" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.Extensions.Identity.Stores" Version="9.0.4" />
|
<PackageReference Include="Microsoft.Extensions.Identity.Stores" Version="9.0.4" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|||||||
@@ -10,18 +10,7 @@ public interface IUserRepository
|
|||||||
Task<User?> GetUserByEmailAsync(string email, CancellationToken cancellationToken = default);
|
Task<User?> GetUserByEmailAsync(string email, CancellationToken cancellationToken = default);
|
||||||
Task<IEnumerable<User>> GetAllUsersAsync(CancellationToken cancellationToken = default);
|
Task<IEnumerable<User>> GetAllUsersAsync(CancellationToken cancellationToken = default);
|
||||||
Task<IEnumerable<User>> GetActiveUsersAsync(CancellationToken cancellationToken = default);
|
Task<IEnumerable<User>> GetActiveUsersAsync(CancellationToken cancellationToken = default);
|
||||||
|
|
||||||
Task<User> CreateUserAsync(User user, CancellationToken cancellationToken = default);
|
|
||||||
Task<User> UpdateUserAsync(User user, CancellationToken cancellationToken = default);
|
|
||||||
Task DeleteUserAsync(string userId, CancellationToken cancellationToken = default);
|
|
||||||
|
|
||||||
Task<bool> UserExistsAsync(string userId, CancellationToken cancellationToken = default);
|
Task<bool> UserExistsAsync(string userId, CancellationToken cancellationToken = default);
|
||||||
Task<bool> EmailExistsAsync(string email, CancellationToken cancellationToken = default);
|
|
||||||
|
|
||||||
Task<bool> ActivateUserAsync(string userId, CancellationToken cancellationToken = default);
|
|
||||||
Task<bool> DeactivateUserAsync(string userId, CancellationToken cancellationToken = default);
|
|
||||||
|
|
||||||
Task<IEnumerable<User>> GetUsersByRoleAsync(Guid roleId, CancellationToken cancellationToken = default);
|
Task<IEnumerable<User>> GetUsersByRoleAsync(Guid roleId, CancellationToken cancellationToken = default);
|
||||||
|
|
||||||
Task<User?> GetUserWithAllRelatedDataAsync(string userId, CancellationToken cancellationToken = default);
|
Task<User?> GetUserWithAllRelatedDataAsync(string userId, CancellationToken cancellationToken = default);
|
||||||
}
|
}
|
||||||
@@ -23,7 +23,6 @@ public class RoleConfiguration : IEntityTypeConfiguration<Role>
|
|||||||
.HasDatabaseName("IX_Role_RoleName");
|
.HasDatabaseName("IX_Role_RoleName");
|
||||||
|
|
||||||
builder.HasData(
|
builder.HasData(
|
||||||
new Role { Id = Guid.Parse("11111111-1111-1111-1111-111111111111"), RoleName = "User" },
|
|
||||||
new Role { Id = Guid.Parse("22222222-2222-2222-2222-222222222222"), RoleName = "Merchant" },
|
new Role { Id = Guid.Parse("22222222-2222-2222-2222-222222222222"), RoleName = "Merchant" },
|
||||||
new Role { Id = Guid.Parse("33333333-3333-3333-3333-333333333333"), RoleName = "Admin" }
|
new Role { Id = Guid.Parse("33333333-3333-3333-3333-333333333333"), RoleName = "Admin" }
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
|||||||
namespace Imprink.Infrastructure.Migrations
|
namespace Imprink.Infrastructure.Migrations
|
||||||
{
|
{
|
||||||
[DbContext(typeof(ApplicationDbContext))]
|
[DbContext(typeof(ApplicationDbContext))]
|
||||||
[Migration("20250608204903_InitialSetup")]
|
[Migration("20250609202250_InitialSetup")]
|
||||||
partial class InitialSetup
|
partial class InitialSetup
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@@ -8,35 +8,9 @@ namespace Imprink.Infrastructure.Repositories;
|
|||||||
|
|
||||||
public class ProductRepository(ApplicationDbContext context) : IProductRepository
|
public class ProductRepository(ApplicationDbContext context) : IProductRepository
|
||||||
{
|
{
|
||||||
public async Task<Product?> GetByIdAsync(Guid id, CancellationToken cancellationToken = default)
|
public async Task<PagedResult<Product>> GetPagedAsync(
|
||||||
{
|
ProductFilterParameters filterParameters,
|
||||||
return await context.Products
|
CancellationToken cancellationToken = default)
|
||||||
.FirstOrDefaultAsync(p => p.Id == id, cancellationToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<Product?> GetByIdWithVariantsAsync(Guid id, CancellationToken cancellationToken = default)
|
|
||||||
{
|
|
||||||
return await context.Products
|
|
||||||
.Include(p => p.ProductVariants.Where(pv => pv.IsActive))
|
|
||||||
.FirstOrDefaultAsync(p => p.Id == id, cancellationToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<Product?> GetByIdWithCategoryAsync(Guid id, CancellationToken cancellationToken = default)
|
|
||||||
{
|
|
||||||
return await context.Products
|
|
||||||
.Include(p => p.Category)
|
|
||||||
.FirstOrDefaultAsync(p => p.Id == id, cancellationToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<Product?> GetByIdFullAsync(Guid id, CancellationToken cancellationToken = default)
|
|
||||||
{
|
|
||||||
return await context.Products
|
|
||||||
.Include(p => p.Category)
|
|
||||||
.Include(p => p.ProductVariants.Where(pv => pv.IsActive))
|
|
||||||
.FirstOrDefaultAsync(p => p.Id == id, cancellationToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<PagedResult<Product>> GetPagedAsync(ProductFilterParameters filterParameters, CancellationToken cancellationToken = default)
|
|
||||||
{
|
{
|
||||||
var query = context.Products
|
var query = context.Products
|
||||||
.Include(p => p.Category)
|
.Include(p => p.Category)
|
||||||
@@ -49,8 +23,9 @@ public class ProductRepository(ApplicationDbContext context) : IProductRepositor
|
|||||||
|
|
||||||
if (!string.IsNullOrEmpty(filterParameters.SearchTerm))
|
if (!string.IsNullOrEmpty(filterParameters.SearchTerm))
|
||||||
{
|
{
|
||||||
query = query.Where(p => p.Name.Contains(filterParameters.SearchTerm) ||
|
query = query.Where(
|
||||||
(p.Description != null && p.Description.Contains(filterParameters.SearchTerm)));
|
p => p.Name.Contains(filterParameters.SearchTerm)
|
||||||
|
|| (p.Description != null && p.Description.Contains(filterParameters.SearchTerm)));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (filterParameters.CategoryId.HasValue)
|
if (filterParameters.CategoryId.HasValue)
|
||||||
@@ -102,6 +77,34 @@ public class ProductRepository(ApplicationDbContext context) : IProductRepositor
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<Product?> GetByIdAsync(Guid id, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
return await context.Products
|
||||||
|
.FirstOrDefaultAsync(p => p.Id == id, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<Product?> GetByIdWithVariantsAsync(Guid id, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
return await context.Products
|
||||||
|
.Include(p => p.ProductVariants.Where(pv => pv.IsActive))
|
||||||
|
.FirstOrDefaultAsync(p => p.Id == id, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<Product?> GetByIdWithCategoryAsync(Guid id, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
return await context.Products
|
||||||
|
.Include(p => p.Category)
|
||||||
|
.FirstOrDefaultAsync(p => p.Id == id, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<Product?> GetByIdFullAsync(Guid id, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
return await context.Products
|
||||||
|
.Include(p => p.Category)
|
||||||
|
.Include(p => p.ProductVariants.Where(pv => pv.IsActive))
|
||||||
|
.FirstOrDefaultAsync(p => p.Id == id, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<IEnumerable<Product>> GetByCategoryAsync(Guid categoryId, CancellationToken cancellationToken = default)
|
public async Task<IEnumerable<Product>> GetByCategoryAsync(Guid categoryId, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
return await context.Products
|
return await context.Products
|
||||||
@@ -68,62 +68,12 @@ public class UserRepository(ApplicationDbContext context) : IUserRepository
|
|||||||
.ToListAsync(cancellationToken);
|
.ToListAsync(cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<User> CreateUserAsync(User user, CancellationToken cancellationToken = default)
|
|
||||||
{
|
|
||||||
context.Users.Add(user);
|
|
||||||
await context.SaveChangesAsync(cancellationToken);
|
|
||||||
return user;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<User> UpdateUserAsync(User user, CancellationToken cancellationToken = default)
|
|
||||||
{
|
|
||||||
context.Users.Update(user);
|
|
||||||
await context.SaveChangesAsync(cancellationToken);
|
|
||||||
return user;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task DeleteUserAsync(string userId, CancellationToken cancellationToken = default)
|
|
||||||
{
|
|
||||||
var user = await context.Users.FindAsync(new object[] { userId }, cancellationToken);
|
|
||||||
if (user != null)
|
|
||||||
{
|
|
||||||
context.Users.Remove(user);
|
|
||||||
await context.SaveChangesAsync(cancellationToken);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<bool> UserExistsAsync(string userId, CancellationToken cancellationToken = default)
|
public async Task<bool> UserExistsAsync(string userId, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
return await context.Users
|
return await context.Users
|
||||||
.AnyAsync(u => u.Id == userId, cancellationToken);
|
.AnyAsync(u => u.Id == userId, cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<bool> EmailExistsAsync(string email, CancellationToken cancellationToken = default)
|
|
||||||
{
|
|
||||||
return await context.Users
|
|
||||||
.AnyAsync(u => u.Email == email, cancellationToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<bool> ActivateUserAsync(string userId, CancellationToken cancellationToken = default)
|
|
||||||
{
|
|
||||||
var user = await context.Users.FindAsync(new object[] { userId }, cancellationToken);
|
|
||||||
if (user == null) return false;
|
|
||||||
|
|
||||||
user.IsActive = true;
|
|
||||||
await context.SaveChangesAsync(cancellationToken);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<bool> DeactivateUserAsync(string userId, CancellationToken cancellationToken = default)
|
|
||||||
{
|
|
||||||
var user = await context.Users.FindAsync(new object[] { userId }, cancellationToken);
|
|
||||||
if (user == null) return false;
|
|
||||||
|
|
||||||
user.IsActive = false;
|
|
||||||
await context.SaveChangesAsync(cancellationToken);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<IEnumerable<User>> GetUsersByRoleAsync(Guid roleId, CancellationToken cancellationToken = default)
|
public async Task<IEnumerable<User>> GetUsersByRoleAsync(Guid roleId, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
return await context.Users
|
return await context.Users
|
||||||
@@ -1,5 +1,3 @@
|
|||||||
using Imprink.Application.Products.Create;
|
|
||||||
using Imprink.Application.Products.Delete;
|
|
||||||
using Imprink.Application.Products.Dtos;
|
using Imprink.Application.Products.Dtos;
|
||||||
using Imprink.Application.Products.Query;
|
using Imprink.Application.Products.Query;
|
||||||
using MediatR;
|
using MediatR;
|
||||||
@@ -8,40 +6,13 @@ using Microsoft.AspNetCore.Mvc;
|
|||||||
namespace Imprink.WebApi.Controllers;
|
namespace Imprink.WebApi.Controllers;
|
||||||
|
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[Route("api/[controller]")]
|
[Route("api/products/categories")]
|
||||||
public class CategoriesController(IMediator mediator) : ControllerBase
|
public class CategoriesController(IMediator mediator) : ControllerBase
|
||||||
{
|
{
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
public async Task<ActionResult<IEnumerable<CategoryDto>>> GetCategories(
|
public async Task<ActionResult<IEnumerable<CategoryDto>>> GetCategories([FromQuery] GetCategoriesQuery query)
|
||||||
[FromQuery] bool? isActive = null,
|
|
||||||
[FromQuery] bool rootCategoriesOnly = false)
|
|
||||||
{
|
{
|
||||||
var query = new GetCategoriesQuery
|
|
||||||
{
|
|
||||||
IsActive = isActive,
|
|
||||||
RootCategoriesOnly = rootCategoriesOnly
|
|
||||||
};
|
|
||||||
|
|
||||||
var result = await mediator.Send(query);
|
var result = await mediator.Send(query);
|
||||||
return Ok(result);
|
return Ok(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost]
|
|
||||||
public async Task<ActionResult<CategoryDto>> CreateCategory([FromBody] CreateCategoryCommand command)
|
|
||||||
{
|
|
||||||
var result = await mediator.Send(command);
|
|
||||||
return CreatedAtAction(nameof(CreateCategory), new { id = result.Id }, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpDelete("{id:guid}")]
|
|
||||||
public async Task<ActionResult> DeleteCategory(Guid id)
|
|
||||||
{
|
|
||||||
var command = new DeleteCategoryCommand { Id = id };
|
|
||||||
var result = await mediator.Send(command);
|
|
||||||
|
|
||||||
if (!result)
|
|
||||||
return NotFound();
|
|
||||||
|
|
||||||
return NoContent();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,3 @@
|
|||||||
using Imprink.Application.Products.Create;
|
|
||||||
using Imprink.Application.Products.Delete;
|
|
||||||
using Imprink.Application.Products.Dtos;
|
using Imprink.Application.Products.Dtos;
|
||||||
using Imprink.Application.Products.Query;
|
using Imprink.Application.Products.Query;
|
||||||
using MediatR;
|
using MediatR;
|
||||||
@@ -8,42 +6,14 @@ using Microsoft.AspNetCore.Mvc;
|
|||||||
namespace Imprink.WebApi.Controllers;
|
namespace Imprink.WebApi.Controllers;
|
||||||
|
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[Route("api/[controller]")]
|
[Route("/api/products/variants")]
|
||||||
public class ProductVariantsController(IMediator mediator) : ControllerBase
|
public class ProductVariantsController(IMediator mediator) : ControllerBase
|
||||||
{
|
{
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
public async Task<ActionResult<IEnumerable<ProductVariantDto>>> GetProductVariants(
|
public async Task<ActionResult<IEnumerable<ProductVariantDto>>> GetProductVariants(
|
||||||
[FromQuery] Guid? productId = null,
|
[FromQuery] GetProductVariantsQuery query)
|
||||||
[FromQuery] bool? isActive = null,
|
|
||||||
[FromQuery] bool inStockOnly = false)
|
|
||||||
{
|
{
|
||||||
var query = new GetProductVariantsQuery
|
|
||||||
{
|
|
||||||
ProductId = productId,
|
|
||||||
IsActive = isActive,
|
|
||||||
InStockOnly = inStockOnly
|
|
||||||
};
|
|
||||||
|
|
||||||
var result = await mediator.Send(query);
|
var result = await mediator.Send(query);
|
||||||
return Ok(result);
|
return Ok(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost]
|
|
||||||
public async Task<ActionResult<ProductVariantDto>> CreateProductVariant([FromBody] CreateProductVariantCommand command)
|
|
||||||
{
|
|
||||||
var result = await mediator.Send(command);
|
|
||||||
return CreatedAtAction(nameof(CreateProductVariant), new { id = result.Id }, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpDelete("{id:guid}")]
|
|
||||||
public async Task<ActionResult> DeleteProductVariant(Guid id)
|
|
||||||
{
|
|
||||||
var command = new DeleteProductVariantCommand { Id = id };
|
|
||||||
var result = await mediator.Send(command);
|
|
||||||
|
|
||||||
if (!result)
|
|
||||||
return NotFound();
|
|
||||||
|
|
||||||
return NoContent();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,66 +1,23 @@
|
|||||||
using Imprink.Application.Products.Create;
|
using Imprink.Application.Products;
|
||||||
using Imprink.Application.Products.Delete;
|
|
||||||
using Imprink.Application.Products.Dtos;
|
using Imprink.Application.Products.Dtos;
|
||||||
using Imprink.Application.Products.Query;
|
|
||||||
using Imprink.Domain.Common.Models;
|
using Imprink.Domain.Common.Models;
|
||||||
using MediatR;
|
using MediatR;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
namespace Imprink.WebApi.Controllers;
|
namespace Imprink.WebApi.Controllers;
|
||||||
|
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[Route("api/[controller]")]
|
[Route("/api/products")]
|
||||||
public class ProductsController(IMediator mediator) : ControllerBase
|
public class ProductsController(IMediator mediator) : ControllerBase
|
||||||
{
|
{
|
||||||
|
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
|
[AllowAnonymous]
|
||||||
public async Task<ActionResult<PagedResultDto<ProductDto>>> GetProducts(
|
public async Task<ActionResult<PagedResultDto<ProductDto>>> GetProducts(
|
||||||
[FromQuery] int pageNumber = 1,
|
[FromQuery] ProductFilterParameters filterParameters)
|
||||||
[FromQuery] int pageSize = 10,
|
|
||||||
[FromQuery] string? searchTerm = null,
|
|
||||||
[FromQuery] Guid? categoryId = null,
|
|
||||||
[FromQuery] decimal? minPrice = null,
|
|
||||||
[FromQuery] decimal? maxPrice = null,
|
|
||||||
[FromQuery] bool? isActive = true,
|
|
||||||
[FromQuery] bool? isCustomizable = null,
|
|
||||||
[FromQuery] string sortBy = "Name",
|
|
||||||
[FromQuery] string sortDirection = "ASC")
|
|
||||||
{
|
{
|
||||||
var filterParameters = new ProductFilterParameters
|
var result = await mediator.Send(new GetProductsQuery { FilterParameters = filterParameters });
|
||||||
{
|
|
||||||
PageNumber = pageNumber,
|
|
||||||
PageSize = pageSize,
|
|
||||||
SearchTerm = searchTerm,
|
|
||||||
CategoryId = categoryId,
|
|
||||||
MinPrice = minPrice,
|
|
||||||
MaxPrice = maxPrice,
|
|
||||||
IsActive = isActive,
|
|
||||||
IsCustomizable = isCustomizable,
|
|
||||||
SortBy = sortBy,
|
|
||||||
SortDirection = sortDirection
|
|
||||||
};
|
|
||||||
|
|
||||||
var query = new GetProductsQuery { FilterParameters = filterParameters };
|
|
||||||
var result = await mediator.Send(query);
|
|
||||||
|
|
||||||
return Ok(result);
|
return Ok(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost]
|
|
||||||
public async Task<ActionResult<ProductDto>> CreateProduct([FromBody] CreateProductCommand command)
|
|
||||||
{
|
|
||||||
var result = await mediator.Send(command);
|
|
||||||
return CreatedAtAction(nameof(CreateProduct), new { id = result.Id }, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpDelete("{id:guid}")]
|
|
||||||
public async Task<ActionResult> DeleteProduct(Guid id)
|
|
||||||
{
|
|
||||||
var command = new DeleteProductCommand { Id = id };
|
|
||||||
var result = await mediator.Send(command);
|
|
||||||
|
|
||||||
if (!result)
|
|
||||||
return NotFound();
|
|
||||||
|
|
||||||
return NoContent();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
17
src/Imprink.WebApi/Controllers/Products/SeedingController.cs
Normal file
17
src/Imprink.WebApi/Controllers/Products/SeedingController.cs
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
|
namespace Imprink.WebApi.Controllers;
|
||||||
|
|
||||||
|
[ApiController]
|
||||||
|
[Route("/api/products/seed")]
|
||||||
|
public class SeedingController(Seeder seeder) : ControllerBase
|
||||||
|
{
|
||||||
|
[HttpGet]
|
||||||
|
[Authorize(Roles = "Admin")]
|
||||||
|
public async Task<ActionResult<bool>> Seed()
|
||||||
|
{
|
||||||
|
await seeder.SeedAsync();
|
||||||
|
return Ok();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,22 +8,22 @@ using Microsoft.AspNetCore.Mvc;
|
|||||||
namespace Imprink.WebApi.Controllers.Users;
|
namespace Imprink.WebApi.Controllers.Users;
|
||||||
|
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[Route("/users")]
|
[Route("/api/users")]
|
||||||
public class UserController(IMediator mediator) : ControllerBase
|
public class UserController(IMediator mediator) : ControllerBase
|
||||||
{
|
{
|
||||||
[Authorize]
|
[Authorize]
|
||||||
[HttpPost("sync")]
|
[HttpPost("sync")]
|
||||||
public async Task<IActionResult> Sync()
|
public async Task<IActionResult> Sync()
|
||||||
{
|
{
|
||||||
var enumerable = User.Claims as Claim[] ?? User.Claims.ToArray();
|
var claims = User.Claims as Claim[] ?? User.Claims.ToArray();
|
||||||
|
|
||||||
var auth0User = new Auth0User
|
var auth0User = new Auth0User
|
||||||
{
|
{
|
||||||
Sub = enumerable.FirstOrDefault(c => c.Type == ClaimTypes.NameIdentifier)?.Value ?? string.Empty,
|
Sub = claims.FirstOrDefault(c => c.Type == ClaimTypes.NameIdentifier)?.Value ?? string.Empty,
|
||||||
Name = enumerable.FirstOrDefault(c => c.Type == "name")?.Value ?? string.Empty,
|
Name = claims.FirstOrDefault(c => c.Type == "name")?.Value ?? string.Empty,
|
||||||
Nickname = enumerable.FirstOrDefault(c => c.Type == "nickname")?.Value ?? string.Empty,
|
Nickname = claims.FirstOrDefault(c => c.Type == "nickname")?.Value ?? string.Empty,
|
||||||
Email = enumerable.FirstOrDefault(c => c.Type == ClaimTypes.Email)?.Value ?? string.Empty,
|
Email = claims.FirstOrDefault(c => c.Type == ClaimTypes.Email)?.Value ?? string.Empty,
|
||||||
EmailVerified = bool.TryParse(enumerable.FirstOrDefault(c => c.Type == "email_verified")?.Value, out var emailVerified) && emailVerified
|
EmailVerified = bool.TryParse(claims.FirstOrDefault(c => c.Type == "email_verified")?.Value, out var emailVerified) && emailVerified
|
||||||
};
|
};
|
||||||
|
|
||||||
await mediator.Send(new SyncUserCommand(auth0User));
|
await mediator.Send(new SyncUserCommand(auth0User));
|
||||||
|
|||||||
@@ -31,8 +31,4 @@
|
|||||||
</Content>
|
</Content>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<Folder Include="Controllers\Orders\" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -30,8 +30,8 @@ public class RequestTimingMiddleware(RequestDelegate next, ILogger<RequestTiming
|
|||||||
|
|
||||||
public static class RequestTimingMiddlewareExtensions
|
public static class RequestTimingMiddlewareExtensions
|
||||||
{
|
{
|
||||||
public static IApplicationBuilder UseRequestTiming(this IApplicationBuilder builder)
|
public static void UseRequestTiming(this IApplicationBuilder builder)
|
||||||
{
|
{
|
||||||
return builder.UseMiddleware<RequestTimingMiddleware>();
|
builder.UseMiddleware<RequestTimingMiddleware>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,13 +1,9 @@
|
|||||||
using Imprink.WebApi;
|
using Imprink.WebApi;
|
||||||
using Serilog;
|
using Serilog;
|
||||||
using Serilog.Events;
|
|
||||||
|
|
||||||
var builder = WebApplication.CreateBuilder(args);
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
|
|
||||||
Log.Logger = new LoggerConfiguration()
|
Log.Logger = new LoggerConfiguration().ReadFrom.Configuration(builder.Configuration).CreateLogger();
|
||||||
.ReadFrom.Configuration(builder.Configuration)
|
|
||||||
.CreateLogger();
|
|
||||||
|
|
||||||
builder.Host.UseSerilog();
|
builder.Host.UseSerilog();
|
||||||
|
|
||||||
Startup.ConfigureServices(builder);
|
Startup.ConfigureServices(builder);
|
||||||
|
|||||||
349
src/Imprink.WebApi/Seeder.cs
Normal file
349
src/Imprink.WebApi/Seeder.cs
Normal file
@@ -0,0 +1,349 @@
|
|||||||
|
using Imprink.Domain.Entities.Product;
|
||||||
|
using Imprink.Infrastructure.Database;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
namespace Imprink.WebApi;
|
||||||
|
|
||||||
|
public class Seeder(ApplicationDbContext context)
|
||||||
|
{
|
||||||
|
private readonly Random _random = new();
|
||||||
|
|
||||||
|
private readonly string[] _categoryImages =
|
||||||
|
[
|
||||||
|
"https://images.unsplash.com/photo-1441986300917-64674bd600d8?w=500",
|
||||||
|
"https://images.unsplash.com/photo-1560472354-b33ff0c44a43?w=500",
|
||||||
|
"https://images.unsplash.com/photo-1586953208448-b95a79798f07?w=500",
|
||||||
|
"https://images.unsplash.com/photo-1503602642458-232111445657?w=500"
|
||||||
|
];
|
||||||
|
|
||||||
|
private readonly string[] _textileImages =
|
||||||
|
[
|
||||||
|
"https://images.unsplash.com/photo-1521572163474-6864f9cf17ab?w=500",
|
||||||
|
"https://images.unsplash.com/photo-1583743814966-8936f37f4ad2?w=500",
|
||||||
|
"https://images.unsplash.com/photo-1571945153237-4929e783af4a?w=500",
|
||||||
|
"https://images.unsplash.com/photo-1618354691373-d851c5c3a990?w=500",
|
||||||
|
"https://images.unsplash.com/photo-1576566588028-4147f3842f27?w=500"
|
||||||
|
];
|
||||||
|
|
||||||
|
private readonly string[] _hardSurfaceImages =
|
||||||
|
[
|
||||||
|
"https://images.unsplash.com/photo-1586023492125-27b2c045efd7?w=500",
|
||||||
|
"https://images.unsplash.com/photo-1542291026-7eec264c27ff?w=500",
|
||||||
|
"https://images.unsplash.com/photo-1544966503-7cc5ac882d2e?w=500",
|
||||||
|
"https://images.unsplash.com/photo-1553062407-98eeb64c6a62?w=500"
|
||||||
|
];
|
||||||
|
|
||||||
|
private readonly string[] _paperImages =
|
||||||
|
[
|
||||||
|
"https://images.unsplash.com/photo-1586281010691-79ab3d0f2102?w=500",
|
||||||
|
"https://images.unsplash.com/photo-1594736797933-d0401ba2fe65?w=500",
|
||||||
|
"https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=500",
|
||||||
|
"https://images.unsplash.com/photo-1584464491033-06628f3a6b7b?w=500"
|
||||||
|
];
|
||||||
|
|
||||||
|
public async Task SeedAsync()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Console.WriteLine("Starting database seeding...");
|
||||||
|
|
||||||
|
var categories = await SeedCategories();
|
||||||
|
Console.WriteLine($"Created {categories.Count} categories");
|
||||||
|
|
||||||
|
var products = await SeedProducts(categories);
|
||||||
|
Console.WriteLine($"Created {products.Count} products");
|
||||||
|
|
||||||
|
await SeedProductVariants(products);
|
||||||
|
Console.WriteLine("Created product variants");
|
||||||
|
|
||||||
|
Console.WriteLine("Database seeding completed successfully!");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"Error during seeding: {ex.Message}");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<List<Category>> SeedCategories()
|
||||||
|
{
|
||||||
|
var categories = new List<Category>();
|
||||||
|
var now = DateTime.UtcNow;
|
||||||
|
|
||||||
|
var categoryData = new Dictionary<string, List<string>>
|
||||||
|
{
|
||||||
|
["Textile"] =
|
||||||
|
[
|
||||||
|
"T-Shirts", "Hoodies", "Tank Tops", "Long Sleeves", "Polo Shirts",
|
||||||
|
"Sweatshirts", "Jackets", "Caps & Hats", "Bags", "Towels",
|
||||||
|
"Aprons", "Baby Clothing", "Youth Clothing", "Women's Apparel", "Men's Apparel"
|
||||||
|
],
|
||||||
|
["Hard Surfaces"] =
|
||||||
|
[
|
||||||
|
"Mugs", "Water Bottles", "Phone Cases", "Laptop Cases", "Keychains",
|
||||||
|
"Mouse Pads", "Coasters", "Picture Frames", "Awards & Trophies", "Signs",
|
||||||
|
"Magnets", "Buttons & Pins", "Clocks", "Tiles", "Metal Prints"
|
||||||
|
],
|
||||||
|
["Paper"] =
|
||||||
|
[
|
||||||
|
"Business Cards", "Flyers", "Brochures", "Posters", "Banners",
|
||||||
|
"Stickers", "Labels", "Notebooks", "Calendars", "Greeting Cards",
|
||||||
|
"Postcards", "Bookmarks", "Menu Cards", "Invitations", "Certificates"
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
var existingMainCategories = await context.Set<Category>()
|
||||||
|
.Where(c => c.ParentCategoryId == null)
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
var mainCategoryMap = existingMainCategories.ToDictionary(c => c.Name, c => c);
|
||||||
|
|
||||||
|
foreach (var mainCategoryName in categoryData.Keys)
|
||||||
|
{
|
||||||
|
Category mainCategory;
|
||||||
|
if (mainCategoryMap.TryGetValue(mainCategoryName, out var value))
|
||||||
|
{
|
||||||
|
mainCategory = value;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mainCategory = new Category
|
||||||
|
{
|
||||||
|
Id = Guid.NewGuid(),
|
||||||
|
Name = mainCategoryName,
|
||||||
|
Description = $"{mainCategoryName} products and materials",
|
||||||
|
ImageUrl = _categoryImages[_random.Next(_categoryImages.Length)],
|
||||||
|
SortOrder = categories.Count + 1,
|
||||||
|
IsActive = true,
|
||||||
|
CreatedAt = now,
|
||||||
|
ModifiedAt = now,
|
||||||
|
CreatedBy = "seeder@system.com",
|
||||||
|
ModifiedBy = "seeder@system.com"
|
||||||
|
};
|
||||||
|
context.Set<Category>().Add(mainCategory);
|
||||||
|
await context.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
categories.Add(mainCategory);
|
||||||
|
|
||||||
|
var subcategoryNames = categoryData[mainCategoryName];
|
||||||
|
for (var i = 0; i < subcategoryNames.Count; i++)
|
||||||
|
{
|
||||||
|
var subcategory = new Category
|
||||||
|
{
|
||||||
|
Id = Guid.NewGuid(),
|
||||||
|
Name = subcategoryNames[i],
|
||||||
|
Description = $"High-quality {subcategoryNames[i].ToLower()} for custom printing",
|
||||||
|
ImageUrl = GetImageForCategory(mainCategoryName),
|
||||||
|
SortOrder = i + 1,
|
||||||
|
IsActive = true,
|
||||||
|
ParentCategoryId = mainCategory.Id,
|
||||||
|
CreatedAt = now,
|
||||||
|
ModifiedAt = now,
|
||||||
|
CreatedBy = "seeder@system.com",
|
||||||
|
ModifiedBy = "seeder@system.com"
|
||||||
|
};
|
||||||
|
|
||||||
|
categories.Add(subcategory);
|
||||||
|
context.Set<Category>().Add(subcategory);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await context.SaveChangesAsync();
|
||||||
|
return categories;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<List<Product>> SeedProducts(List<Category> categories)
|
||||||
|
{
|
||||||
|
var products = new List<Product>();
|
||||||
|
var now = DateTime.UtcNow;
|
||||||
|
|
||||||
|
var subcategories = categories.Where(c => c.ParentCategoryId.HasValue).ToList();
|
||||||
|
|
||||||
|
foreach (var category in subcategories)
|
||||||
|
{
|
||||||
|
var productCount = _random.Next(15, 35);
|
||||||
|
|
||||||
|
for (var i = 0; i < productCount; i++)
|
||||||
|
{
|
||||||
|
var product = new Product
|
||||||
|
{
|
||||||
|
Id = Guid.NewGuid(),
|
||||||
|
Name = GenerateProductName(category.Name, i + 1),
|
||||||
|
Description = GenerateProductDescription(category.Name),
|
||||||
|
BasePrice = GenerateBasePrice(category.Name),
|
||||||
|
IsCustomizable = _random.NextDouble() > 0.2,
|
||||||
|
IsActive = _random.NextDouble() > 0.05,
|
||||||
|
ImageUrl = GetImageForCategory(GetMainCategoryName(category)),
|
||||||
|
CategoryId = category.Id,
|
||||||
|
Category = category,
|
||||||
|
CreatedAt = now.AddDays(-_random.Next(0, 365)),
|
||||||
|
ModifiedAt = now.AddDays(-_random.Next(0, 30)),
|
||||||
|
CreatedBy = "seeder@system.com",
|
||||||
|
ModifiedBy = "seeder@system.com"
|
||||||
|
};
|
||||||
|
|
||||||
|
products.Add(product);
|
||||||
|
context.Set<Product>().Add(product);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await context.SaveChangesAsync();
|
||||||
|
return products;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task SeedProductVariants(List<Product> products)
|
||||||
|
{
|
||||||
|
var now = DateTime.UtcNow;
|
||||||
|
var skuCounter = 1;
|
||||||
|
|
||||||
|
foreach (var variant in from product in products let mainCategory = GetMainCategoryName(product.Category) select GenerateVariantsForProduct(product, mainCategory, ref skuCounter, now) into variants from variant in variants select variant)
|
||||||
|
{
|
||||||
|
context.Set<ProductVariant>().Add(variant);
|
||||||
|
}
|
||||||
|
|
||||||
|
await context.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<ProductVariant> GenerateVariantsForProduct(Product product, string mainCategory, ref int skuCounter, DateTime now)
|
||||||
|
{
|
||||||
|
var variants = new List<ProductVariant>();
|
||||||
|
|
||||||
|
var sizes = GetSizesForCategory(mainCategory);
|
||||||
|
var colors = GetColorsForCategory();
|
||||||
|
|
||||||
|
var variantCount = Math.Min(_random.Next(3, 9), sizes.Count * colors.Count);
|
||||||
|
var usedCombinations = new HashSet<string>();
|
||||||
|
|
||||||
|
for (var i = 0; i < variantCount; i++)
|
||||||
|
{
|
||||||
|
string size, color;
|
||||||
|
string combination;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
size = sizes[_random.Next(sizes.Count)];
|
||||||
|
color = colors[_random.Next(colors.Count)];
|
||||||
|
combination = $"{size}-{color}";
|
||||||
|
} while (usedCombinations.Contains(combination));
|
||||||
|
|
||||||
|
usedCombinations.Add(combination);
|
||||||
|
|
||||||
|
var variant = new ProductVariant
|
||||||
|
{
|
||||||
|
Id = Guid.NewGuid(),
|
||||||
|
ProductId = product.Id,
|
||||||
|
Product = product,
|
||||||
|
Size = size,
|
||||||
|
Color = color,
|
||||||
|
Price = product.BasePrice + (_random.Next(-500, 1500) / 100m),
|
||||||
|
ImageUrl = GetImageForCategory(mainCategory),
|
||||||
|
Sku = $"SKU{skuCounter:D6}",
|
||||||
|
StockQuantity = _random.Next(0, 500),
|
||||||
|
IsActive = _random.NextDouble() > 0.03,
|
||||||
|
CreatedAt = now.AddDays(-_random.Next(0, 300)),
|
||||||
|
ModifiedAt = now.AddDays(-_random.Next(0, 30)),
|
||||||
|
CreatedBy = "seeder@system.com",
|
||||||
|
ModifiedBy = "seeder@system.com"
|
||||||
|
};
|
||||||
|
|
||||||
|
variants.Add(variant);
|
||||||
|
skuCounter++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return variants;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GenerateProductName(string categoryName, int index)
|
||||||
|
{
|
||||||
|
var adjectives = new[] { "Premium", "Classic", "Modern", "Vintage", "Professional", "Casual", "Deluxe", "Standard", "Economy", "Luxury" };
|
||||||
|
var materials = new Dictionary<string, string[]>
|
||||||
|
{
|
||||||
|
["T-Shirts"] = ["Cotton", "Blend", "Organic", "Bamboo", "Performance"],
|
||||||
|
["Mugs"] = ["Ceramic", "Stainless", "Glass", "Enamel", "Porcelain"],
|
||||||
|
["Business Cards"] = ["Matte", "Glossy", "Textured", "Recycled", "Premium"]
|
||||||
|
};
|
||||||
|
|
||||||
|
var adjective = adjectives[_random.Next(adjectives.Length)];
|
||||||
|
var material = materials.TryGetValue(categoryName, out var value) ? value[_random.Next(value.Length)] :
|
||||||
|
"Quality";
|
||||||
|
|
||||||
|
return $"{adjective} {material} {categoryName.TrimEnd('s')} #{index:D3}";
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GenerateProductDescription(string categoryName)
|
||||||
|
{
|
||||||
|
var descriptions = new[]
|
||||||
|
{
|
||||||
|
$"High-quality {categoryName.ToLower()} perfect for custom printing and personalization.",
|
||||||
|
$"Professional-grade {categoryName.ToLower()} designed for durability and print quality.",
|
||||||
|
$"Premium {categoryName.ToLower()} suitable for both small and large print runs.",
|
||||||
|
$"Versatile {categoryName.ToLower()} ideal for promotional materials and custom designs.",
|
||||||
|
$"Top-tier {categoryName.ToLower()} offering excellent print adhesion and longevity."
|
||||||
|
};
|
||||||
|
|
||||||
|
return descriptions[_random.Next(descriptions.Length)];
|
||||||
|
}
|
||||||
|
|
||||||
|
private decimal GenerateBasePrice(string categoryName)
|
||||||
|
{
|
||||||
|
var priceRanges = new Dictionary<string, (decimal min, decimal max)>
|
||||||
|
{
|
||||||
|
["T-Shirts"] = (8.99m, 24.99m),
|
||||||
|
["Hoodies"] = (19.99m, 49.99m),
|
||||||
|
["Mugs"] = (4.99m, 15.99m),
|
||||||
|
["Business Cards"] = (9.99m, 39.99m),
|
||||||
|
["Phone Cases"] = (12.99m, 29.99m)
|
||||||
|
};
|
||||||
|
|
||||||
|
var (min, max) = priceRanges.TryGetValue(categoryName, value: out var range) ?
|
||||||
|
range : (5.99m, 29.99m);
|
||||||
|
|
||||||
|
return Math.Round(min + (max - min) * (decimal)_random.NextDouble(), 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetImageForCategory(string mainCategory)
|
||||||
|
{
|
||||||
|
return mainCategory switch
|
||||||
|
{
|
||||||
|
"Textile" => _textileImages[_random.Next(_textileImages.Length)],
|
||||||
|
"Hard Surfaces" => _hardSurfaceImages[_random.Next(_hardSurfaceImages.Length)],
|
||||||
|
"Paper" => _paperImages[_random.Next(_paperImages.Length)],
|
||||||
|
_ => _categoryImages[_random.Next(_categoryImages.Length)]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetMainCategoryName(Category category)
|
||||||
|
{
|
||||||
|
if (category.ParentCategoryId == null)
|
||||||
|
return category.Name;
|
||||||
|
|
||||||
|
var textileCategories = new[] { "T-Shirts", "Hoodies", "Tank Tops", "Long Sleeves", "Polo Shirts", "Sweatshirts", "Jackets", "Caps & Hats", "Bags", "Towels", "Aprons", "Baby Clothing", "Youth Clothing", "Women's Apparel", "Men's Apparel" };
|
||||||
|
var hardSurfaceCategories = new[] { "Mugs", "Water Bottles", "Phone Cases", "Laptop Cases", "Keychains", "Mouse Pads", "Coasters", "Picture Frames", "Awards & Trophies", "Signs", "Magnets", "Buttons & Pins", "Clocks", "Tiles", "Metal Prints" };
|
||||||
|
var paperCategories = new[] { "Business Cards", "Flyers", "Brochures", "Posters", "Banners", "Stickers", "Labels", "Notebooks", "Calendars", "Greeting Cards", "Postcards", "Bookmarks", "Menu Cards", "Invitations", "Certificates" };
|
||||||
|
|
||||||
|
if (textileCategories.Contains(category.Name)) return "Textile";
|
||||||
|
if (hardSurfaceCategories.Contains(category.Name)) return "Hard Surfaces";
|
||||||
|
return paperCategories.Contains(category.Name) ? "Paper" : "Textile";
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<string> GetSizesForCategory(string mainCategory)
|
||||||
|
{
|
||||||
|
return mainCategory switch
|
||||||
|
{
|
||||||
|
"Textile" => ["XS", "S", "M", "L", "XL", "XXL", "XXXL"],
|
||||||
|
"Hard Surfaces" => ["Small", "Medium", "Large", "XL", "Standard"],
|
||||||
|
"Paper" => ["A4", "A5", "Letter", "Legal", "Custom", "Standard"],
|
||||||
|
_ => ["S", "M", "L", "XL"]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<string> GetColorsForCategory()
|
||||||
|
{
|
||||||
|
return
|
||||||
|
[
|
||||||
|
"White", "Black", "Red", "Blue", "Green", "Yellow", "Purple", "Orange",
|
||||||
|
"Pink", "Gray", "Navy", "Maroon", "Forest", "Royal", "Sky", "Lime"
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -25,6 +25,8 @@ public static class Startup
|
|||||||
services.AddScoped<IUserRoleRepository, UserRoleRepository>();
|
services.AddScoped<IUserRoleRepository, UserRoleRepository>();
|
||||||
services.AddScoped<IUnitOfWork, UnitOfWork>();
|
services.AddScoped<IUnitOfWork, UnitOfWork>();
|
||||||
|
|
||||||
|
services.AddScoped<Seeder>();
|
||||||
|
|
||||||
services.AddDbContext<ApplicationDbContext>(options =>
|
services.AddDbContext<ApplicationDbContext>(options =>
|
||||||
options.UseSqlServer(
|
options.UseSqlServer(
|
||||||
builder.Configuration.GetConnectionString("DefaultConnection"),
|
builder.Configuration.GetConnectionString("DefaultConnection"),
|
||||||
@@ -61,13 +63,14 @@ public static class Startup
|
|||||||
if (string.IsNullOrEmpty(userId)) return Task.CompletedTask;
|
if (string.IsNullOrEmpty(userId)) return Task.CompletedTask;
|
||||||
var identity = context.Principal!.Identity as ClaimsIdentity;
|
var identity = context.Principal!.Identity as ClaimsIdentity;
|
||||||
|
|
||||||
var roles = (from ur in dbContext?.UserRole
|
var roles = (
|
||||||
|
from ur in dbContext?.UserRole
|
||||||
join r in dbContext?.Roles on ur.RoleId equals r.Id
|
join r in dbContext?.Roles on ur.RoleId equals r.Id
|
||||||
where ur.UserId == userId
|
where ur.UserId == userId
|
||||||
select r.RoleName).ToList();
|
select r.RoleName).ToList();
|
||||||
|
|
||||||
foreach (var role in roles) identity!.AddClaim(new Claim(ClaimTypes.Role, role));
|
foreach (var role in roles) identity!.AddClaim(new Claim(ClaimTypes.Role, role));
|
||||||
|
identity!.AddClaim(new Claim(ClaimTypes.Role, "User"));
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user