diff --git a/src/Shared/Authorization/FshPermissions.cs b/src/Shared/Authorization/FshPermissions.cs index 01872af96..e18c1b500 100644 --- a/src/Shared/Authorization/FshPermissions.cs +++ b/src/Shared/Authorization/FshPermissions.cs @@ -36,6 +36,14 @@ public static class FshPermissions new("Delete Products", FshActions.Delete, FshResources.Products), new("Export Products", FshActions.Export, FshResources.Products), + //brands + new("View Brands", FshActions.View, FshResources.Brands, IsBasic: true), + new("Search Brands", FshActions.Search, FshResources.Brands, IsBasic: true), + new("Create Brands", FshActions.Create, FshResources.Brands), + new("Update Brands", FshActions.Update, FshResources.Brands), + new("Delete Brands", FshActions.Delete, FshResources.Brands), + new("Export Brands", FshActions.Export, FshResources.Brands), + //todos new("View Todos", FshActions.View, FshResources.Todos, IsBasic: true), new("Search Todos", FshActions.Search, FshResources.Todos, IsBasic: true), diff --git a/src/api/migrations/PostgreSQL/Catalog/20240601095057_Add Catalog Schema.cs b/src/api/migrations/PostgreSQL/Catalog/20240601095057_Add Catalog Schema.cs deleted file mode 100644 index c95ee16aa..000000000 --- a/src/api/migrations/PostgreSQL/Catalog/20240601095057_Add Catalog Schema.cs +++ /dev/null @@ -1,45 +0,0 @@ -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace FSH.Starter.WebApi.Migrations.PostgreSQL.Catalog -{ - /// - public partial class AddCatalogSchema : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.EnsureSchema( - name: "catalog"); - - migrationBuilder.CreateTable( - name: "Products", - schema: "catalog", - columns: table => new - { - Id = table.Column(type: "uuid", nullable: false), - Name = table.Column(type: "character varying(100)", maxLength: 100, nullable: false), - Description = table.Column(type: "character varying(1000)", maxLength: 1000, nullable: true), - Price = table.Column(type: "numeric", nullable: false), - TenantId = table.Column(type: "character varying(64)", maxLength: 64, nullable: false), - Created = table.Column(type: "timestamp with time zone", nullable: false), - CreatedBy = table.Column(type: "uuid", nullable: false), - LastModified = table.Column(type: "timestamp with time zone", nullable: false), - LastModifiedBy = table.Column(type: "uuid", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_Products", x => x.Id); - }); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropTable( - name: "Products", - schema: "catalog"); - } - } -} diff --git a/src/api/migrations/PostgreSQL/Catalog/20240601095057_Add Catalog Schema.Designer.cs b/src/api/migrations/PostgreSQL/Catalog/20241116102306_Add Catalog Schema.Designer.cs similarity index 55% rename from src/api/migrations/PostgreSQL/Catalog/20240601095057_Add Catalog Schema.Designer.cs rename to src/api/migrations/PostgreSQL/Catalog/20241116102306_Add Catalog Schema.Designer.cs index 994aa4477..e20c0bba2 100644 --- a/src/api/migrations/PostgreSQL/Catalog/20240601095057_Add Catalog Schema.Designer.cs +++ b/src/api/migrations/PostgreSQL/Catalog/20241116102306_Add Catalog Schema.Designer.cs @@ -12,7 +12,7 @@ namespace FSH.Starter.WebApi.Migrations.PostgreSQL.Catalog { [DbContext(typeof(CatalogDbContext))] - [Migration("20240601095057_Add Catalog Schema")] + [Migration("20241116102306_Add Catalog Schema")] partial class AddCatalogSchema { /// @@ -21,17 +21,59 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) #pragma warning disable 612, 618 modelBuilder .HasDefaultSchema("catalog") - .HasAnnotation("ProductVersion", "8.0.6") + .HasAnnotation("ProductVersion", "8.0.8") .HasAnnotation("Relational:MaxIdentifierLength", 63); NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + modelBuilder.Entity("FSH.Starter.WebApi.Catalog.Domain.Brand", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Created") + .HasColumnType("timestamp with time zone"); + + b.Property("CreatedBy") + .HasColumnType("uuid"); + + b.Property("Description") + .HasMaxLength(1000) + .HasColumnType("character varying(1000)"); + + b.Property("LastModified") + .HasColumnType("timestamp with time zone"); + + b.Property("LastModifiedBy") + .HasColumnType("uuid"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("TenantId") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.HasKey("Id"); + + b.ToTable("Brands", "catalog"); + + b.HasAnnotation("Finbuckle:MultiTenant", true); + }); + modelBuilder.Entity("FSH.Starter.WebApi.Catalog.Domain.Product", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("uuid"); + b.Property("BrandId") + .HasColumnType("uuid"); + b.Property("Created") .HasColumnType("timestamp with time zone"); @@ -63,10 +105,21 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.HasKey("Id"); + b.HasIndex("BrandId"); + b.ToTable("Products", "catalog"); b.HasAnnotation("Finbuckle:MultiTenant", true); }); + + modelBuilder.Entity("FSH.Starter.WebApi.Catalog.Domain.Product", b => + { + b.HasOne("FSH.Starter.WebApi.Catalog.Domain.Brand", "Brand") + .WithMany() + .HasForeignKey("BrandId"); + + b.Navigation("Brand"); + }); #pragma warning restore 612, 618 } } diff --git a/src/api/migrations/PostgreSQL/Catalog/20241116102306_Add Catalog Schema.cs b/src/api/migrations/PostgreSQL/Catalog/20241116102306_Add Catalog Schema.cs new file mode 100644 index 000000000..17b995411 --- /dev/null +++ b/src/api/migrations/PostgreSQL/Catalog/20241116102306_Add Catalog Schema.cs @@ -0,0 +1,82 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace FSH.Starter.WebApi.Migrations.PostgreSQL.Catalog +{ + /// + public partial class AddCatalogSchema : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.EnsureSchema( + name: "catalog"); + + migrationBuilder.CreateTable( + name: "Brands", + schema: "catalog", + columns: table => new + { + Id = table.Column(type: "uuid", nullable: false), + Name = table.Column(type: "character varying(100)", maxLength: 100, nullable: false), + Description = table.Column(type: "character varying(1000)", maxLength: 1000, nullable: true), + TenantId = table.Column(type: "character varying(64)", maxLength: 64, nullable: false), + Created = table.Column(type: "timestamp with time zone", nullable: false), + CreatedBy = table.Column(type: "uuid", nullable: false), + LastModified = table.Column(type: "timestamp with time zone", nullable: false), + LastModifiedBy = table.Column(type: "uuid", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Brands", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "Products", + schema: "catalog", + columns: table => new + { + Id = table.Column(type: "uuid", nullable: false), + Name = table.Column(type: "character varying(100)", maxLength: 100, nullable: false), + Description = table.Column(type: "character varying(1000)", maxLength: 1000, nullable: true), + Price = table.Column(type: "numeric", nullable: false), + BrandId = table.Column(type: "uuid", nullable: true), + TenantId = table.Column(type: "character varying(64)", maxLength: 64, nullable: false), + Created = table.Column(type: "timestamp with time zone", nullable: false), + CreatedBy = table.Column(type: "uuid", nullable: false), + LastModified = table.Column(type: "timestamp with time zone", nullable: false), + LastModifiedBy = table.Column(type: "uuid", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Products", x => x.Id); + table.ForeignKey( + name: "FK_Products_Brands_BrandId", + column: x => x.BrandId, + principalSchema: "catalog", + principalTable: "Brands", + principalColumn: "Id"); + }); + + migrationBuilder.CreateIndex( + name: "IX_Products_BrandId", + schema: "catalog", + table: "Products", + column: "BrandId"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "Products", + schema: "catalog"); + + migrationBuilder.DropTable( + name: "Brands", + schema: "catalog"); + } + } +} diff --git a/src/api/migrations/PostgreSQL/Catalog/CatalogDbContextModelSnapshot.cs b/src/api/migrations/PostgreSQL/Catalog/CatalogDbContextModelSnapshot.cs index 9a90e2270..615efd23b 100644 --- a/src/api/migrations/PostgreSQL/Catalog/CatalogDbContextModelSnapshot.cs +++ b/src/api/migrations/PostgreSQL/Catalog/CatalogDbContextModelSnapshot.cs @@ -18,17 +18,59 @@ protected override void BuildModel(ModelBuilder modelBuilder) #pragma warning disable 612, 618 modelBuilder .HasDefaultSchema("catalog") - .HasAnnotation("ProductVersion", "8.0.6") + .HasAnnotation("ProductVersion", "8.0.8") .HasAnnotation("Relational:MaxIdentifierLength", 63); NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + modelBuilder.Entity("FSH.Starter.WebApi.Catalog.Domain.Brand", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Created") + .HasColumnType("timestamp with time zone"); + + b.Property("CreatedBy") + .HasColumnType("uuid"); + + b.Property("Description") + .HasMaxLength(1000) + .HasColumnType("character varying(1000)"); + + b.Property("LastModified") + .HasColumnType("timestamp with time zone"); + + b.Property("LastModifiedBy") + .HasColumnType("uuid"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("TenantId") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.HasKey("Id"); + + b.ToTable("Brands", "catalog"); + + b.HasAnnotation("Finbuckle:MultiTenant", true); + }); + modelBuilder.Entity("FSH.Starter.WebApi.Catalog.Domain.Product", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("uuid"); + b.Property("BrandId") + .HasColumnType("uuid"); + b.Property("Created") .HasColumnType("timestamp with time zone"); @@ -60,10 +102,21 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasKey("Id"); + b.HasIndex("BrandId"); + b.ToTable("Products", "catalog"); b.HasAnnotation("Finbuckle:MultiTenant", true); }); + + modelBuilder.Entity("FSH.Starter.WebApi.Catalog.Domain.Product", b => + { + b.HasOne("FSH.Starter.WebApi.Catalog.Domain.Brand", "Brand") + .WithMany() + .HasForeignKey("BrandId"); + + b.Navigation("Brand"); + }); #pragma warning restore 612, 618 } } diff --git a/src/api/modules/Catalog/Catalog.Application/Brands/Create/v1/CreateBrandCommand.cs b/src/api/modules/Catalog/Catalog.Application/Brands/Create/v1/CreateBrandCommand.cs new file mode 100644 index 000000000..0c2559f9a --- /dev/null +++ b/src/api/modules/Catalog/Catalog.Application/Brands/Create/v1/CreateBrandCommand.cs @@ -0,0 +1,8 @@ +using System.ComponentModel; +using MediatR; + +namespace FSH.Starter.WebApi.Catalog.Application.Brands.Create.v1; +public sealed record CreateBrandCommand( + [property: DefaultValue("Sample Brand")] string? Name, + [property: DefaultValue("Descriptive Description")] string? Description = null) : IRequest; + diff --git a/src/api/modules/Catalog/Catalog.Application/Brands/Create/v1/CreateBrandCommandValidator.cs b/src/api/modules/Catalog/Catalog.Application/Brands/Create/v1/CreateBrandCommandValidator.cs new file mode 100644 index 000000000..0d2e69533 --- /dev/null +++ b/src/api/modules/Catalog/Catalog.Application/Brands/Create/v1/CreateBrandCommandValidator.cs @@ -0,0 +1,11 @@ +using FluentValidation; + +namespace FSH.Starter.WebApi.Catalog.Application.Brands.Create.v1; +public class CreateBrandCommandValidator : AbstractValidator +{ + public CreateBrandCommandValidator() + { + RuleFor(b => b.Name).NotEmpty().MinimumLength(2).MaximumLength(100); + RuleFor(b => b.Description).MaximumLength(1000); + } +} diff --git a/src/api/modules/Catalog/Catalog.Application/Brands/Create/v1/CreateBrandHandler.cs b/src/api/modules/Catalog/Catalog.Application/Brands/Create/v1/CreateBrandHandler.cs new file mode 100644 index 000000000..15b4b7633 --- /dev/null +++ b/src/api/modules/Catalog/Catalog.Application/Brands/Create/v1/CreateBrandHandler.cs @@ -0,0 +1,21 @@ +using FSH.Framework.Core.Persistence; +using FSH.Starter.WebApi.Catalog.Domain; +using MediatR; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; + +namespace FSH.Starter.WebApi.Catalog.Application.Brands.Create.v1; +public sealed class CreateBrandHandler( + ILogger logger, + [FromKeyedServices("catalog:brands")] IRepository repository) + : IRequestHandler +{ + public async Task Handle(CreateBrandCommand request, CancellationToken cancellationToken) + { + ArgumentNullException.ThrowIfNull(request); + var brand = Brand.Create(request.Name!, request.Description); + await repository.AddAsync(brand, cancellationToken); + logger.LogInformation("brand created {BrandId}", brand.Id); + return new CreateBrandResponse(brand.Id); + } +} diff --git a/src/api/modules/Catalog/Catalog.Application/Brands/Create/v1/CreateBrandResponse.cs b/src/api/modules/Catalog/Catalog.Application/Brands/Create/v1/CreateBrandResponse.cs new file mode 100644 index 000000000..11e63834b --- /dev/null +++ b/src/api/modules/Catalog/Catalog.Application/Brands/Create/v1/CreateBrandResponse.cs @@ -0,0 +1,4 @@ +namespace FSH.Starter.WebApi.Catalog.Application.Brands.Create.v1; + +public sealed record CreateBrandResponse(Guid? Id); + diff --git a/src/api/modules/Catalog/Catalog.Application/Brands/Delete/v1/DeleteBrandCommand.cs b/src/api/modules/Catalog/Catalog.Application/Brands/Delete/v1/DeleteBrandCommand.cs new file mode 100644 index 000000000..0e11b2414 --- /dev/null +++ b/src/api/modules/Catalog/Catalog.Application/Brands/Delete/v1/DeleteBrandCommand.cs @@ -0,0 +1,5 @@ +using MediatR; + +namespace FSH.Starter.WebApi.Catalog.Application.Brands.Delete.v1; +public sealed record DeleteBrandCommand( + Guid Id) : IRequest; diff --git a/src/api/modules/Catalog/Catalog.Application/Brands/Delete/v1/DeleteBrandHandler.cs b/src/api/modules/Catalog/Catalog.Application/Brands/Delete/v1/DeleteBrandHandler.cs new file mode 100644 index 000000000..d4afe86ef --- /dev/null +++ b/src/api/modules/Catalog/Catalog.Application/Brands/Delete/v1/DeleteBrandHandler.cs @@ -0,0 +1,22 @@ +using FSH.Framework.Core.Persistence; +using FSH.Starter.WebApi.Catalog.Domain; +using FSH.Starter.WebApi.Catalog.Domain.Exceptions; +using MediatR; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; + +namespace FSH.Starter.WebApi.Catalog.Application.Brands.Delete.v1; +public sealed class DeleteBrandHandler( + ILogger logger, + [FromKeyedServices("catalog:brands")] IRepository repository) + : IRequestHandler +{ + public async Task Handle(DeleteBrandCommand request, CancellationToken cancellationToken) + { + ArgumentNullException.ThrowIfNull(request); + var brand = await repository.GetByIdAsync(request.Id, cancellationToken); + _ = brand ?? throw new BrandNotFoundException(request.Id); + await repository.DeleteAsync(brand, cancellationToken); + logger.LogInformation("Brand with id : {BrandId} deleted", brand.Id); + } +} diff --git a/src/api/modules/Catalog/Catalog.Application/Brands/EventHandlers/BrandCreatedEventHandler.cs b/src/api/modules/Catalog/Catalog.Application/Brands/EventHandlers/BrandCreatedEventHandler.cs new file mode 100644 index 000000000..777526b76 --- /dev/null +++ b/src/api/modules/Catalog/Catalog.Application/Brands/EventHandlers/BrandCreatedEventHandler.cs @@ -0,0 +1,16 @@ +using FSH.Starter.WebApi.Catalog.Domain.Events; +using MediatR; +using Microsoft.Extensions.Logging; + +namespace FSH.Starter.WebApi.Catalog.Application.Brands.EventHandlers; + +public class BrandCreatedEventHandler(ILogger logger) : INotificationHandler +{ + public async Task Handle(BrandCreated notification, + CancellationToken cancellationToken) + { + logger.LogInformation("handling brand created domain event.."); + await Task.FromResult(notification); + logger.LogInformation("finished handling brand created domain event.."); + } +} diff --git a/src/api/modules/Catalog/Catalog.Application/Brands/Get/v1/BrandResponse.cs b/src/api/modules/Catalog/Catalog.Application/Brands/Get/v1/BrandResponse.cs new file mode 100644 index 000000000..726030b24 --- /dev/null +++ b/src/api/modules/Catalog/Catalog.Application/Brands/Get/v1/BrandResponse.cs @@ -0,0 +1,2 @@ +namespace FSH.Starter.WebApi.Catalog.Application.Brands.Get.v1; +public sealed record BrandResponse(Guid? Id, string Name, string? Description); diff --git a/src/api/modules/Catalog/Catalog.Application/Brands/Get/v1/GetBrandHandler.cs b/src/api/modules/Catalog/Catalog.Application/Brands/Get/v1/GetBrandHandler.cs new file mode 100644 index 000000000..7848a10d6 --- /dev/null +++ b/src/api/modules/Catalog/Catalog.Application/Brands/Get/v1/GetBrandHandler.cs @@ -0,0 +1,28 @@ +using Microsoft.Extensions.DependencyInjection; +using FSH.Starter.WebApi.Catalog.Domain.Exceptions; +using FSH.Framework.Core.Persistence; +using FSH.Framework.Core.Caching; +using FSH.Starter.WebApi.Catalog.Domain; +using MediatR; + +namespace FSH.Starter.WebApi.Catalog.Application.Brands.Get.v1; +public sealed class GetBrandHandler( + [FromKeyedServices("catalog:brands")] IReadRepository repository, + ICacheService cache) + : IRequestHandler +{ + public async Task Handle(GetBrandRequest request, CancellationToken cancellationToken) + { + ArgumentNullException.ThrowIfNull(request); + var item = await cache.GetOrSetAsync( + $"brand:{request.Id}", + async () => + { + var brandItem = await repository.GetByIdAsync(request.Id, cancellationToken); + if (brandItem == null) throw new BrandNotFoundException(request.Id); + return new BrandResponse(brandItem.Id, brandItem.Name, brandItem.Description); + }, + cancellationToken: cancellationToken); + return item!; + } +} diff --git a/src/api/modules/Catalog/Catalog.Application/Brands/Get/v1/GetBrandRequest.cs b/src/api/modules/Catalog/Catalog.Application/Brands/Get/v1/GetBrandRequest.cs new file mode 100644 index 000000000..a9354be5a --- /dev/null +++ b/src/api/modules/Catalog/Catalog.Application/Brands/Get/v1/GetBrandRequest.cs @@ -0,0 +1,8 @@ +using MediatR; + +namespace FSH.Starter.WebApi.Catalog.Application.Brands.Get.v1; +public class GetBrandRequest : IRequest +{ + public Guid Id { get; set; } + public GetBrandRequest(Guid id) => Id = id; +} diff --git a/src/api/modules/Catalog/Catalog.Application/Brands/Search/v1/SearchBrandSpecs.cs b/src/api/modules/Catalog/Catalog.Application/Brands/Search/v1/SearchBrandSpecs.cs new file mode 100644 index 000000000..b18cadc7f --- /dev/null +++ b/src/api/modules/Catalog/Catalog.Application/Brands/Search/v1/SearchBrandSpecs.cs @@ -0,0 +1,15 @@ +using Ardalis.Specification; +using FSH.Framework.Core.Paging; +using FSH.Framework.Core.Specifications; +using FSH.Starter.WebApi.Catalog.Application.Brands.Get.v1; +using FSH.Starter.WebApi.Catalog.Domain; + +namespace FSH.Starter.WebApi.Catalog.Application.Brands.Search.v1; +public class SearchBrandSpecs : EntitiesByPaginationFilterSpec +{ + public SearchBrandSpecs(SearchBrandsCommand command) + : base(command) => + Query + .OrderBy(c => c.Name, !command.HasOrderBy()) + .Where(b => b.Name.Contains(command.Keyword), !string.IsNullOrEmpty(command.Keyword)); +} diff --git a/src/api/modules/Catalog/Catalog.Application/Brands/Search/v1/SearchBrandsCommand.cs b/src/api/modules/Catalog/Catalog.Application/Brands/Search/v1/SearchBrandsCommand.cs new file mode 100644 index 000000000..70f4b3e0a --- /dev/null +++ b/src/api/modules/Catalog/Catalog.Application/Brands/Search/v1/SearchBrandsCommand.cs @@ -0,0 +1,11 @@ +using FSH.Framework.Core.Paging; +using FSH.Starter.WebApi.Catalog.Application.Brands.Get.v1; +using MediatR; + +namespace FSH.Starter.WebApi.Catalog.Application.Brands.Search.v1; + +public class SearchBrandsCommand : PaginationFilter, IRequest> +{ + public string? Name { get; set; } + public string? Description { get; set; } +} diff --git a/src/api/modules/Catalog/Catalog.Application/Brands/Search/v1/SearchBrandsHandler.cs b/src/api/modules/Catalog/Catalog.Application/Brands/Search/v1/SearchBrandsHandler.cs new file mode 100644 index 000000000..29b7107f4 --- /dev/null +++ b/src/api/modules/Catalog/Catalog.Application/Brands/Search/v1/SearchBrandsHandler.cs @@ -0,0 +1,24 @@ +using FSH.Framework.Core.Paging; +using FSH.Framework.Core.Persistence; +using FSH.Starter.WebApi.Catalog.Application.Brands.Get.v1; +using FSH.Starter.WebApi.Catalog.Domain; +using MediatR; +using Microsoft.Extensions.DependencyInjection; + +namespace FSH.Starter.WebApi.Catalog.Application.Brands.Search.v1; +public sealed class SearchBrandsHandler( + [FromKeyedServices("catalog:brands")] IReadRepository repository) + : IRequestHandler> +{ + public async Task> Handle(SearchBrandsCommand request, CancellationToken cancellationToken) + { + ArgumentNullException.ThrowIfNull(request); + + var spec = new SearchBrandSpecs(request); + + var items = await repository.ListAsync(spec, cancellationToken).ConfigureAwait(false); + var totalCount = await repository.CountAsync(spec, cancellationToken).ConfigureAwait(false); + + return new PagedList(items, request!.PageNumber, request!.PageSize, totalCount); + } +} diff --git a/src/api/modules/Catalog/Catalog.Application/Brands/Update/v1/UpdateBrandCommand.cs b/src/api/modules/Catalog/Catalog.Application/Brands/Update/v1/UpdateBrandCommand.cs new file mode 100644 index 000000000..ce7dd54cf --- /dev/null +++ b/src/api/modules/Catalog/Catalog.Application/Brands/Update/v1/UpdateBrandCommand.cs @@ -0,0 +1,7 @@ +using MediatR; + +namespace FSH.Starter.WebApi.Catalog.Application.Brands.Update.v1; +public sealed record UpdateBrandCommand( + Guid Id, + string? Name, + string? Description = null) : IRequest; diff --git a/src/api/modules/Catalog/Catalog.Application/Brands/Update/v1/UpdateBrandCommandValidator.cs b/src/api/modules/Catalog/Catalog.Application/Brands/Update/v1/UpdateBrandCommandValidator.cs new file mode 100644 index 000000000..a3ce8da6c --- /dev/null +++ b/src/api/modules/Catalog/Catalog.Application/Brands/Update/v1/UpdateBrandCommandValidator.cs @@ -0,0 +1,11 @@ +using FluentValidation; + +namespace FSH.Starter.WebApi.Catalog.Application.Brands.Update.v1; +public class UpdateBrandCommandValidator : AbstractValidator +{ + public UpdateBrandCommandValidator() + { + RuleFor(b => b.Name).NotEmpty().MinimumLength(2).MaximumLength(100); + RuleFor(b => b.Description).MaximumLength(1000); + } +} diff --git a/src/api/modules/Catalog/Catalog.Application/Brands/Update/v1/UpdateBrandHandler.cs b/src/api/modules/Catalog/Catalog.Application/Brands/Update/v1/UpdateBrandHandler.cs new file mode 100644 index 000000000..2477fdb4a --- /dev/null +++ b/src/api/modules/Catalog/Catalog.Application/Brands/Update/v1/UpdateBrandHandler.cs @@ -0,0 +1,24 @@ +using FSH.Framework.Core.Persistence; +using FSH.Starter.WebApi.Catalog.Domain; +using FSH.Starter.WebApi.Catalog.Domain.Exceptions; +using MediatR; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; + +namespace FSH.Starter.WebApi.Catalog.Application.Brands.Update.v1; +public sealed class UpdateBrandHandler( + ILogger logger, + [FromKeyedServices("catalog:brands")] IRepository repository) + : IRequestHandler +{ + public async Task Handle(UpdateBrandCommand request, CancellationToken cancellationToken) + { + ArgumentNullException.ThrowIfNull(request); + var brand = await repository.GetByIdAsync(request.Id, cancellationToken); + _ = brand ?? throw new BrandNotFoundException(request.Id); + var updatedBrand = brand.Update(request.Name, request.Description); + await repository.UpdateAsync(updatedBrand, cancellationToken); + logger.LogInformation("Brand with id : {BrandId} updated.", brand.Id); + return new UpdateBrandResponse(brand.Id); + } +} diff --git a/src/api/modules/Catalog/Catalog.Application/Brands/Update/v1/UpdateBrandResponse.cs b/src/api/modules/Catalog/Catalog.Application/Brands/Update/v1/UpdateBrandResponse.cs new file mode 100644 index 000000000..6b4acdc87 --- /dev/null +++ b/src/api/modules/Catalog/Catalog.Application/Brands/Update/v1/UpdateBrandResponse.cs @@ -0,0 +1,2 @@ +namespace FSH.Starter.WebApi.Catalog.Application.Brands.Update.v1; +public sealed record UpdateBrandResponse(Guid? Id); diff --git a/src/api/modules/Catalog/Catalog.Application/Products/Create/v1/CreateProductCommand.cs b/src/api/modules/Catalog/Catalog.Application/Products/Create/v1/CreateProductCommand.cs index 94a69924c..99291ae8e 100644 --- a/src/api/modules/Catalog/Catalog.Application/Products/Create/v1/CreateProductCommand.cs +++ b/src/api/modules/Catalog/Catalog.Application/Products/Create/v1/CreateProductCommand.cs @@ -5,4 +5,5 @@ namespace FSH.Starter.WebApi.Catalog.Application.Products.Create.v1; public sealed record CreateProductCommand( [property: DefaultValue("Sample Product")] string? Name, [property: DefaultValue(10)] decimal Price, - [property: DefaultValue("Descriptive Description")] string? Description = null) : IRequest; + [property: DefaultValue("Descriptive Description")] string? Description = null, + [property: DefaultValue(null)] Guid? BrandId = null) : IRequest; diff --git a/src/api/modules/Catalog/Catalog.Application/Products/Create/v1/CreateProductHandler.cs b/src/api/modules/Catalog/Catalog.Application/Products/Create/v1/CreateProductHandler.cs index 7f02a1951..cb640ac64 100644 --- a/src/api/modules/Catalog/Catalog.Application/Products/Create/v1/CreateProductHandler.cs +++ b/src/api/modules/Catalog/Catalog.Application/Products/Create/v1/CreateProductHandler.cs @@ -13,7 +13,7 @@ public sealed class CreateProductHandler( public async Task Handle(CreateProductCommand request, CancellationToken cancellationToken) { ArgumentNullException.ThrowIfNull(request); - var product = Product.Create(request.Name!, request.Description, request.Price); + var product = Product.Create(request.Name!, request.Description, request.Price, request.BrandId); await repository.AddAsync(product, cancellationToken); logger.LogInformation("product created {ProductId}", product.Id); return new CreateProductResponse(product.Id); diff --git a/src/api/modules/Catalog/Catalog.Application/Products/Get/v1/GetProductHandler.cs b/src/api/modules/Catalog/Catalog.Application/Products/Get/v1/GetProductHandler.cs index 8aea28540..53f327e26 100644 --- a/src/api/modules/Catalog/Catalog.Application/Products/Get/v1/GetProductHandler.cs +++ b/src/api/modules/Catalog/Catalog.Application/Products/Get/v1/GetProductHandler.cs @@ -18,9 +18,10 @@ public async Task Handle(GetProductRequest request, Cancellatio $"product:{request.Id}", async () => { - var productItem = await repository.GetByIdAsync(request.Id, cancellationToken); + var spec = new GetProductSpecs(request.Id); + var productItem = await repository.FirstOrDefaultAsync(spec, cancellationToken); if (productItem == null) throw new ProductNotFoundException(request.Id); - return new ProductResponse(productItem.Id, productItem.Name, productItem.Description, productItem.Price); + return productItem; }, cancellationToken: cancellationToken); return item!; diff --git a/src/api/modules/Catalog/Catalog.Application/Products/Get/v1/GetProductSpecs.cs b/src/api/modules/Catalog/Catalog.Application/Products/Get/v1/GetProductSpecs.cs new file mode 100644 index 000000000..9e30c3767 --- /dev/null +++ b/src/api/modules/Catalog/Catalog.Application/Products/Get/v1/GetProductSpecs.cs @@ -0,0 +1,14 @@ +using Ardalis.Specification; +using FSH.Starter.WebApi.Catalog.Domain; + +namespace FSH.Starter.WebApi.Catalog.Application.Products.Get.v1; + +public class GetProductSpecs : Specification +{ + public GetProductSpecs(Guid id) + { + Query + .Where(p => p.Id == id) + .Include(p => p.Brand); + } +} diff --git a/src/api/modules/Catalog/Catalog.Application/Products/Get/v1/ProductResponse.cs b/src/api/modules/Catalog/Catalog.Application/Products/Get/v1/ProductResponse.cs index 2c199ef2d..080d35868 100644 --- a/src/api/modules/Catalog/Catalog.Application/Products/Get/v1/ProductResponse.cs +++ b/src/api/modules/Catalog/Catalog.Application/Products/Get/v1/ProductResponse.cs @@ -1,2 +1,4 @@ +using FSH.Starter.WebApi.Catalog.Application.Brands.Get.v1; + namespace FSH.Starter.WebApi.Catalog.Application.Products.Get.v1; -public sealed record ProductResponse(Guid? Id, string Name, string? Description, decimal Price); +public sealed record ProductResponse(Guid? Id, string Name, string? Description, decimal Price, BrandResponse? Brand); diff --git a/src/api/modules/Catalog/Catalog.Application/Products/Search/v1/SearchProductSpecs.cs b/src/api/modules/Catalog/Catalog.Application/Products/Search/v1/SearchProductSpecs.cs index 6d9ee52a0..98567c6a5 100644 --- a/src/api/modules/Catalog/Catalog.Application/Products/Search/v1/SearchProductSpecs.cs +++ b/src/api/modules/Catalog/Catalog.Application/Products/Search/v1/SearchProductSpecs.cs @@ -10,7 +10,9 @@ public class SearchProductSpecs : EntitiesByPaginationFilterSpec Query + .Include(p => p.Brand) .OrderBy(c => c.Name, !command.HasOrderBy()) + .Where(p => p.BrandId == command.BrandId!.Value, command.BrandId.HasValue) .Where(p => p.Price >= command.MinimumRate!.Value, command.MinimumRate.HasValue) .Where(p => p.Price <= command.MaximumRate!.Value, command.MaximumRate.HasValue); } diff --git a/src/api/modules/Catalog/Catalog.Application/Products/Update/v1/UpdateProductCommand.cs b/src/api/modules/Catalog/Catalog.Application/Products/Update/v1/UpdateProductCommand.cs index 76d2bf2c7..dd7db751c 100644 --- a/src/api/modules/Catalog/Catalog.Application/Products/Update/v1/UpdateProductCommand.cs +++ b/src/api/modules/Catalog/Catalog.Application/Products/Update/v1/UpdateProductCommand.cs @@ -5,4 +5,5 @@ public sealed record UpdateProductCommand( Guid Id, string? Name, decimal Price, - string? Description = null) : IRequest; + string? Description = null, + Guid? BrandId = null) : IRequest; diff --git a/src/api/modules/Catalog/Catalog.Application/Products/Update/v1/UpdateProductHandler.cs b/src/api/modules/Catalog/Catalog.Application/Products/Update/v1/UpdateProductHandler.cs index e1d6156ca..506219625 100644 --- a/src/api/modules/Catalog/Catalog.Application/Products/Update/v1/UpdateProductHandler.cs +++ b/src/api/modules/Catalog/Catalog.Application/Products/Update/v1/UpdateProductHandler.cs @@ -16,7 +16,7 @@ public async Task Handle(UpdateProductCommand request, Ca ArgumentNullException.ThrowIfNull(request); var product = await repository.GetByIdAsync(request.Id, cancellationToken); _ = product ?? throw new ProductNotFoundException(request.Id); - var updatedProduct = product.Update(request.Name, request.Description, request.Price); + var updatedProduct = product.Update(request.Name, request.Description, request.Price, request.BrandId); await repository.UpdateAsync(updatedProduct, cancellationToken); logger.LogInformation("product with id : {ProductId} updated.", product.Id); return new UpdateProductResponse(product.Id); diff --git a/src/api/modules/Catalog/Catalog.Domain/Brand.cs b/src/api/modules/Catalog/Catalog.Domain/Brand.cs new file mode 100644 index 000000000..ce0b9997a --- /dev/null +++ b/src/api/modules/Catalog/Catalog.Domain/Brand.cs @@ -0,0 +1,48 @@ +using FSH.Framework.Core.Domain; +using FSH.Framework.Core.Domain.Contracts; +using FSH.Starter.WebApi.Catalog.Domain.Events; + +namespace FSH.Starter.WebApi.Catalog.Domain; +public class Brand : AuditableEntity, IAggregateRoot +{ + public string Name { get; private set; } = default!; + public string? Description { get; private set; } + + public static Brand Create(string name, string? description) + { + var brand = new Brand + { + Name = name, + Description = description + }; + + brand.QueueDomainEvent(new BrandCreated() { Brand = brand }); + + return brand; + } + + public Brand Update(string? name, string? description) + { + if (name is not null && Name?.Equals(name, StringComparison.OrdinalIgnoreCase) is not true) Name = name; + if (description is not null && Description?.Equals(description, StringComparison.OrdinalIgnoreCase) is not true) Description = description; + + this.QueueDomainEvent(new BrandUpdated() { Brand = this }); + + return this; + } + + public static Brand Update(Guid id, string name, string? description) + { + var brand = new Brand + { + Id = id, + Name = name, + Description = description + }; + + brand.QueueDomainEvent(new BrandUpdated() { Brand = brand }); + + return brand; + } +} + diff --git a/src/api/modules/Catalog/Catalog.Domain/Events/BrandCreated.cs b/src/api/modules/Catalog/Catalog.Domain/Events/BrandCreated.cs new file mode 100644 index 000000000..a1ae4abeb --- /dev/null +++ b/src/api/modules/Catalog/Catalog.Domain/Events/BrandCreated.cs @@ -0,0 +1,7 @@ +using FSH.Framework.Core.Domain.Events; + +namespace FSH.Starter.WebApi.Catalog.Domain.Events; +public sealed record BrandCreated : DomainEvent +{ + public Brand? Brand { get; set; } +} diff --git a/src/api/modules/Catalog/Catalog.Domain/Events/BrandUpdated.cs b/src/api/modules/Catalog/Catalog.Domain/Events/BrandUpdated.cs new file mode 100644 index 000000000..4446dcf07 --- /dev/null +++ b/src/api/modules/Catalog/Catalog.Domain/Events/BrandUpdated.cs @@ -0,0 +1,7 @@ +using FSH.Framework.Core.Domain.Events; + +namespace FSH.Starter.WebApi.Catalog.Domain.Events; +public sealed record BrandUpdated : DomainEvent +{ + public Brand? Brand { get; set; } +} diff --git a/src/api/modules/Catalog/Catalog.Domain/Exceptions/BrandNotFoundException.cs b/src/api/modules/Catalog/Catalog.Domain/Exceptions/BrandNotFoundException.cs new file mode 100644 index 000000000..84a40a1b8 --- /dev/null +++ b/src/api/modules/Catalog/Catalog.Domain/Exceptions/BrandNotFoundException.cs @@ -0,0 +1,10 @@ +using FSH.Framework.Core.Exceptions; + +namespace FSH.Starter.WebApi.Catalog.Domain.Exceptions; +public sealed class BrandNotFoundException : NotFoundException +{ + public BrandNotFoundException(Guid id) + : base($"brand with id {id} not found") + { + } +} diff --git a/src/api/modules/Catalog/Catalog.Domain/Product.cs b/src/api/modules/Catalog/Catalog.Domain/Product.cs index 6c5080a51..fbb610bfb 100644 --- a/src/api/modules/Catalog/Catalog.Domain/Product.cs +++ b/src/api/modules/Catalog/Catalog.Domain/Product.cs @@ -8,38 +8,43 @@ public class Product : AuditableEntity, IAggregateRoot public string Name { get; private set; } = default!; public string? Description { get; private set; } public decimal Price { get; private set; } + public Guid? BrandId { get; private set; } + public virtual Brand Brand { get; private set; } = default!; - public static Product Create(string name, string? description, decimal price) + public static Product Create(string name, string? description, decimal price, Guid? brandId) { var product = new Product(); product.Name = name; product.Description = description; product.Price = price; + product.BrandId = brandId; product.QueueDomainEvent(new ProductCreated() { Product = product }); return product; } - public Product Update(string? name, string? description, decimal? price) + public Product Update(string? name, string? description, decimal? price, Guid? brandId) { if (name is not null && Name?.Equals(name, StringComparison.OrdinalIgnoreCase) is not true) Name = name; if (description is not null && Description?.Equals(description, StringComparison.OrdinalIgnoreCase) is not true) Description = description; if (price.HasValue && Price != price) Price = price.Value; + if (brandId.HasValue && brandId.Value != Guid.Empty && !BrandId.Equals(brandId.Value)) BrandId = brandId.Value; this.QueueDomainEvent(new ProductUpdated() { Product = this }); return this; } - public static Product Update(Guid id, string name, string? description, decimal price) + public static Product Update(Guid id, string name, string? description, decimal price, Guid? brandId) { var product = new Product { Id = id, Name = name, Description = description, - Price = price + Price = price, + BrandId = brandId }; product.QueueDomainEvent(new ProductUpdated() { Product = product }); diff --git a/src/api/modules/Catalog/Catalog.Infrastructure/CatalogModule.cs b/src/api/modules/Catalog/Catalog.Infrastructure/CatalogModule.cs index e9f3a4eec..8327a6a9a 100644 --- a/src/api/modules/Catalog/Catalog.Infrastructure/CatalogModule.cs +++ b/src/api/modules/Catalog/Catalog.Infrastructure/CatalogModule.cs @@ -23,6 +23,13 @@ public override void AddRoutes(IEndpointRouteBuilder app) productGroup.MapGetProductListEndpoint(); productGroup.MapProductUpdateEndpoint(); productGroup.MapProductDeleteEndpoint(); + + var brandGroup = app.MapGroup("brands").WithTags("brands"); + brandGroup.MapBrandCreationEndpoint(); + brandGroup.MapGetBrandEndpoint(); + brandGroup.MapGetBrandListEndpoint(); + brandGroup.MapBrandUpdateEndpoint(); + brandGroup.MapBrandDeleteEndpoint(); } } public static WebApplicationBuilder RegisterCatalogServices(this WebApplicationBuilder builder) @@ -32,6 +39,8 @@ public static WebApplicationBuilder RegisterCatalogServices(this WebApplicationB builder.Services.AddScoped(); builder.Services.AddKeyedScoped, CatalogRepository>("catalog:products"); builder.Services.AddKeyedScoped, CatalogRepository>("catalog:products"); + builder.Services.AddKeyedScoped, CatalogRepository>("catalog:brands"); + builder.Services.AddKeyedScoped, CatalogRepository>("catalog:brands"); return builder; } public static WebApplication UseCatalogModule(this WebApplication app) diff --git a/src/api/modules/Catalog/Catalog.Infrastructure/Endpoints/v1/CreateBrandEndpoint.cs b/src/api/modules/Catalog/Catalog.Infrastructure/Endpoints/v1/CreateBrandEndpoint.cs new file mode 100644 index 000000000..b7adb6b9b --- /dev/null +++ b/src/api/modules/Catalog/Catalog.Infrastructure/Endpoints/v1/CreateBrandEndpoint.cs @@ -0,0 +1,26 @@ +using FSH.Framework.Infrastructure.Auth.Policy; +using FSH.Starter.WebApi.Catalog.Application.Brands.Create.v1; +using MediatR; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Routing; + +namespace FSH.Starter.WebApi.Catalog.Infrastructure.Endpoints.v1; +public static class CreateBrandEndpoint +{ + internal static RouteHandlerBuilder MapBrandCreationEndpoint(this IEndpointRouteBuilder endpoints) + { + return endpoints + .MapPost("/", async (CreateBrandCommand request, ISender mediator) => + { + var response = await mediator.Send(request); + return Results.Ok(response); + }) + .WithName(nameof(CreateBrandEndpoint)) + .WithSummary("creates a brand") + .WithDescription("creates a brand") + .Produces() + .RequirePermission("Permissions.Brands.Create") + .MapToApiVersion(1); + } +} diff --git a/src/api/modules/Catalog/Catalog.Infrastructure/Endpoints/v1/DeleteBrandEndpoint.cs b/src/api/modules/Catalog/Catalog.Infrastructure/Endpoints/v1/DeleteBrandEndpoint.cs new file mode 100644 index 000000000..3b39820dc --- /dev/null +++ b/src/api/modules/Catalog/Catalog.Infrastructure/Endpoints/v1/DeleteBrandEndpoint.cs @@ -0,0 +1,26 @@ +using FSH.Framework.Infrastructure.Auth.Policy; +using FSH.Starter.WebApi.Catalog.Application.Brands.Delete.v1; +using MediatR; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Routing; + +namespace FSH.Starter.WebApi.Catalog.Infrastructure.Endpoints.v1; +public static class DeleteBrandEndpoint +{ + internal static RouteHandlerBuilder MapBrandDeleteEndpoint(this IEndpointRouteBuilder endpoints) + { + return endpoints + .MapDelete("/{id:guid}", async (Guid id, ISender mediator) => + { + await mediator.Send(new DeleteBrandCommand(id)); + return Results.NoContent(); + }) + .WithName(nameof(DeleteBrandEndpoint)) + .WithSummary("deletes brand by id") + .WithDescription("deletes brand by id") + .Produces(StatusCodes.Status204NoContent) + .RequirePermission("Permissions.Brands.Delete") + .MapToApiVersion(1); + } +} diff --git a/src/api/modules/Catalog/Catalog.Infrastructure/Endpoints/v1/GetBrandEndpoint.cs b/src/api/modules/Catalog/Catalog.Infrastructure/Endpoints/v1/GetBrandEndpoint.cs new file mode 100644 index 000000000..13600025c --- /dev/null +++ b/src/api/modules/Catalog/Catalog.Infrastructure/Endpoints/v1/GetBrandEndpoint.cs @@ -0,0 +1,26 @@ +using FSH.Framework.Infrastructure.Auth.Policy; +using FSH.Starter.WebApi.Catalog.Application.Brands.Get.v1; +using MediatR; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Routing; + +namespace FSH.Starter.WebApi.Catalog.Infrastructure.Endpoints.v1; +public static class GetBrandEndpoint +{ + internal static RouteHandlerBuilder MapGetBrandEndpoint(this IEndpointRouteBuilder endpoints) + { + return endpoints + .MapGet("/{id:guid}", async (Guid id, ISender mediator) => + { + var response = await mediator.Send(new GetBrandRequest(id)); + return Results.Ok(response); + }) + .WithName(nameof(GetBrandEndpoint)) + .WithSummary("gets brand by id") + .WithDescription("gets brand by id") + .Produces() + .RequirePermission("Permissions.Brands.View") + .MapToApiVersion(1); + } +} diff --git a/src/api/modules/Catalog/Catalog.Infrastructure/Endpoints/v1/SearchBrandsEndpoint.cs b/src/api/modules/Catalog/Catalog.Infrastructure/Endpoints/v1/SearchBrandsEndpoint.cs new file mode 100644 index 000000000..bc6d9a83f --- /dev/null +++ b/src/api/modules/Catalog/Catalog.Infrastructure/Endpoints/v1/SearchBrandsEndpoint.cs @@ -0,0 +1,30 @@ +using FSH.Framework.Core.Paging; +using FSH.Framework.Infrastructure.Auth.Policy; +using FSH.Starter.WebApi.Catalog.Application.Brands.Get.v1; +using FSH.Starter.WebApi.Catalog.Application.Brands.Search.v1; +using MediatR; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Routing; + +namespace FSH.Starter.WebApi.Catalog.Infrastructure.Endpoints.v1; + +public static class SearchBrandsEndpoint +{ + internal static RouteHandlerBuilder MapGetBrandListEndpoint(this IEndpointRouteBuilder endpoints) + { + return endpoints + .MapPost("/search", async (ISender mediator, [FromBody] SearchBrandsCommand command) => + { + var response = await mediator.Send(command); + return Results.Ok(response); + }) + .WithName(nameof(SearchBrandsEndpoint)) + .WithSummary("Gets a list of brands") + .WithDescription("Gets a list of brands with pagination and filtering support") + .Produces>() + .RequirePermission("Permissions.Brands.View") + .MapToApiVersion(1); + } +} diff --git a/src/api/modules/Catalog/Catalog.Infrastructure/Endpoints/v1/UpdateBrandEndpoint.cs b/src/api/modules/Catalog/Catalog.Infrastructure/Endpoints/v1/UpdateBrandEndpoint.cs new file mode 100644 index 000000000..3e07b34be --- /dev/null +++ b/src/api/modules/Catalog/Catalog.Infrastructure/Endpoints/v1/UpdateBrandEndpoint.cs @@ -0,0 +1,27 @@ +using FSH.Framework.Infrastructure.Auth.Policy; +using FSH.Starter.WebApi.Catalog.Application.Brands.Update.v1; +using MediatR; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Routing; + +namespace FSH.Starter.WebApi.Catalog.Infrastructure.Endpoints.v1; +public static class UpdateBrandEndpoint +{ + internal static RouteHandlerBuilder MapBrandUpdateEndpoint(this IEndpointRouteBuilder endpoints) + { + return endpoints + .MapPut("/{id:guid}", async (Guid id, UpdateBrandCommand request, ISender mediator) => + { + if (id != request.Id) return Results.BadRequest(); + var response = await mediator.Send(request); + return Results.Ok(response); + }) + .WithName(nameof(UpdateBrandEndpoint)) + .WithSummary("update a brand") + .WithDescription("update a brand") + .Produces() + .RequirePermission("Permissions.Brands.Update") + .MapToApiVersion(1); + } +} diff --git a/src/api/modules/Catalog/Catalog.Infrastructure/Persistence/CatalogDbContext.cs b/src/api/modules/Catalog/Catalog.Infrastructure/Persistence/CatalogDbContext.cs index cc3964f6e..1dc8297ed 100644 --- a/src/api/modules/Catalog/Catalog.Infrastructure/Persistence/CatalogDbContext.cs +++ b/src/api/modules/Catalog/Catalog.Infrastructure/Persistence/CatalogDbContext.cs @@ -17,6 +17,7 @@ public CatalogDbContext(IMultiTenantContextAccessor multiTenantCo } public DbSet Products { get; set; } = null!; + public DbSet Brands { get; set; } = null!; protected override void OnModelCreating(ModelBuilder modelBuilder) { diff --git a/src/api/modules/Catalog/Catalog.Infrastructure/Persistence/CatalogDbInitializer.cs b/src/api/modules/Catalog/Catalog.Infrastructure/Persistence/CatalogDbInitializer.cs index e627108e6..db213a062 100644 --- a/src/api/modules/Catalog/Catalog.Infrastructure/Persistence/CatalogDbInitializer.cs +++ b/src/api/modules/Catalog/Catalog.Infrastructure/Persistence/CatalogDbInitializer.cs @@ -22,9 +22,10 @@ public async Task SeedAsync(CancellationToken cancellationToken) const string Name = "Keychron V6 QMK Custom Wired Mechanical Keyboard"; const string Description = "A full-size layout QMK/VIA custom mechanical keyboard"; const decimal Price = 79; + Guid? BrandId = null; if (await context.Products.FirstOrDefaultAsync(t => t.Name == Name, cancellationToken).ConfigureAwait(false) is null) { - var product = Product.Create(Name, Description, Price); + var product = Product.Create(Name, Description, Price, BrandId); await context.Products.AddAsync(product, cancellationToken); await context.SaveChangesAsync(cancellationToken).ConfigureAwait(false); logger.LogInformation("[{Tenant}] seeding default catalog data", context.TenantInfo!.Identifier); diff --git a/src/api/modules/Catalog/Catalog.Infrastructure/Persistence/Configurations/BrandConfigurations.cs b/src/api/modules/Catalog/Catalog.Infrastructure/Persistence/Configurations/BrandConfigurations.cs new file mode 100644 index 000000000..0abf96da3 --- /dev/null +++ b/src/api/modules/Catalog/Catalog.Infrastructure/Persistence/Configurations/BrandConfigurations.cs @@ -0,0 +1,16 @@ +using Finbuckle.MultiTenant; +using FSH.Starter.WebApi.Catalog.Domain; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace FSH.Starter.WebApi.Catalog.Infrastructure.Persistence.Configurations; +internal sealed class BrandConfiguration : IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder builder) + { + builder.IsMultiTenant(); + builder.HasKey(x => x.Id); + builder.Property(x => x.Name).HasMaxLength(100); + builder.Property(x => x.Description).HasMaxLength(1000); + } +} diff --git a/src/apps/blazor/client/Layout/NavMenu.razor b/src/apps/blazor/client/Layout/NavMenu.razor index bd13ae88d..86ab42d0d 100644 --- a/src/apps/blazor/client/Layout/NavMenu.razor +++ b/src/apps/blazor/client/Layout/NavMenu.razor @@ -10,6 +10,7 @@ Modules Products + Brands Todos @if (CanViewAdministrationGroup) diff --git a/src/apps/blazor/client/Layout/NavMenu.razor.cs b/src/apps/blazor/client/Layout/NavMenu.razor.cs index f2b4f2550..41b598a48 100644 --- a/src/apps/blazor/client/Layout/NavMenu.razor.cs +++ b/src/apps/blazor/client/Layout/NavMenu.razor.cs @@ -18,6 +18,7 @@ public partial class NavMenu private bool _canViewRoles; private bool _canViewUsers; private bool _canViewProducts; + private bool _canViewBrands; private bool _canViewTodos; private bool _canViewTenants; private bool _canViewAuditTrails; @@ -31,6 +32,7 @@ protected override async Task OnParametersSetAsync() _canViewRoles = await AuthService.HasPermissionAsync(user, FshActions.View, FshResources.Roles); _canViewUsers = await AuthService.HasPermissionAsync(user, FshActions.View, FshResources.Users); _canViewProducts = await AuthService.HasPermissionAsync(user, FshActions.View, FshResources.Products); + _canViewBrands = await AuthService.HasPermissionAsync(user, FshActions.View, FshResources.Brands); _canViewTodos = await AuthService.HasPermissionAsync(user, FshActions.View, FshResources.Todos); _canViewTenants = await AuthService.HasPermissionAsync(user, FshActions.View, FshResources.Tenants); _canViewAuditTrails = await AuthService.HasPermissionAsync(user, FshActions.View, FshResources.AuditTrails); diff --git a/src/apps/blazor/client/Pages/Catalog/Brands.razor b/src/apps/blazor/client/Pages/Catalog/Brands.razor new file mode 100644 index 000000000..e805ff379 --- /dev/null +++ b/src/apps/blazor/client/Pages/Catalog/Brands.razor @@ -0,0 +1,44 @@ +@page "/catalog/brands" + + + + + + + + + + + @if (!Context.AddEditModal.IsCreate) + { + + + + } + + + + + + + + +
+ @if(!Context.AddEditModal.IsCreate) + { + + View + + + + Delete + + } +
+
+
+
+ +
diff --git a/src/apps/blazor/client/Pages/Catalog/Brands.razor.cs b/src/apps/blazor/client/Pages/Catalog/Brands.razor.cs new file mode 100644 index 000000000..846f2985f --- /dev/null +++ b/src/apps/blazor/client/Pages/Catalog/Brands.razor.cs @@ -0,0 +1,50 @@ +using FSH.Starter.Blazor.Client.Components.EntityTable; +using FSH.Starter.Blazor.Infrastructure.Api; +using FSH.Starter.Shared.Authorization; +using Mapster; +using Microsoft.AspNetCore.Components; + +namespace FSH.Starter.Blazor.Client.Pages.Catalog; + +public partial class Brands +{ + [Inject] + protected IApiClient _client { get; set; } = default!; + + protected EntityServerTableContext Context { get; set; } = default!; + + private EntityTable _table = default!; + + protected override void OnInitialized() => + Context = new( + entityName: "Brand", + entityNamePlural: "Brands", + entityResource: FshResources.Brands, + fields: new() + { + new(brand => brand.Id, "Id", "Id"), + new(brand => brand.Name, "Name", "Name"), + new(brand => brand.Description, "Description", "Description") + }, + enableAdvancedSearch: true, + idFunc: brand => brand.Id!.Value, + searchFunc: async filter => + { + var brandFilter = filter.Adapt(); + var result = await _client.SearchBrandsEndpointAsync("1", brandFilter); + return result.Adapt>(); + }, + createFunc: async brand => + { + await _client.CreateBrandEndpointAsync("1", brand.Adapt()); + }, + updateFunc: async (id, brand) => + { + await _client.UpdateBrandEndpointAsync("1", id, brand.Adapt()); + }, + deleteFunc: async id => await _client.DeleteBrandEndpointAsync("1", id)); +} + +public class BrandViewModel : UpdateBrandCommand +{ +} diff --git a/src/apps/blazor/client/Pages/Catalog/Products.razor b/src/apps/blazor/client/Pages/Catalog/Products.razor index ceb965042..f3cb893b1 100644 --- a/src/apps/blazor/client/Pages/Catalog/Products.razor +++ b/src/apps/blazor/client/Pages/Catalog/Products.razor @@ -5,6 +5,13 @@ + + All Brands + @foreach (var brand in _brands) + { + @brand.Name + } + Minimum Rate: @_searchMinimumRate.ToString() Maximum Rate: @_searchMaximumRate.ToString() @@ -26,6 +33,14 @@ + + + @foreach (var brand in _brands) + { + @brand.Name + } + +
diff --git a/src/apps/blazor/client/Pages/Catalog/Products.razor.cs b/src/apps/blazor/client/Pages/Catalog/Products.razor.cs index 3cae28ca5..46266197c 100644 --- a/src/apps/blazor/client/Pages/Catalog/Products.razor.cs +++ b/src/apps/blazor/client/Pages/Catalog/Products.razor.cs @@ -15,7 +15,10 @@ public partial class Products private EntityTable _table = default!; - protected override void OnInitialized() => + private List _brands = new(); + + protected override async Task OnInitializedAsync() + { Context = new( entityName: "Product", entityNamePlural: "Products", @@ -25,7 +28,8 @@ protected override void OnInitialized() => new(prod => prod.Id,"Id", "Id"), new(prod => prod.Name,"Name", "Name"), new(prod => prod.Description, "Description", "Description"), - new(prod => prod.Price, "Price", "Price") + new(prod => prod.Price, "Price", "Price"), + new(prod => prod.Brand?.Name, "Brand", "Brand") }, enableAdvancedSearch: true, idFunc: prod => prod.Id!.Value, @@ -34,6 +38,7 @@ protected override void OnInitialized() => var productFilter = filter.Adapt(); productFilter.MinimumRate = Convert.ToDouble(SearchMinimumRate); productFilter.MaximumRate = Convert.ToDouble(SearchMaximumRate); + productFilter.BrandId = SearchBrandId; var result = await _client.SearchProductsEndpointAsync("1", productFilter); return result.Adapt>(); }, @@ -47,10 +52,25 @@ protected override void OnInitialized() => }, deleteFunc: async id => await _client.DeleteProductEndpointAsync("1", id)); + await LoadBrandsAsync(); + } + + private async Task LoadBrandsAsync() + { + if (_brands.Count == 0) + { + var response = await _client.SearchBrandsEndpointAsync("1", new SearchBrandsCommand()); + if (response?.Items != null) + { + _brands = response.Items.ToList(); + } + } + } + // Advanced Search - private Guid _searchBrandId; - private Guid SearchBrandId + private Guid? _searchBrandId; + private Guid? SearchBrandId { get => _searchBrandId; set diff --git a/src/apps/blazor/infrastructure/Api/ApiClient.cs b/src/apps/blazor/infrastructure/Api/ApiClient.cs index b3e9b0bcc..0de5930cb 100644 --- a/src/apps/blazor/infrastructure/Api/ApiClient.cs +++ b/src/apps/blazor/infrastructure/Api/ApiClient.cs @@ -1,6 +1,6 @@ //---------------------- // -// Generated using the NSwag toolchain v14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0)) (http://NSwag.org) +// Generated using the NSwag toolchain v14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0)) (http://NSwag.org) // //---------------------- @@ -10,6 +10,7 @@ #pragma warning disable 114 // Disable "CS0114 '{derivedDto}.RaisePropertyChanged(String)' hides inherited member 'dtoBase.RaisePropertyChanged(String)'. To make the current member override that implementation, add the override keyword. Otherwise add the new keyword." #pragma warning disable 472 // Disable "CS0472 The result of the expression is always 'false' since a value of type 'Int32' is never equal to 'null' of type 'Int32?' #pragma warning disable 612 // Disable "CS0612 '...' is obsolete" +#pragma warning disable 649 // Disable "CS0649 Field is never assigned to, and will always have its default value null" #pragma warning disable 1573 // Disable "CS1573 Parameter '...' has no matching param tag in the XML comment for ... #pragma warning disable 1591 // Disable "CS1591 Missing XML comment for publicly visible type or member ..." #pragma warning disable 8073 // Disable "CS8073 The result of the expression is always 'false' since a value of type 'T' is never equal to 'null' of type 'T?'" @@ -17,15 +18,130 @@ #pragma warning disable 8603 // Disable "CS8603 Possible null reference return" #pragma warning disable 8604 // Disable "CS8604 Possible null reference argument for parameter" #pragma warning disable 8625 // Disable "CS8625 Cannot convert null literal to non-nullable reference type" -#pragma warning disable CS8765 // Nullability of type of parameter doesn't match overridden member (possibly because of nullability attributes). +#pragma warning disable 8765 // Disable "CS8765 Nullability of type of parameter doesn't match overridden member (possibly because of nullability attributes)." namespace FSH.Starter.Blazor.Infrastructure.Api { using System = global::System; - [System.CodeDom.Compiler.GeneratedCode("NSwag", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NSwag", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial interface IApiClient { + /// + /// creates a brand + /// + /// + /// creates a brand + /// + /// The requested API version + /// OK + /// A server side error occurred. + System.Threading.Tasks.Task CreateBrandEndpointAsync(string version, CreateBrandCommand body); + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// creates a brand + /// + /// + /// creates a brand + /// + /// The requested API version + /// OK + /// A server side error occurred. + System.Threading.Tasks.Task CreateBrandEndpointAsync(string version, CreateBrandCommand body, System.Threading.CancellationToken cancellationToken); + + /// + /// gets brand by id + /// + /// + /// gets brand by id + /// + /// The requested API version + /// OK + /// A server side error occurred. + System.Threading.Tasks.Task GetBrandEndpointAsync(string version, System.Guid id); + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// gets brand by id + /// + /// + /// gets brand by id + /// + /// The requested API version + /// OK + /// A server side error occurred. + System.Threading.Tasks.Task GetBrandEndpointAsync(string version, System.Guid id, System.Threading.CancellationToken cancellationToken); + + /// + /// update a brand + /// + /// + /// update a brand + /// + /// The requested API version + /// OK + /// A server side error occurred. + System.Threading.Tasks.Task UpdateBrandEndpointAsync(string version, System.Guid id, UpdateBrandCommand body); + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// update a brand + /// + /// + /// update a brand + /// + /// The requested API version + /// OK + /// A server side error occurred. + System.Threading.Tasks.Task UpdateBrandEndpointAsync(string version, System.Guid id, UpdateBrandCommand body, System.Threading.CancellationToken cancellationToken); + + /// + /// deletes brand by id + /// + /// + /// deletes brand by id + /// + /// The requested API version + /// No Content + /// A server side error occurred. + System.Threading.Tasks.Task DeleteBrandEndpointAsync(string version, System.Guid id); + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// deletes brand by id + /// + /// + /// deletes brand by id + /// + /// The requested API version + /// No Content + /// A server side error occurred. + System.Threading.Tasks.Task DeleteBrandEndpointAsync(string version, System.Guid id, System.Threading.CancellationToken cancellationToken); + + /// + /// Gets a list of brands + /// + /// + /// Gets a list of brands with pagination and filtering support + /// + /// The requested API version + /// OK + /// A server side error occurred. + System.Threading.Tasks.Task SearchBrandsEndpointAsync(string version, SearchBrandsCommand body); + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Gets a list of brands + /// + /// + /// Gets a list of brands with pagination and filtering support + /// + /// The requested API version + /// OK + /// A server side error occurred. + System.Threading.Tasks.Task SearchBrandsEndpointAsync(string version, SearchBrandsCommand body, System.Threading.CancellationToken cancellationToken); + /// /// creates a product /// @@ -823,77 +939,593 @@ public partial interface IApiClient /// A server side error occurred. System.Threading.Tasks.Task AssignRolesToUserEndpointAsync(string id, AssignUserRoleCommand body, System.Threading.CancellationToken cancellationToken); - /// - /// get user roles - /// - /// - /// get user roles - /// - /// OK - /// A server side error occurred. - System.Threading.Tasks.Task> GetUserRolesEndpointAsync(string id); + /// + /// get user roles + /// + /// + /// get user roles + /// + /// OK + /// A server side error occurred. + System.Threading.Tasks.Task> GetUserRolesEndpointAsync(string id); + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// get user roles + /// + /// + /// get user roles + /// + /// OK + /// A server side error occurred. + System.Threading.Tasks.Task> GetUserRolesEndpointAsync(string id, System.Threading.CancellationToken cancellationToken); + + /// + /// Get user's audit trail details + /// + /// + /// Get user's audit trail details. + /// + /// OK + /// A server side error occurred. + System.Threading.Tasks.Task> GetUserAuditTrailEndpointAsync(System.Guid id); + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Get user's audit trail details + /// + /// + /// Get user's audit trail details. + /// + /// OK + /// A server side error occurred. + System.Threading.Tasks.Task> GetUserAuditTrailEndpointAsync(System.Guid id, System.Threading.CancellationToken cancellationToken); + + } + + [System.CodeDom.Compiler.GeneratedCode("NSwag", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class ApiClient : IApiClient + { + private System.Net.Http.HttpClient _httpClient; + private static System.Lazy _settings = new System.Lazy(CreateSerializerSettings, true); + private System.Text.Json.JsonSerializerOptions _instanceSettings; + + #pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. + public ApiClient(System.Net.Http.HttpClient httpClient) + #pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. + { + _httpClient = httpClient; + Initialize(); + } + + private static System.Text.Json.JsonSerializerOptions CreateSerializerSettings() + { + var settings = new System.Text.Json.JsonSerializerOptions(); + UpdateJsonSerializerSettings(settings); + return settings; + } + + protected System.Text.Json.JsonSerializerOptions JsonSerializerSettings { get { return _instanceSettings ?? _settings.Value; } } + + static partial void UpdateJsonSerializerSettings(System.Text.Json.JsonSerializerOptions settings); + + partial void Initialize(); + + partial void PrepareRequest(System.Net.Http.HttpClient client, System.Net.Http.HttpRequestMessage request, string url); + partial void PrepareRequest(System.Net.Http.HttpClient client, System.Net.Http.HttpRequestMessage request, System.Text.StringBuilder urlBuilder); + partial void ProcessResponse(System.Net.Http.HttpClient client, System.Net.Http.HttpResponseMessage response); + + /// + /// creates a brand + /// + /// + /// creates a brand + /// + /// The requested API version + /// OK + /// A server side error occurred. + public virtual System.Threading.Tasks.Task CreateBrandEndpointAsync(string version, CreateBrandCommand body) + { + return CreateBrandEndpointAsync(version, body, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// creates a brand + /// + /// + /// creates a brand + /// + /// The requested API version + /// OK + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task CreateBrandEndpointAsync(string version, CreateBrandCommand body, System.Threading.CancellationToken cancellationToken) + { + if (version == null) + throw new System.ArgumentNullException("version"); + + if (body == null) + throw new System.ArgumentNullException("body"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var json_ = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(body, JsonSerializerSettings); + var content_ = new System.Net.Http.ByteArrayContent(json_); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + + // Operation Path: "api/v{version}/catalog/brands" + urlBuilder_.Append("api/v"); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(version, System.Globalization.CultureInfo.InvariantCulture))); + urlBuilder_.Append("/catalog/brands"); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// gets brand by id + /// + /// + /// gets brand by id + /// + /// The requested API version + /// OK + /// A server side error occurred. + public virtual System.Threading.Tasks.Task GetBrandEndpointAsync(string version, System.Guid id) + { + return GetBrandEndpointAsync(version, id, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// gets brand by id + /// + /// + /// gets brand by id + /// + /// The requested API version + /// OK + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task GetBrandEndpointAsync(string version, System.Guid id, System.Threading.CancellationToken cancellationToken) + { + if (version == null) + throw new System.ArgumentNullException("version"); + + if (id == null) + throw new System.ArgumentNullException("id"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + + // Operation Path: "api/v{version}/catalog/brands/{id}" + urlBuilder_.Append("api/v"); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(version, System.Globalization.CultureInfo.InvariantCulture))); + urlBuilder_.Append("/catalog/brands/"); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(id, System.Globalization.CultureInfo.InvariantCulture))); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// update a brand + /// + /// + /// update a brand + /// + /// The requested API version + /// OK + /// A server side error occurred. + public virtual System.Threading.Tasks.Task UpdateBrandEndpointAsync(string version, System.Guid id, UpdateBrandCommand body) + { + return UpdateBrandEndpointAsync(version, id, body, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// update a brand + /// + /// + /// update a brand + /// + /// The requested API version + /// OK + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task UpdateBrandEndpointAsync(string version, System.Guid id, UpdateBrandCommand body, System.Threading.CancellationToken cancellationToken) + { + if (version == null) + throw new System.ArgumentNullException("version"); + + if (id == null) + throw new System.ArgumentNullException("id"); + + if (body == null) + throw new System.ArgumentNullException("body"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var json_ = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(body, JsonSerializerSettings); + var content_ = new System.Net.Http.ByteArrayContent(json_); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("PUT"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + + // Operation Path: "api/v{version}/catalog/brands/{id}" + urlBuilder_.Append("api/v"); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(version, System.Globalization.CultureInfo.InvariantCulture))); + urlBuilder_.Append("/catalog/brands/"); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(id, System.Globalization.CultureInfo.InvariantCulture))); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// deletes brand by id + /// + /// + /// deletes brand by id + /// + /// The requested API version + /// No Content + /// A server side error occurred. + public virtual System.Threading.Tasks.Task DeleteBrandEndpointAsync(string version, System.Guid id) + { + return DeleteBrandEndpointAsync(version, id, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// deletes brand by id + /// + /// + /// deletes brand by id + /// + /// The requested API version + /// No Content + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task DeleteBrandEndpointAsync(string version, System.Guid id, System.Threading.CancellationToken cancellationToken) + { + if (version == null) + throw new System.ArgumentNullException("version"); + + if (id == null) + throw new System.ArgumentNullException("id"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("DELETE"); + + var urlBuilder_ = new System.Text.StringBuilder(); + + // Operation Path: "api/v{version}/catalog/brands/{id}" + urlBuilder_.Append("api/v"); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(version, System.Globalization.CultureInfo.InvariantCulture))); + urlBuilder_.Append("/catalog/brands/"); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(id, System.Globalization.CultureInfo.InvariantCulture))); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); - /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. - /// - /// get user roles - /// - /// - /// get user roles - /// - /// OK - /// A server side error occurred. - System.Threading.Tasks.Task> GetUserRolesEndpointAsync(string id, System.Threading.CancellationToken cancellationToken); + var status_ = (int)response_.StatusCode; + if (status_ == 204) + { + return; + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } /// - /// Get user's audit trail details + /// Gets a list of brands /// /// - /// Get user's audit trail details. + /// Gets a list of brands with pagination and filtering support /// + /// The requested API version /// OK /// A server side error occurred. - System.Threading.Tasks.Task> GetUserAuditTrailEndpointAsync(System.Guid id); + public virtual System.Threading.Tasks.Task SearchBrandsEndpointAsync(string version, SearchBrandsCommand body) + { + return SearchBrandsEndpointAsync(version, body, System.Threading.CancellationToken.None); + } /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. /// - /// Get user's audit trail details + /// Gets a list of brands /// /// - /// Get user's audit trail details. + /// Gets a list of brands with pagination and filtering support /// + /// The requested API version /// OK /// A server side error occurred. - System.Threading.Tasks.Task> GetUserAuditTrailEndpointAsync(System.Guid id, System.Threading.CancellationToken cancellationToken); + public virtual async System.Threading.Tasks.Task SearchBrandsEndpointAsync(string version, SearchBrandsCommand body, System.Threading.CancellationToken cancellationToken) + { + if (version == null) + throw new System.ArgumentNullException("version"); - } + if (body == null) + throw new System.ArgumentNullException("body"); - [System.CodeDom.Compiler.GeneratedCode("NSwag", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class ApiClient : IApiClient - { - private System.Net.Http.HttpClient _httpClient; - private static System.Lazy _settings = new System.Lazy(CreateSerializerSettings, true); + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var json_ = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(body, JsonSerializerSettings); + var content_ = new System.Net.Http.ByteArrayContent(json_); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); - #pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. - public ApiClient(System.Net.Http.HttpClient httpClient) - #pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. - { - _httpClient = httpClient; - } + var urlBuilder_ = new System.Text.StringBuilder(); + + // Operation Path: "api/v{version}/catalog/brands/search" + urlBuilder_.Append("api/v"); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(version, System.Globalization.CultureInfo.InvariantCulture))); + urlBuilder_.Append("/catalog/brands/search"); - private static System.Text.Json.JsonSerializerOptions CreateSerializerSettings() - { - var settings = new System.Text.Json.JsonSerializerOptions(); - UpdateJsonSerializerSettings(settings); - return settings; - } + PrepareRequest(client_, request_, urlBuilder_); - protected System.Text.Json.JsonSerializerOptions JsonSerializerSettings { get { return _settings.Value; } } + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); - static partial void UpdateJsonSerializerSettings(System.Text.Json.JsonSerializerOptions settings); + PrepareRequest(client_, request_, url_); - partial void PrepareRequest(System.Net.Http.HttpClient client, System.Net.Http.HttpRequestMessage request, string url); - partial void PrepareRequest(System.Net.Http.HttpClient client, System.Net.Http.HttpRequestMessage request, System.Text.StringBuilder urlBuilder); - partial void ProcessResponse(System.Net.Http.HttpClient client, System.Net.Http.HttpResponseMessage response); + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } /// /// creates a product @@ -933,7 +1565,7 @@ public virtual async System.Threading.Tasks.Task CreatePr { using (var request_ = new System.Net.Http.HttpRequestMessage()) { - var json_ = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(body, _settings.Value); + var json_ = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(body, JsonSerializerSettings); var content_ = new System.Net.Http.ByteArrayContent(json_); content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); request_.Content = content_; @@ -1141,7 +1773,7 @@ public virtual async System.Threading.Tasks.Task UpdatePr { using (var request_ = new System.Net.Http.HttpRequestMessage()) { - var json_ = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(body, _settings.Value); + var json_ = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(body, JsonSerializerSettings); var content_ = new System.Net.Http.ByteArrayContent(json_); content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); request_.Content = content_; @@ -1341,7 +1973,7 @@ public virtual async System.Threading.Tasks.Task Searc { using (var request_ = new System.Net.Http.HttpRequestMessage()) { - var json_ = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(body, _settings.Value); + var json_ = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(body, JsonSerializerSettings); var content_ = new System.Net.Http.ByteArrayContent(json_); content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); request_.Content = content_; @@ -1712,7 +2344,7 @@ public virtual async System.Threading.Tasks.Task CreateOrUpdateRoleEndp { using (var request_ = new System.Net.Http.HttpRequestMessage()) { - var json_ = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(body, _settings.Value); + var json_ = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(body, JsonSerializerSettings); var content_ = new System.Net.Http.ByteArrayContent(json_); content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); request_.Content = content_; @@ -1907,7 +2539,7 @@ public virtual async System.Threading.Tasks.Task UpdateRolePermissionsEndpointAs { using (var request_ = new System.Net.Http.HttpRequestMessage()) { - var json_ = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(body, _settings.Value); + var json_ = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(body, JsonSerializerSettings); var content_ = new System.Net.Http.ByteArrayContent(json_); content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); request_.Content = content_; @@ -2000,7 +2632,7 @@ public virtual async System.Threading.Tasks.Task CreateTen { using (var request_ = new System.Net.Http.HttpRequestMessage()) { - var json_ = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(body, _settings.Value); + var json_ = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(body, JsonSerializerSettings); var content_ = new System.Net.Http.ByteArrayContent(json_); content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); request_.Content = content_; @@ -2281,7 +2913,7 @@ public virtual async System.Threading.Tasks.Task Up { using (var request_ = new System.Net.Http.HttpRequestMessage()) { - var json_ = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(body, _settings.Value); + var json_ = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(body, JsonSerializerSettings); var content_ = new System.Net.Http.ByteArrayContent(json_); content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); request_.Content = content_; @@ -2575,7 +3207,7 @@ public virtual async System.Threading.Tasks.Task CreateTodoE { using (var request_ = new System.Net.Http.HttpRequestMessage()) { - var json_ = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(body, _settings.Value); + var json_ = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(body, JsonSerializerSettings); var content_ = new System.Net.Http.ByteArrayContent(json_); content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); request_.Content = content_; @@ -2783,7 +3415,7 @@ public virtual async System.Threading.Tasks.Task UpdateTodoE { using (var request_ = new System.Net.Http.HttpRequestMessage()) { - var json_ = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(body, _settings.Value); + var json_ = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(body, JsonSerializerSettings); var content_ = new System.Net.Http.ByteArrayContent(json_); content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); request_.Content = content_; @@ -2983,7 +3615,7 @@ public virtual async System.Threading.Tasks.Task GetTodoListEn { using (var request_ = new System.Net.Http.HttpRequestMessage()) { - var json_ = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(body, _settings.Value); + var json_ = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(body, JsonSerializerSettings); var content_ = new System.Net.Http.ByteArrayContent(json_); content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); request_.Content = content_; @@ -3086,7 +3718,7 @@ public virtual async System.Threading.Tasks.Task RefreshTokenEndp if (tenant == null) throw new System.ArgumentNullException("tenant"); request_.Headers.TryAddWithoutValidation("tenant", ConvertToString(tenant, System.Globalization.CultureInfo.InvariantCulture)); - var json_ = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(body, _settings.Value); + var json_ = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(body, JsonSerializerSettings); var content_ = new System.Net.Http.ByteArrayContent(json_); content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); request_.Content = content_; @@ -3187,7 +3819,7 @@ public virtual async System.Threading.Tasks.Task TokenGenerationE if (tenant == null) throw new System.ArgumentNullException("tenant"); request_.Headers.TryAddWithoutValidation("tenant", ConvertToString(tenant, System.Globalization.CultureInfo.InvariantCulture)); - var json_ = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(body, _settings.Value); + var json_ = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(body, JsonSerializerSettings); var content_ = new System.Net.Http.ByteArrayContent(json_); content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); request_.Content = content_; @@ -3284,7 +3916,7 @@ public virtual async System.Threading.Tasks.Task RegisterU { using (var request_ = new System.Net.Http.HttpRequestMessage()) { - var json_ = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(body, _settings.Value); + var json_ = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(body, JsonSerializerSettings); var content_ = new System.Net.Http.ByteArrayContent(json_); content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); request_.Content = content_; @@ -3385,7 +4017,7 @@ public virtual async System.Threading.Tasks.Task SelfRegis if (tenant == null) throw new System.ArgumentNullException("tenant"); request_.Headers.TryAddWithoutValidation("tenant", ConvertToString(tenant, System.Globalization.CultureInfo.InvariantCulture)); - var json_ = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(body, _settings.Value); + var json_ = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(body, JsonSerializerSettings); var content_ = new System.Net.Http.ByteArrayContent(json_); content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); request_.Content = content_; @@ -3482,7 +4114,7 @@ public virtual async System.Threading.Tasks.Task UpdateUserEndpointAsync(UpdateU { using (var request_ = new System.Net.Http.HttpRequestMessage()) { - var json_ = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(body, _settings.Value); + var json_ = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(body, JsonSerializerSettings); var content_ = new System.Net.Http.ByteArrayContent(json_); content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); request_.Content = content_; @@ -3939,7 +4571,7 @@ public virtual async System.Threading.Tasks.Task ForgotPasswordEndpointAsync(str if (tenant == null) throw new System.ArgumentNullException("tenant"); request_.Headers.TryAddWithoutValidation("tenant", ConvertToString(tenant, System.Globalization.CultureInfo.InvariantCulture)); - var json_ = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(body, _settings.Value); + var json_ = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(body, JsonSerializerSettings); var content_ = new System.Net.Http.ByteArrayContent(json_); content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); request_.Content = content_; @@ -4030,7 +4662,7 @@ public virtual async System.Threading.Tasks.Task ChangePasswordEndpointAsync(Cha { using (var request_ = new System.Net.Http.HttpRequestMessage()) { - var json_ = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(body, _settings.Value); + var json_ = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(body, JsonSerializerSettings); var content_ = new System.Net.Http.ByteArrayContent(json_); content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); request_.Content = content_; @@ -4125,7 +4757,7 @@ public virtual async System.Threading.Tasks.Task ResetPasswordEndpointAsync(stri if (tenant == null) throw new System.ArgumentNullException("tenant"); request_.Headers.TryAddWithoutValidation("tenant", ConvertToString(tenant, System.Globalization.CultureInfo.InvariantCulture)); - var json_ = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(body, _settings.Value); + var json_ = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(body, JsonSerializerSettings); var content_ = new System.Net.Http.ByteArrayContent(json_); content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); request_.Content = content_; @@ -4309,7 +4941,7 @@ public virtual async System.Threading.Tasks.Task ToggleUserStatusEndpointAsync(s { using (var request_ = new System.Net.Http.HttpRequestMessage()) { - var json_ = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(body, _settings.Value); + var json_ = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(body, JsonSerializerSettings); var content_ = new System.Net.Http.ByteArrayContent(json_); content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); request_.Content = content_; @@ -4405,7 +5037,7 @@ public virtual async System.Threading.Tasks.Task AssignRolesToUserEndpointAsync( { using (var request_ = new System.Net.Http.HttpRequestMessage()) { - var json_ = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(body, _settings.Value); + var json_ = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(body, JsonSerializerSettings); var content_ = new System.Net.Http.ByteArrayContent(json_); content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); request_.Content = content_; @@ -4764,7 +5396,7 @@ private string ConvertToString(object? value, System.Globalization.CultureInfo c } } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class ActivateTenantResponse { @@ -4773,7 +5405,7 @@ public partial class ActivateTenantResponse } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class AssignUserRoleCommand { @@ -4782,7 +5414,7 @@ public partial class AssignUserRoleCommand } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class AuditTrail { @@ -4815,7 +5447,49 @@ public partial class AuditTrail } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class BrandResponse + { + + [System.Text.Json.Serialization.JsonPropertyName("id")] + public System.Guid? Id { get; set; } = default!; + + [System.Text.Json.Serialization.JsonPropertyName("name")] + public string? Name { get; set; } = default!; + + [System.Text.Json.Serialization.JsonPropertyName("description")] + public string? Description { get; set; } = default!; + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class BrandResponsePagedList + { + + [System.Text.Json.Serialization.JsonPropertyName("items")] + public System.Collections.Generic.ICollection? Items { get; set; } = default!; + + [System.Text.Json.Serialization.JsonPropertyName("pageNumber")] + public int PageNumber { get; set; } = default!; + + [System.Text.Json.Serialization.JsonPropertyName("pageSize")] + public int PageSize { get; set; } = default!; + + [System.Text.Json.Serialization.JsonPropertyName("totalCount")] + public int TotalCount { get; set; } = default!; + + [System.Text.Json.Serialization.JsonPropertyName("totalPages")] + public int TotalPages { get; set; } = default!; + + [System.Text.Json.Serialization.JsonPropertyName("hasPrevious")] + public bool HasPrevious { get; set; } = default!; + + [System.Text.Json.Serialization.JsonPropertyName("hasNext")] + public bool HasNext { get; set; } = default!; + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class ChangePasswordCommand { @@ -4830,7 +5504,28 @@ public partial class ChangePasswordCommand } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class CreateBrandCommand + { + + [System.Text.Json.Serialization.JsonPropertyName("name")] + public string? Name { get; set; } = "Sample Brand"; + + [System.Text.Json.Serialization.JsonPropertyName("description")] + public string? Description { get; set; } = "Descriptive Description"; + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class CreateBrandResponse + { + + [System.Text.Json.Serialization.JsonPropertyName("id")] + public System.Guid? Id { get; set; } = default!; + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class CreateOrUpdateRoleCommand { @@ -4845,7 +5540,7 @@ public partial class CreateOrUpdateRoleCommand } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class CreateProductCommand { @@ -4858,9 +5553,12 @@ public partial class CreateProductCommand [System.Text.Json.Serialization.JsonPropertyName("description")] public string? Description { get; set; } = "Descriptive Description"; + [System.Text.Json.Serialization.JsonPropertyName("brandId")] + public System.Guid? BrandId { get; set; } = default!; + } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class CreateProductResponse { @@ -4869,7 +5567,7 @@ public partial class CreateProductResponse } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class CreateTenantCommand { @@ -4890,7 +5588,7 @@ public partial class CreateTenantCommand } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class CreateTenantResponse { @@ -4899,7 +5597,7 @@ public partial class CreateTenantResponse } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class CreateTodoCommand { @@ -4911,7 +5609,7 @@ public partial class CreateTodoCommand } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class CreateTodoResponse { @@ -4920,7 +5618,7 @@ public partial class CreateTodoResponse } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class DisableTenantResponse { @@ -4929,7 +5627,7 @@ public partial class DisableTenantResponse } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class FileUploadCommand { @@ -4944,7 +5642,7 @@ public partial class FileUploadCommand } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class Filter { @@ -4965,7 +5663,7 @@ public partial class Filter } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class ForgotPasswordCommand { @@ -4974,7 +5672,7 @@ public partial class ForgotPasswordCommand } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class GetTodoResponse { @@ -4989,7 +5687,7 @@ public partial class GetTodoResponse } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class PaginationFilter { @@ -5013,7 +5711,7 @@ public partial class PaginationFilter } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class ProductResponse { @@ -5029,9 +5727,12 @@ public partial class ProductResponse [System.Text.Json.Serialization.JsonPropertyName("price")] public double Price { get; set; } = default!; + [System.Text.Json.Serialization.JsonPropertyName("brand")] + public BrandResponse Brand { get; set; } = default!; + } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class ProductResponsePagedList { @@ -5058,7 +5759,7 @@ public partial class ProductResponsePagedList } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class RefreshTokenCommand { @@ -5070,7 +5771,7 @@ public partial class RefreshTokenCommand } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class RegisterUserCommand { @@ -5097,7 +5798,7 @@ public partial class RegisterUserCommand } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class RegisterUserResponse { @@ -5106,7 +5807,7 @@ public partial class RegisterUserResponse } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class ResetPasswordCommand { @@ -5121,7 +5822,7 @@ public partial class ResetPasswordCommand } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class RoleDto { @@ -5139,7 +5840,7 @@ public partial class RoleDto } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class Search { @@ -5151,7 +5852,37 @@ public partial class Search } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class SearchBrandsCommand + { + + [System.Text.Json.Serialization.JsonPropertyName("advancedSearch")] + public Search AdvancedSearch { get; set; } = default!; + + [System.Text.Json.Serialization.JsonPropertyName("keyword")] + public string? Keyword { get; set; } = default!; + + [System.Text.Json.Serialization.JsonPropertyName("advancedFilter")] + public Filter AdvancedFilter { get; set; } = default!; + + [System.Text.Json.Serialization.JsonPropertyName("pageNumber")] + public int PageNumber { get; set; } = default!; + + [System.Text.Json.Serialization.JsonPropertyName("pageSize")] + public int PageSize { get; set; } = default!; + + [System.Text.Json.Serialization.JsonPropertyName("orderBy")] + public System.Collections.Generic.ICollection? OrderBy { get; set; } = default!; + + [System.Text.Json.Serialization.JsonPropertyName("name")] + public string? Name { get; set; } = default!; + + [System.Text.Json.Serialization.JsonPropertyName("description")] + public string? Description { get; set; } = default!; + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class SearchProductsCommand { @@ -5184,7 +5915,7 @@ public partial class SearchProductsCommand } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class TenantDetail { @@ -5211,7 +5942,7 @@ public partial class TenantDetail } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class TodoDto { @@ -5226,7 +5957,7 @@ public partial class TodoDto } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class TodoDtoPagedList { @@ -5253,7 +5984,7 @@ public partial class TodoDtoPagedList } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class ToggleUserStatusCommand { @@ -5265,7 +5996,7 @@ public partial class ToggleUserStatusCommand } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class TokenGenerationCommand { @@ -5277,7 +6008,7 @@ public partial class TokenGenerationCommand } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class TokenResponse { @@ -5292,7 +6023,31 @@ public partial class TokenResponse } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class UpdateBrandCommand + { + + [System.Text.Json.Serialization.JsonPropertyName("id")] + public System.Guid Id { get; set; } = default!; + + [System.Text.Json.Serialization.JsonPropertyName("name")] + public string? Name { get; set; } = default!; + + [System.Text.Json.Serialization.JsonPropertyName("description")] + public string? Description { get; set; } = default!; + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class UpdateBrandResponse + { + + [System.Text.Json.Serialization.JsonPropertyName("id")] + public System.Guid? Id { get; set; } = default!; + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class UpdatePermissionsCommand { @@ -5304,7 +6059,7 @@ public partial class UpdatePermissionsCommand } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class UpdateProductCommand { @@ -5320,9 +6075,12 @@ public partial class UpdateProductCommand [System.Text.Json.Serialization.JsonPropertyName("description")] public string? Description { get; set; } = default!; + [System.Text.Json.Serialization.JsonPropertyName("brandId")] + public System.Guid? BrandId { get; set; } = default!; + } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class UpdateProductResponse { @@ -5331,7 +6089,7 @@ public partial class UpdateProductResponse } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class UpdateTodoCommand { @@ -5346,7 +6104,7 @@ public partial class UpdateTodoCommand } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class UpdateTodoResponse { @@ -5355,7 +6113,7 @@ public partial class UpdateTodoResponse } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class UpdateUserCommand { @@ -5382,7 +6140,7 @@ public partial class UpdateUserCommand } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class UpgradeSubscriptionCommand { @@ -5394,7 +6152,7 @@ public partial class UpgradeSubscriptionCommand } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class UpgradeSubscriptionResponse { @@ -5406,7 +6164,7 @@ public partial class UpgradeSubscriptionResponse } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class UserDetail { @@ -5439,7 +6197,7 @@ public partial class UserDetail } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class UserRoleDetail { @@ -5459,7 +6217,7 @@ public partial class UserRoleDetail - [System.CodeDom.Compiler.GeneratedCode("NSwag", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NSwag", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class ApiException : System.Exception { public int StatusCode { get; private set; } @@ -5482,7 +6240,7 @@ public override string ToString() } } - [System.CodeDom.Compiler.GeneratedCode("NSwag", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + [System.CodeDom.Compiler.GeneratedCode("NSwag", "14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class ApiException : ApiException { public TResult Result { get; private set; } diff --git a/src/apps/blazor/infrastructure/Api/nswag.json b/src/apps/blazor/infrastructure/Api/nswag.json index ac898f089..4d3fb1c43 100644 --- a/src/apps/blazor/infrastructure/Api/nswag.json +++ b/src/apps/blazor/infrastructure/Api/nswag.json @@ -1,5 +1,5 @@ { - "runtime": "WinX64", + "runtime": "Net80", "defaultVariables": null, "documentGenerator": { "fromDocument": {