From 834f5b0dfaa66928c58e58e3b92723038ba60ebe Mon Sep 17 00:00:00 2001 From: Hasibur Rahman Fayez Date: Sun, 7 Dec 2025 23:16:29 +0600 Subject: [PATCH 1/6] Mashrafee Problem Fixed --- .../OtpMail/SendOtpCommandHandler.cs | 34 +++++++++---------- 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/src/Application/SmtpConfigs/OtpMail/SendOtpCommandHandler.cs b/src/Application/SmtpConfigs/OtpMail/SendOtpCommandHandler.cs index f9e5047..61d34a9 100644 --- a/src/Application/SmtpConfigs/OtpMail/SendOtpCommandHandler.cs +++ b/src/Application/SmtpConfigs/OtpMail/SendOtpCommandHandler.cs @@ -52,29 +52,27 @@ public async Task> Handle(SendOtpCommand command, CancellationToken try { - using (var client = new SmtpClient()) - { - SecureSocketOptions sslOption = smtpConfig.EnableSsl - ? SecureSocketOptions.StartTls - : SecureSocketOptions.None; + using var client = new SmtpClient(); + SecureSocketOptions sslOption = smtpConfig.EnableSsl + ? SecureSocketOptions.StartTls + : SecureSocketOptions.None; - await client.ConnectAsync( - smtpConfig.Host, - smtpConfig.Port, - sslOption, - cancellationToken); + await client.ConnectAsync( + smtpConfig.Host, + smtpConfig.Port, + sslOption, + cancellationToken); - await client.AuthenticateAsync( - smtpConfig.Username, - smtpConfig.Password, - cancellationToken); + await client.AuthenticateAsync( + smtpConfig.Username, + smtpConfig.Password, + cancellationToken); - await client.SendAsync(message, cancellationToken); + await client.SendAsync(message, cancellationToken); - await client.DisconnectAsync(true, cancellationToken); + await client.DisconnectAsync(true, cancellationToken); - return Result.Success(otpId); - } + return Result.Success(otpId); } catch (Exception) { From 34606dee808249e7e9dc9b71f760398743dc0854 Mon Sep 17 00:00:00 2001 From: Hasibur Rahman Fayez Date: Sun, 7 Dec 2025 23:42:32 +0600 Subject: [PATCH 2/6] Country Table Done.... --- .../Data/IApplicationDbContext.cs | 2 + .../Countries/Create/CreateCountryCommand.cs | 13 ++++++ .../Create/CreateCountryCommandHandler.cs | 35 +++++++++++++++ .../Create/CreateCountryValidator.cs | 20 +++++++++ .../Countries/Delete/DeleteCountryCommand.cs | 6 +++ .../Delete/DeleteCountryCommandHandler.cs | 37 ++++++++++++++++ .../Delete/DeleteCountryCommandValidator.cs | 12 +++++ .../Countries/Get/GetCountriesQuery.cs | 7 +++ .../Countries/Get/GetCountriesQueryHandler.cs | 36 +++++++++++++++ .../Countries/Get/GetCountryResponse.cs | 10 +++++ .../Countries/GetById/GetCountryByIdQuery.cs | 6 +++ .../GetById/GetCountryByIdQueryHandler.cs | 44 +++++++++++++++++++ .../GetById/GetCountryByIdResponse.cs | 10 +++++ .../Countries/Update/UpdateCountryCommand.cs | 12 +++++ .../Update/UpdateCountryCommandHandler.cs | 41 +++++++++++++++++ .../Update/UpdateCountryCommandValidator.cs | 24 ++++++++++ src/Domain/Countries/Country.cs | 11 +++++ .../Countries/CountryConfiguration.cs | 31 +++++++++++++ .../Database/ApplicationDbContext.cs | 2 + src/Web.Api/Endpoints/Countries/Create.cs | 44 +++++++++++++++++++ src/Web.Api/Endpoints/Countries/Delete.cs | 27 ++++++++++++ src/Web.Api/Endpoints/Countries/Get.cs | 24 ++++++++++ src/Web.Api/Endpoints/Countries/GetById.cs | 25 +++++++++++ src/Web.Api/Endpoints/Countries/Update.cs | 42 ++++++++++++++++++ src/Web.Api/Endpoints/Tags.cs | 1 + 25 files changed, 522 insertions(+) create mode 100644 src/Application/Countries/Create/CreateCountryCommand.cs create mode 100644 src/Application/Countries/Create/CreateCountryCommandHandler.cs create mode 100644 src/Application/Countries/Create/CreateCountryValidator.cs create mode 100644 src/Application/Countries/Delete/DeleteCountryCommand.cs create mode 100644 src/Application/Countries/Delete/DeleteCountryCommandHandler.cs create mode 100644 src/Application/Countries/Delete/DeleteCountryCommandValidator.cs create mode 100644 src/Application/Countries/Get/GetCountriesQuery.cs create mode 100644 src/Application/Countries/Get/GetCountriesQueryHandler.cs create mode 100644 src/Application/Countries/Get/GetCountryResponse.cs create mode 100644 src/Application/Countries/GetById/GetCountryByIdQuery.cs create mode 100644 src/Application/Countries/GetById/GetCountryByIdQueryHandler.cs create mode 100644 src/Application/Countries/GetById/GetCountryByIdResponse.cs create mode 100644 src/Application/Countries/Update/UpdateCountryCommand.cs create mode 100644 src/Application/Countries/Update/UpdateCountryCommandHandler.cs create mode 100644 src/Application/Countries/Update/UpdateCountryCommandValidator.cs create mode 100644 src/Domain/Countries/Country.cs create mode 100644 src/Infrastructure/Countries/CountryConfiguration.cs create mode 100644 src/Web.Api/Endpoints/Countries/Create.cs create mode 100644 src/Web.Api/Endpoints/Countries/Delete.cs create mode 100644 src/Web.Api/Endpoints/Countries/Get.cs create mode 100644 src/Web.Api/Endpoints/Countries/GetById.cs create mode 100644 src/Web.Api/Endpoints/Countries/Update.cs diff --git a/src/Application/Abstractions/Data/IApplicationDbContext.cs b/src/Application/Abstractions/Data/IApplicationDbContext.cs index 3fd77a6..d66e1e9 100644 --- a/src/Application/Abstractions/Data/IApplicationDbContext.cs +++ b/src/Application/Abstractions/Data/IApplicationDbContext.cs @@ -2,6 +2,7 @@ using Domain.AuditLogs; using Domain.Businesses; using Domain.BusinessMembers; +using Domain.Countries; using Domain.Customers; using Domain.EmailVerification; using Domain.MfaLogs; @@ -43,6 +44,7 @@ public interface IApplicationDbContext DbSet MfaSettings { get; } DbSet Otp { get; } DbSet SmtpConfig { get; } + DbSet Countries { get; } EntityEntry Entry(object entity); Task SaveChangesAsync(CancellationToken cancellationToken = default); } diff --git a/src/Application/Countries/Create/CreateCountryCommand.cs b/src/Application/Countries/Create/CreateCountryCommand.cs new file mode 100644 index 0000000..cca7bae --- /dev/null +++ b/src/Application/Countries/Create/CreateCountryCommand.cs @@ -0,0 +1,13 @@ +using Application.Abstractions.Messaging; +using SharedKernel; + +namespace Application.Countries.Create; + +public class CreateCountryCommand : ICommand +{ + public string Name { get; set; } + public string Capital { get; set; } + public string PhoneCode { get; set; } + public bool IsActive { get; set; } +}; + diff --git a/src/Application/Countries/Create/CreateCountryCommandHandler.cs b/src/Application/Countries/Create/CreateCountryCommandHandler.cs new file mode 100644 index 0000000..f1de301 --- /dev/null +++ b/src/Application/Countries/Create/CreateCountryCommandHandler.cs @@ -0,0 +1,35 @@ +using Application.Abstractions.Data; +using Application.Abstractions.Messaging; +using Domain.Countries; +using SharedKernel; + +namespace Application.Countries.Create; + +public class CreateCountryCommandHandler + : ICommandHandler +{ + private readonly IApplicationDbContext _context; + + public CreateCountryCommandHandler(IApplicationDbContext context) + { + _context = context; + } + + public async Task> Handle( + CreateCountryCommand request, + CancellationToken cancellationToken) + { + var country = new Country + { + Id = Guid.NewGuid(), + Name = request.Name, + Capital = request.Capital, + PhoneCode = request.PhoneCode, + IsActive = request.IsActive + }; + + await _context.Countries.AddAsync(country, cancellationToken); + await _context.SaveChangesAsync(cancellationToken); + return Result.Success(country.Id); + } +} diff --git a/src/Application/Countries/Create/CreateCountryValidator.cs b/src/Application/Countries/Create/CreateCountryValidator.cs new file mode 100644 index 0000000..ff07c2a --- /dev/null +++ b/src/Application/Countries/Create/CreateCountryValidator.cs @@ -0,0 +1,20 @@ +using FluentValidation; + +namespace Application.Countries.Create; + +public class CreateCountryValidator : AbstractValidator +{ + public CreateCountryValidator() + { + RuleFor(x => x.Name) + .NotEmpty() + .MaximumLength(150); + + RuleFor(x => x.Capital) + .MaximumLength(150); + + RuleFor(x => x.PhoneCode) + .NotEmpty() + .MaximumLength(20); + } +} diff --git a/src/Application/Countries/Delete/DeleteCountryCommand.cs b/src/Application/Countries/Delete/DeleteCountryCommand.cs new file mode 100644 index 0000000..50d8ffd --- /dev/null +++ b/src/Application/Countries/Delete/DeleteCountryCommand.cs @@ -0,0 +1,6 @@ +using Application.Abstractions.Messaging; + +namespace Application.Countries.Delete; + +public sealed record DeleteCountryCommand(Guid Id) : ICommand; + diff --git a/src/Application/Countries/Delete/DeleteCountryCommandHandler.cs b/src/Application/Countries/Delete/DeleteCountryCommandHandler.cs new file mode 100644 index 0000000..6ed59c7 --- /dev/null +++ b/src/Application/Countries/Delete/DeleteCountryCommandHandler.cs @@ -0,0 +1,37 @@ +using Application.Abstractions.Data; +using Application.Abstractions.Messaging; +using Domain.Countries; +using Microsoft.EntityFrameworkCore; +using SharedKernel; + +namespace Application.Countries.Delete; + +internal sealed class DeleteCountryCommandHandler : ICommandHandler +{ + private readonly IApplicationDbContext _context; + + public DeleteCountryCommandHandler(IApplicationDbContext context) + { + _context = context; + } + + public async Task Handle(DeleteCountryCommand command, CancellationToken cancellationToken) + { + Country? country = await _context.Countries + .SingleOrDefaultAsync(c => c.Id == command.Id, cancellationToken); + + if (country is null) + { + return Result.Failure( + Error.NotFound( + "Country.NotFound", + $"Country with Id {command.Id} not found." + ) + ); + } + + _context.Countries.Remove(country); + await _context.SaveChangesAsync(cancellationToken); + return Result.Success(); + } +} diff --git a/src/Application/Countries/Delete/DeleteCountryCommandValidator.cs b/src/Application/Countries/Delete/DeleteCountryCommandValidator.cs new file mode 100644 index 0000000..6bf309d --- /dev/null +++ b/src/Application/Countries/Delete/DeleteCountryCommandValidator.cs @@ -0,0 +1,12 @@ +using FluentValidation; + +namespace Application.Countries.Delete; + +public sealed class DeleteCountryCommandValidator : AbstractValidator +{ + public DeleteCountryCommandValidator() + { + RuleFor(x => x.Id) + .NotEmpty().WithMessage("Country Id is required."); + } +} diff --git a/src/Application/Countries/Get/GetCountriesQuery.cs b/src/Application/Countries/Get/GetCountriesQuery.cs new file mode 100644 index 0000000..b6574e7 --- /dev/null +++ b/src/Application/Countries/Get/GetCountriesQuery.cs @@ -0,0 +1,7 @@ +using Application.Abstractions.Messaging; +using Application.Countries.Get; +using SharedKernel; + +namespace Application.Countries.Get; + +public sealed record GetCountriesQuery() : IQuery>; diff --git a/src/Application/Countries/Get/GetCountriesQueryHandler.cs b/src/Application/Countries/Get/GetCountriesQueryHandler.cs new file mode 100644 index 0000000..8944e1b --- /dev/null +++ b/src/Application/Countries/Get/GetCountriesQueryHandler.cs @@ -0,0 +1,36 @@ +using Application.Abstractions.Data; +using Application.Abstractions.Messaging; +using Application.Businesses.Get; +using Microsoft.EntityFrameworkCore; +using SharedKernel; + +namespace Application.Countries.Get; + +internal sealed class GetCountriesQueryHandler + : IQueryHandler> +{ + private readonly IApplicationDbContext _context; + + public GetCountriesQueryHandler(IApplicationDbContext context) + { + _context = context; + } + + public async Task>> Handle( + GetCountriesQuery request, + CancellationToken cancellationToken) + { + List countries = await _context.Countries + .AsNoTracking() + .Select(b => new GetCountryResponse + { + Id = b.Id, + Name = b.Name, + Capital = b.Capital, + PhoneCode = b.PhoneCode, + IsActive = b.IsActive + }) + .ToListAsync(cancellationToken); + return Result.Success(countries); + } +} diff --git a/src/Application/Countries/Get/GetCountryResponse.cs b/src/Application/Countries/Get/GetCountryResponse.cs new file mode 100644 index 0000000..b16f8e8 --- /dev/null +++ b/src/Application/Countries/Get/GetCountryResponse.cs @@ -0,0 +1,10 @@ +namespace Application.Countries.Get; + +public sealed class GetCountryResponse +{ + public Guid Id { get; set; } + public string Name { get; set; } + public string Capital { get; set; } + public string PhoneCode { get; set; } + public bool IsActive { get; set; } +} diff --git a/src/Application/Countries/GetById/GetCountryByIdQuery.cs b/src/Application/Countries/GetById/GetCountryByIdQuery.cs new file mode 100644 index 0000000..89efaf6 --- /dev/null +++ b/src/Application/Countries/GetById/GetCountryByIdQuery.cs @@ -0,0 +1,6 @@ +using Application.Abstractions.Messaging; +using Application.Businesses.GetById; + +namespace Application.Countries.GetById; + +public sealed record GetCountryByIdQuery(Guid Id) : IQuery; diff --git a/src/Application/Countries/GetById/GetCountryByIdQueryHandler.cs b/src/Application/Countries/GetById/GetCountryByIdQueryHandler.cs new file mode 100644 index 0000000..76d3605 --- /dev/null +++ b/src/Application/Countries/GetById/GetCountryByIdQueryHandler.cs @@ -0,0 +1,44 @@ +using Application.Abstractions.Data; +using Application.Abstractions.Messaging; +using Microsoft.EntityFrameworkCore; +using SharedKernel; + +namespace Application.Countries.GetById; + +internal sealed class GetCountryByIdQueryHandler : IQueryHandler +{ + private readonly IApplicationDbContext _context; + + public GetCountryByIdQueryHandler(IApplicationDbContext context) + { + _context = context; + } + + public async Task> Handle(GetCountryByIdQuery request, CancellationToken cancellationToken) + { + GetCountryByIdResponse country = await _context.Countries + .AsNoTracking() + .Where(b => b.Id == request.Id) + .Select(b => new GetCountryByIdResponse + { + Id = b.Id, + Name = b.Name, + Capital = b.Capital, + PhoneCode = b.PhoneCode, + IsActive = b.IsActive + }) + .SingleOrDefaultAsync(cancellationToken); + + if (country is null) + { + return Result.Failure( + Error.NotFound( + "Country.NotFound", + $"Country with Id {request.Id} not found." + ) + ); + } + + return Result.Success(country); + } +} diff --git a/src/Application/Countries/GetById/GetCountryByIdResponse.cs b/src/Application/Countries/GetById/GetCountryByIdResponse.cs new file mode 100644 index 0000000..98e492b --- /dev/null +++ b/src/Application/Countries/GetById/GetCountryByIdResponse.cs @@ -0,0 +1,10 @@ +namespace Application.Countries.GetById; + +public sealed class GetCountryByIdResponse +{ + public Guid Id { get; set; } + public string Name { get; set; } + public string Capital { get; set; } + public string PhoneCode { get; set; } + public bool IsActive { get; set; } +} diff --git a/src/Application/Countries/Update/UpdateCountryCommand.cs b/src/Application/Countries/Update/UpdateCountryCommand.cs new file mode 100644 index 0000000..90d4122 --- /dev/null +++ b/src/Application/Countries/Update/UpdateCountryCommand.cs @@ -0,0 +1,12 @@ +using Application.Abstractions.Messaging; + +namespace Application.Countries.Update; + +public sealed class UpdateCountryCommand() : ICommand +{ + public Guid Id { get; set; } + public string Name { get; set; } + public string Capital { get; set; } + public string PhoneCode { get; set; } + public bool IsActive { get; set; } +} diff --git a/src/Application/Countries/Update/UpdateCountryCommandHandler.cs b/src/Application/Countries/Update/UpdateCountryCommandHandler.cs new file mode 100644 index 0000000..3534094 --- /dev/null +++ b/src/Application/Countries/Update/UpdateCountryCommandHandler.cs @@ -0,0 +1,41 @@ +using Application.Abstractions.Data; +using Application.Abstractions.Messaging; +using Domain.Countries; +using Microsoft.EntityFrameworkCore; +using SharedKernel; + +namespace Application.Countries.Update; + +internal sealed class UpdateCountryCommandHandler : ICommandHandler +{ + private readonly IApplicationDbContext _context; + + public UpdateCountryCommandHandler(IApplicationDbContext context) + { + _context = context; + } + + public async Task Handle(UpdateCountryCommand command, CancellationToken cancellationToken) + { + Country? country = await _context.Countries + .FirstOrDefaultAsync(c => c.Id == command.Id, cancellationToken); + + if (country is null) + { + return Result.Failure( + Error.NotFound( + "Country.NotFound", + $"Country with Id {command.Id} not found." + ) + ); + } + + country.Name = command.Name; + country.Capital = command.Capital; + country.PhoneCode = command.PhoneCode; + country.IsActive = command.IsActive; + + await _context.SaveChangesAsync(cancellationToken); + return Result.Success(); + } +} diff --git a/src/Application/Countries/Update/UpdateCountryCommandValidator.cs b/src/Application/Countries/Update/UpdateCountryCommandValidator.cs new file mode 100644 index 0000000..0c2882a --- /dev/null +++ b/src/Application/Countries/Update/UpdateCountryCommandValidator.cs @@ -0,0 +1,24 @@ +using FluentValidation; + +namespace Application.Countries.Update; + + +public sealed class UpdateCountryCommandValidator : AbstractValidator +{ + public UpdateCountryCommandValidator() + { + RuleFor(x => x.Id) + .NotEmpty().WithMessage("Country Id is required."); + + RuleFor(x => x.Name) + .NotEmpty().WithMessage("Country name is required.") + .MaximumLength(150); + + RuleFor(x => x.Capital) + .MaximumLength(150); + + RuleFor(x => x.PhoneCode) + .NotEmpty() + .MaximumLength(20); + } +} diff --git a/src/Domain/Countries/Country.cs b/src/Domain/Countries/Country.cs new file mode 100644 index 0000000..37d9b26 --- /dev/null +++ b/src/Domain/Countries/Country.cs @@ -0,0 +1,11 @@ +namespace Domain.Countries; + +public class Country +{ + public Guid Id { get; set; } + public string Name { get; set; } + public string Capital { get; set; } + public string PhoneCode { get; set; } + public bool IsActive { get; set; } +} + diff --git a/src/Infrastructure/Countries/CountryConfiguration.cs b/src/Infrastructure/Countries/CountryConfiguration.cs new file mode 100644 index 0000000..134d711 --- /dev/null +++ b/src/Infrastructure/Countries/CountryConfiguration.cs @@ -0,0 +1,31 @@ +using Domain.Countries; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace Infrastructure.Countries; + +public class CountryConfiguration : IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder builder) + { + builder.ToTable("countries"); + + builder.HasKey(x => x.Id); + + builder.Property(x => x.Id) + .IsRequired(); + + builder.Property(x => x.Name) + .IsRequired() + .HasMaxLength(150); + + builder.Property(x => x.Capital) + .HasMaxLength(150); + + builder.Property(x => x.PhoneCode) + .HasMaxLength(20); + + builder.Property(x => x.IsActive) + .IsRequired(); + } +} diff --git a/src/Infrastructure/Database/ApplicationDbContext.cs b/src/Infrastructure/Database/ApplicationDbContext.cs index 981f0fa..349f4bf 100644 --- a/src/Infrastructure/Database/ApplicationDbContext.cs +++ b/src/Infrastructure/Database/ApplicationDbContext.cs @@ -3,6 +3,7 @@ using Domain.AuditLogs; using Domain.Businesses; using Domain.BusinessMembers; +using Domain.Countries; using Domain.Customers; using Domain.EmailVerification; using Domain.MfaLogs; @@ -62,6 +63,7 @@ public sealed class ApplicationDbContext( public DbSet MfaSettings { get; set; } public DbSet Otp { get; set; } public DbSet SmtpConfig { get; set; } + public DbSet Countries { get; set; } public new EntityEntry Entry(object entity) => base.Entry(entity); diff --git a/src/Web.Api/Endpoints/Countries/Create.cs b/src/Web.Api/Endpoints/Countries/Create.cs new file mode 100644 index 0000000..421d547 --- /dev/null +++ b/src/Web.Api/Endpoints/Countries/Create.cs @@ -0,0 +1,44 @@ +using Application.Abstractions.Messaging; +using Application.Countries.Create; +using SharedKernel; +using Web.Api.Extensions; +using Web.Api.Infrastructure; + +namespace Web.Api.Endpoints.Countries; + +public class Create : IEndpoint +{ + public sealed class Request + { + public string Name { get; set; } + public string Capital { get; set; } + public string PhoneCode { get; set; } + public bool IsActive { get; set; } + } + + public void MapEndpoint(IEndpointRouteBuilder app) + { + app.MapPost("/countries", async ( + Request request, + ICommandHandler handler, + CancellationToken cancellationToken) => + { + var command = new CreateCountryCommand + { + Name = request.Name, + Capital = request.Capital, + PhoneCode = request.PhoneCode, + IsActive = request.IsActive, + }; + + Result result = await handler.Handle(command, cancellationToken); + + return result.Match( + id => Results.Created($"/countries/{id}", new { id }), + CustomResults.Problem + ); + }) + .WithTags(Tags.Countries) + .RequireAuthorization(); + } +} diff --git a/src/Web.Api/Endpoints/Countries/Delete.cs b/src/Web.Api/Endpoints/Countries/Delete.cs new file mode 100644 index 0000000..93198a2 --- /dev/null +++ b/src/Web.Api/Endpoints/Countries/Delete.cs @@ -0,0 +1,27 @@ +using Application.Abstractions.Messaging; +using Application.Countries.Delete; +using SharedKernel; +using Web.Api.Extensions; +using Web.Api.Infrastructure; + +namespace Web.Api.Endpoints.Countries; + +internal sealed class Delete : IEndpoint +{ + public void MapEndpoint(IEndpointRouteBuilder app) + { + app.MapDelete("/countries/{id:guid}", async ( + Guid id, + ICommandHandler handler, + CancellationToken cancellationToken) => + { + var command = new DeleteCountryCommand(id); + + Result result = await handler.Handle(command, cancellationToken); + + return result.Match(Results.NoContent, CustomResults.Problem); + }) + .WithTags(Tags.Countries) + .RequireAuthorization(); + } +} diff --git a/src/Web.Api/Endpoints/Countries/Get.cs b/src/Web.Api/Endpoints/Countries/Get.cs new file mode 100644 index 0000000..7ca2236 --- /dev/null +++ b/src/Web.Api/Endpoints/Countries/Get.cs @@ -0,0 +1,24 @@ +using Application.Abstractions.Messaging; +using Application.Countries.Get; +using SharedKernel; +using Web.Api.Extensions; +using Web.Api.Infrastructure; + +namespace Web.Api.Endpoints.Countries; + +public class Get : IEndpoint +{ + public void MapEndpoint(IEndpointRouteBuilder app) + { + app.MapGet("/countries", async ( + IQueryHandler> handler, + CancellationToken cancellationToken) => + { + var query = new GetCountriesQuery(); + Result> result = await handler.Handle(query, cancellationToken); + return result.Match(Results.Ok, CustomResults.Problem); + }) + .WithTags(Tags.Countries) + .RequireAuthorization(); + } +} diff --git a/src/Web.Api/Endpoints/Countries/GetById.cs b/src/Web.Api/Endpoints/Countries/GetById.cs new file mode 100644 index 0000000..c7923aa --- /dev/null +++ b/src/Web.Api/Endpoints/Countries/GetById.cs @@ -0,0 +1,25 @@ +using Application.Abstractions.Messaging; +using Application.Countries.GetById; +using SharedKernel; +using Web.Api.Extensions; +using Web.Api.Infrastructure; + +namespace Web.Api.Endpoints.Countries; + +public class GetById : IEndpoint +{ + public void MapEndpoint(IEndpointRouteBuilder app) + { + app.MapGet("/countries/{id:guid}", async ( + Guid id, + IQueryHandler handler, + CancellationToken cancellationToken) => + { + var query = new GetCountryByIdQuery(id); + Result result = await handler.Handle(query, cancellationToken); + return result.Match(Results.Ok, CustomResults.Problem); + }) + .WithTags(Tags.Countries) + .RequireAuthorization(); + } +} diff --git a/src/Web.Api/Endpoints/Countries/Update.cs b/src/Web.Api/Endpoints/Countries/Update.cs new file mode 100644 index 0000000..1799fb8 --- /dev/null +++ b/src/Web.Api/Endpoints/Countries/Update.cs @@ -0,0 +1,42 @@ +using Application.Abstractions.Messaging; +using Application.Countries.Update; +using SharedKernel; +using Web.Api.Extensions; +using Web.Api.Infrastructure; + +namespace Web.Api.Endpoints.Countries; + +public class Update : IEndpoint +{ + public sealed class Request + { + public string Name { get; set; } + public string Capital { get; set; } + public string PhoneCode { get; set; } + public bool IsActive { get; set; } + } + + public void MapEndpoint(IEndpointRouteBuilder app) + { + app.MapPut("/countries/{id:guid}", static async ( + Guid id, + Request request, + ICommandHandler handler, + CancellationToken cancellationToken) => + { + var command = new UpdateCountryCommand + { + Id = id, + Name = request.Name, + Capital = request.Capital, + PhoneCode = request.PhoneCode, + IsActive = request.IsActive + }; + + Result result = await handler.Handle(command, cancellationToken); + return result.Match(Results.NoContent, CustomResults.Problem); + }) + .WithTags(Tags.Countries) + .RequireAuthorization(); + } +} diff --git a/src/Web.Api/Endpoints/Tags.cs b/src/Web.Api/Endpoints/Tags.cs index 3901f38..8364623 100644 --- a/src/Web.Api/Endpoints/Tags.cs +++ b/src/Web.Api/Endpoints/Tags.cs @@ -19,4 +19,5 @@ public static class Tags public const string SmtpConfig = "SmtpConfig"; public const string Otp = "Otp"; public const string SendMail = "Sent Email"; + public const string Countries = "Countries"; } From c4860b50a2cc00d3126442b1a3df5d4cd7735ff8 Mon Sep 17 00:00:00 2001 From: Hasibur Rahman Fayez Date: Mon, 8 Dec 2025 00:09:38 +0600 Subject: [PATCH 3/6] Problem Fixed... --- src/Application/Countries/Create/CreateCountryCommand.cs | 6 +++--- src/Application/Countries/Get/GetCountriesQuery.cs | 1 - src/Application/Countries/Get/GetCountriesQueryHandler.cs | 1 - src/Application/Countries/Get/GetCountryResponse.cs | 2 +- .../Countries/GetById/GetCountryByIdResponse.cs | 6 +++--- src/Application/Countries/Update/UpdateCountryCommand.cs | 6 +++--- src/Domain/Countries/Country.cs | 8 +++++--- src/Web.Api/Endpoints/Countries/Create.cs | 6 +++--- src/Web.Api/Endpoints/Countries/Update.cs | 6 +++--- 9 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/Application/Countries/Create/CreateCountryCommand.cs b/src/Application/Countries/Create/CreateCountryCommand.cs index cca7bae..f336656 100644 --- a/src/Application/Countries/Create/CreateCountryCommand.cs +++ b/src/Application/Countries/Create/CreateCountryCommand.cs @@ -5,9 +5,9 @@ namespace Application.Countries.Create; public class CreateCountryCommand : ICommand { - public string Name { get; set; } - public string Capital { get; set; } - public string PhoneCode { get; set; } + public string Name { get; set; } = null!; + public string Capital { get; set; } = null!; + public string PhoneCode { get; set; } = null!; public bool IsActive { get; set; } }; diff --git a/src/Application/Countries/Get/GetCountriesQuery.cs b/src/Application/Countries/Get/GetCountriesQuery.cs index b6574e7..110c81a 100644 --- a/src/Application/Countries/Get/GetCountriesQuery.cs +++ b/src/Application/Countries/Get/GetCountriesQuery.cs @@ -1,6 +1,5 @@ using Application.Abstractions.Messaging; using Application.Countries.Get; -using SharedKernel; namespace Application.Countries.Get; diff --git a/src/Application/Countries/Get/GetCountriesQueryHandler.cs b/src/Application/Countries/Get/GetCountriesQueryHandler.cs index 8944e1b..6c83f81 100644 --- a/src/Application/Countries/Get/GetCountriesQueryHandler.cs +++ b/src/Application/Countries/Get/GetCountriesQueryHandler.cs @@ -1,6 +1,5 @@ using Application.Abstractions.Data; using Application.Abstractions.Messaging; -using Application.Businesses.Get; using Microsoft.EntityFrameworkCore; using SharedKernel; diff --git a/src/Application/Countries/Get/GetCountryResponse.cs b/src/Application/Countries/Get/GetCountryResponse.cs index b16f8e8..d99c89e 100644 --- a/src/Application/Countries/Get/GetCountryResponse.cs +++ b/src/Application/Countries/Get/GetCountryResponse.cs @@ -5,6 +5,6 @@ public sealed class GetCountryResponse public Guid Id { get; set; } public string Name { get; set; } public string Capital { get; set; } - public string PhoneCode { get; set; } + public string PhoneCode { get; set; } = null!; public bool IsActive { get; set; } } diff --git a/src/Application/Countries/GetById/GetCountryByIdResponse.cs b/src/Application/Countries/GetById/GetCountryByIdResponse.cs index 98e492b..65c95d7 100644 --- a/src/Application/Countries/GetById/GetCountryByIdResponse.cs +++ b/src/Application/Countries/GetById/GetCountryByIdResponse.cs @@ -3,8 +3,8 @@ public sealed class GetCountryByIdResponse { public Guid Id { get; set; } - public string Name { get; set; } - public string Capital { get; set; } - public string PhoneCode { get; set; } + public string Name { get; set; } = string.Empty; + public string Capital { get; set; } = string.Empty; + public string PhoneCode { get; set; } = string.Empty; public bool IsActive { get; set; } } diff --git a/src/Application/Countries/Update/UpdateCountryCommand.cs b/src/Application/Countries/Update/UpdateCountryCommand.cs index 90d4122..2bdbc82 100644 --- a/src/Application/Countries/Update/UpdateCountryCommand.cs +++ b/src/Application/Countries/Update/UpdateCountryCommand.cs @@ -5,8 +5,8 @@ namespace Application.Countries.Update; public sealed class UpdateCountryCommand() : ICommand { public Guid Id { get; set; } - public string Name { get; set; } - public string Capital { get; set; } - public string PhoneCode { get; set; } + public string Name { get; set; } = null!; + public string Capital { get; set; } = null!; + public string PhoneCode { get; set; } = null!; public bool IsActive { get; set; } } diff --git a/src/Domain/Countries/Country.cs b/src/Domain/Countries/Country.cs index 37d9b26..98a82dc 100644 --- a/src/Domain/Countries/Country.cs +++ b/src/Domain/Countries/Country.cs @@ -1,11 +1,13 @@ -namespace Domain.Countries; +using SharedKernel; -public class Country +namespace Domain.Countries; + +public class Country : Entity { public Guid Id { get; set; } public string Name { get; set; } public string Capital { get; set; } - public string PhoneCode { get; set; } + public string PhoneCode { get; set; } = null!; public bool IsActive { get; set; } } diff --git a/src/Web.Api/Endpoints/Countries/Create.cs b/src/Web.Api/Endpoints/Countries/Create.cs index 421d547..9ca0546 100644 --- a/src/Web.Api/Endpoints/Countries/Create.cs +++ b/src/Web.Api/Endpoints/Countries/Create.cs @@ -10,9 +10,9 @@ public class Create : IEndpoint { public sealed class Request { - public string Name { get; set; } - public string Capital { get; set; } - public string PhoneCode { get; set; } + public string Name { get; set; } = string.Empty; + public string Capital { get; set; } = string.Empty; + public string PhoneCode { get; set; } = string.Empty; public bool IsActive { get; set; } } diff --git a/src/Web.Api/Endpoints/Countries/Update.cs b/src/Web.Api/Endpoints/Countries/Update.cs index 1799fb8..d14af00 100644 --- a/src/Web.Api/Endpoints/Countries/Update.cs +++ b/src/Web.Api/Endpoints/Countries/Update.cs @@ -10,9 +10,9 @@ public class Update : IEndpoint { public sealed class Request { - public string Name { get; set; } - public string Capital { get; set; } - public string PhoneCode { get; set; } + public string Name { get; set; } = null!; + public string Capital { get; set; } = null!; + public string PhoneCode { get; set; } = null!; public bool IsActive { get; set; } } From 8f9ddc817309ac65d2d76d92cc27b0cf3f32b6bd Mon Sep 17 00:00:00 2001 From: Hasibur Rahman Fayez Date: Mon, 8 Dec 2025 00:12:19 +0600 Subject: [PATCH 4/6] GetCountriesQuery.cs Fixed... --- src/Application/Countries/Get/GetCountriesQuery.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Application/Countries/Get/GetCountriesQuery.cs b/src/Application/Countries/Get/GetCountriesQuery.cs index 110c81a..32808e8 100644 --- a/src/Application/Countries/Get/GetCountriesQuery.cs +++ b/src/Application/Countries/Get/GetCountriesQuery.cs @@ -1,5 +1,4 @@ using Application.Abstractions.Messaging; -using Application.Countries.Get; namespace Application.Countries.Get; From bb7d573763925c1b8355abfb926d030ecdfe5b57 Mon Sep 17 00:00:00 2001 From: Hasibur Rahman Fayez Date: Mon, 8 Dec 2025 00:14:04 +0600 Subject: [PATCH 5/6] GetCountryByIdQuery.cs Fixed.... --- src/Application/Countries/GetById/GetCountryByIdQuery.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Application/Countries/GetById/GetCountryByIdQuery.cs b/src/Application/Countries/GetById/GetCountryByIdQuery.cs index 89efaf6..1ce9574 100644 --- a/src/Application/Countries/GetById/GetCountryByIdQuery.cs +++ b/src/Application/Countries/GetById/GetCountryByIdQuery.cs @@ -1,5 +1,4 @@ using Application.Abstractions.Messaging; -using Application.Businesses.GetById; namespace Application.Countries.GetById; From 6fd56fab23290a0c9be94a2d1ff43b5c88227c51 Mon Sep 17 00:00:00 2001 From: Hasibur Rahman Fayez Date: Mon, 8 Dec 2025 14:13:12 +0600 Subject: [PATCH 6/6] Problem Fixed.... --- src/Application/Countries/Create/CreateCountryCommand.cs | 4 ++-- .../Countries/Create/CreateCountryCommandHandler.cs | 2 +- src/Application/Countries/Create/CreateCountryValidator.cs | 2 +- src/Domain/Countries/Country.cs | 6 +++--- src/Infrastructure/Countries/CountryConfiguration.cs | 2 +- src/Web.Api/Endpoints/Countries/Create.cs | 2 +- src/Web.Api/Endpoints/Countries/Get.cs | 2 +- src/Web.Api/Endpoints/Countries/GetById.cs | 2 +- src/Web.Api/Endpoints/Countries/Update.cs | 2 +- 9 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/Application/Countries/Create/CreateCountryCommand.cs b/src/Application/Countries/Create/CreateCountryCommand.cs index f336656..221aaaf 100644 --- a/src/Application/Countries/Create/CreateCountryCommand.cs +++ b/src/Application/Countries/Create/CreateCountryCommand.cs @@ -3,11 +3,11 @@ namespace Application.Countries.Create; -public class CreateCountryCommand : ICommand +public sealed class CreateCountryCommand : ICommand { public string Name { get; set; } = null!; public string Capital { get; set; } = null!; public string PhoneCode { get; set; } = null!; public bool IsActive { get; set; } -}; +} diff --git a/src/Application/Countries/Create/CreateCountryCommandHandler.cs b/src/Application/Countries/Create/CreateCountryCommandHandler.cs index f1de301..e3cc6c6 100644 --- a/src/Application/Countries/Create/CreateCountryCommandHandler.cs +++ b/src/Application/Countries/Create/CreateCountryCommandHandler.cs @@ -5,7 +5,7 @@ namespace Application.Countries.Create; -public class CreateCountryCommandHandler +internal sealed class CreateCountryCommandHandler : ICommandHandler { private readonly IApplicationDbContext _context; diff --git a/src/Application/Countries/Create/CreateCountryValidator.cs b/src/Application/Countries/Create/CreateCountryValidator.cs index ff07c2a..a82e6de 100644 --- a/src/Application/Countries/Create/CreateCountryValidator.cs +++ b/src/Application/Countries/Create/CreateCountryValidator.cs @@ -2,7 +2,7 @@ namespace Application.Countries.Create; -public class CreateCountryValidator : AbstractValidator +public sealed class CreateCountryValidator : AbstractValidator { public CreateCountryValidator() { diff --git a/src/Domain/Countries/Country.cs b/src/Domain/Countries/Country.cs index 98a82dc..2cc8d98 100644 --- a/src/Domain/Countries/Country.cs +++ b/src/Domain/Countries/Country.cs @@ -2,11 +2,11 @@ namespace Domain.Countries; -public class Country : Entity +public sealed class Country : Entity { public Guid Id { get; set; } - public string Name { get; set; } - public string Capital { get; set; } + public string Name { get; set; } = null!; + public string Capital { get; set; } = null!; public string PhoneCode { get; set; } = null!; public bool IsActive { get; set; } } diff --git a/src/Infrastructure/Countries/CountryConfiguration.cs b/src/Infrastructure/Countries/CountryConfiguration.cs index 134d711..1f0d6c0 100644 --- a/src/Infrastructure/Countries/CountryConfiguration.cs +++ b/src/Infrastructure/Countries/CountryConfiguration.cs @@ -4,7 +4,7 @@ namespace Infrastructure.Countries; -public class CountryConfiguration : IEntityTypeConfiguration +internal sealed class CountryConfiguration : IEntityTypeConfiguration { public void Configure(EntityTypeBuilder builder) { diff --git a/src/Web.Api/Endpoints/Countries/Create.cs b/src/Web.Api/Endpoints/Countries/Create.cs index 9ca0546..30dd051 100644 --- a/src/Web.Api/Endpoints/Countries/Create.cs +++ b/src/Web.Api/Endpoints/Countries/Create.cs @@ -6,7 +6,7 @@ namespace Web.Api.Endpoints.Countries; -public class Create : IEndpoint +internal sealed class Create : IEndpoint { public sealed class Request { diff --git a/src/Web.Api/Endpoints/Countries/Get.cs b/src/Web.Api/Endpoints/Countries/Get.cs index 7ca2236..a53d37f 100644 --- a/src/Web.Api/Endpoints/Countries/Get.cs +++ b/src/Web.Api/Endpoints/Countries/Get.cs @@ -6,7 +6,7 @@ namespace Web.Api.Endpoints.Countries; -public class Get : IEndpoint +internal sealed class Get : IEndpoint { public void MapEndpoint(IEndpointRouteBuilder app) { diff --git a/src/Web.Api/Endpoints/Countries/GetById.cs b/src/Web.Api/Endpoints/Countries/GetById.cs index c7923aa..24a4b14 100644 --- a/src/Web.Api/Endpoints/Countries/GetById.cs +++ b/src/Web.Api/Endpoints/Countries/GetById.cs @@ -6,7 +6,7 @@ namespace Web.Api.Endpoints.Countries; -public class GetById : IEndpoint +internal sealed class GetById : IEndpoint { public void MapEndpoint(IEndpointRouteBuilder app) { diff --git a/src/Web.Api/Endpoints/Countries/Update.cs b/src/Web.Api/Endpoints/Countries/Update.cs index d14af00..0ee7626 100644 --- a/src/Web.Api/Endpoints/Countries/Update.cs +++ b/src/Web.Api/Endpoints/Countries/Update.cs @@ -6,7 +6,7 @@ namespace Web.Api.Endpoints.Countries; -public class Update : IEndpoint +internal sealed class Update : IEndpoint { public sealed class Request {