diff --git a/Dockerfile b/Dockerfile index 1ac1775..d7f5031 100644 --- a/Dockerfile +++ b/Dockerfile @@ -28,8 +28,6 @@ COPY ["src/SharedKernel/SharedKernel.csproj", "src/SharedKernel/"] RUN dotnet restore "./src/Web.Api/Web.Api.csproj" COPY . . WORKDIR "/src/src/Web.Api" -RUN dotnet dev-certs https --clean -RUN dotnet dev-certs https RUN dotnet build "./Web.Api.csproj" -c $BUILD_CONFIGURATION -o /app/build # This stage is used to publish the service project to be copied to the final stage diff --git a/README.md b/README.md index 5d34de3..d091bdf 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# AuthServer +# AuthServer with Admin Panel -A modern, production-ready authentication and authorization server built with .NET 9, implementing Clean Architecture principles, CQRS pattern, and Domain-Driven Design (DDD). +A modern, production-ready authentication and authorization server built with .NET 10, implementing Clean Architecture principles, CQRS pattern, and Domain-Driven Design (DDD). ## 🏗️ Architecture @@ -70,7 +70,7 @@ This project follows **Clean Architecture** with clear separation of concerns ac ## 📋 Prerequisites -- [.NET 9 SDK](https://dotnet.microsoft.com/download/dotnet/9.0) +- [.NET 10 SDK](https://dotnet.microsoft.com/download/dotnet/10.0) - [Docker Desktop](https://www.docker.com/products/docker-desktop) (for containerized deployment) - [PostgreSQL 17](https://www.postgresql.org/download/) (if running without Docker) @@ -267,4 +267,4 @@ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file --- -**Built with ❤️ using .NET 9** \ No newline at end of file +**Built with ❤️ using .NET 9** diff --git a/docker-compose.yml b/docker-compose.yml index 326ed49..4c13942 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -12,6 +12,18 @@ services: - ConnectionStrings__Database=Host=localhost;Port=5432;Database=authserver;Username=postgres;Password=pass1234 - FrontendLoginUrl=https://auth.dapplesoft.com/login # Login page of auth server - IssuerUrl=https://authapi.dapplesoft.com # Auth server Backend Url + - AuthServer_AlwaysHTTPS=false + - Cors__AllowedOrigins__0=http://localhost:4200 + - Cors__AllowedOrigins__1=https://localhost:4200 + - Cors__AllowedOrigins__2=http://localhost:40033 + - Cors__AllowedOrigins__3=https://localhost:40003 + - Cors__AllowedOrigins__4=http://auth.dapplesoft.com + - Cors__AllowedOrigins__5=https://auth.dapplesoft.com + - Cors__AllowedOrigins__6=http://authapi.dapplesoft.com + - Cors__AllowedOrigins__7=https://authapi.dapplesoft.com + - KnownProxies__0=127.0.0.1 + - KnownProxies__1=172.18.240.206 + - KnownProxies__2=172.19.0.1 networks: - auth-network restart: unless-stopped diff --git a/docker-local-compose.yml b/docker-local-compose.yml index 34ee251..eeb691a 100644 --- a/docker-local-compose.yml +++ b/docker-local-compose.yml @@ -13,8 +13,8 @@ services: ConnectionStrings__Database: Host=postgres;Port=5432;Database=clean-architecture;Username=postgres;Password=1234 ASPNETCORE_URLS: http://+:8080;http://+:8081 FrontendLoginUrl: https://localhost:4200/login # Login page of auth server - IssuerUrl: http://localhost:5001 # Auth server Backend Url - Jwt__Secret: YOUR_SECURE_GENERATED_SECRET + IssuerUrl: https://localhost:5001 # Auth server Backend Url + AuthServer_AlwaysHTTPS: false Cors__AllowedOrigins__0: "http://localhost:4200" Cors__AllowedOrigins__1: "https://localhost:4200" Cors__AllowedOrigins__2: "http://localhost:40033" @@ -23,6 +23,9 @@ services: Cors__AllowedOrigins__5: "https://auth.dapplesoft.com" Cors__AllowedOrigins__6: "http://authapi.dapplesoft.com" Cors__AllowedOrigins__7: "https://authapi.dapplesoft.com" + KnownProxies__0: "127.0.0.1" + KnownProxies__1: "172.18.240.206" + KnownProxies__2: "172.19.0.1" restart: on-failure depends_on: postgres: diff --git a/src/Application/Abstractions/Data/IApplicationDbContext.cs b/src/Application/Abstractions/Data/IApplicationDbContext.cs index d0defb5..fb92174 100644 --- a/src/Application/Abstractions/Data/IApplicationDbContext.cs +++ b/src/Application/Abstractions/Data/IApplicationDbContext.cs @@ -1,16 +1,10 @@ using Domain.Areas; using Domain.AuditLogs; -using Domain.Businesses; -using Domain.BusinessMembers; using Domain.Countries; -using Domain.Customers; using Domain.Districts; using Domain.EmailVerification; using Domain.Localities; -using Domain.MfaLogs; -using Domain.MfaSettings; using Domain.Otps; -using Domain.PasswordResets; using Domain.Permissions; using Domain.Regions; using Domain.RolePermissions; @@ -18,8 +12,6 @@ using Domain.SmsConfigs; using Domain.SmtpConfigs; using Domain.Todos; -using Domain.UserLoginHistories; -using Domain.UserProfiles; using Domain.Users; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.ChangeTracking; @@ -30,19 +22,11 @@ public interface IApplicationDbContext { DbSet Users { get; } DbSet EmailVerifications { get; } - DbSet PasswordReset { get; } DbSet TodoItems { get; } - DbSet Customers { get; } DbSet Permissions { get; } DbSet RolePermissions { get; } DbSet Roles { get; } - DbSet UserLoginHistory { get; } - DbSet UserProfile { get; } - DbSet Businesses { get; } - DbSet BusinessMembers { get; } DbSet AuditLogs { get; } - DbSet MfaLogs { get; } - DbSet MfaSettings { get; } DbSet Otp { get; } DbSet SmtpConfig { get; } DbSet SmsConfig { get; } diff --git a/src/Application/BusinessMembers/Create/CreateBusinessMemberCommand.cs b/src/Application/BusinessMembers/Create/CreateBusinessMemberCommand.cs deleted file mode 100644 index 63fd0b8..0000000 --- a/src/Application/BusinessMembers/Create/CreateBusinessMemberCommand.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Application.Abstractions.Messaging; - -namespace Application.BusinessMembers.Create; - -public sealed record CreateBusinessMemberCommand( - Guid BusinessId, - Guid UserId, - Guid RoleId -) : ICommand; diff --git a/src/Application/BusinessMembers/Create/CreateBusinessMemberCommandHandler.cs b/src/Application/BusinessMembers/Create/CreateBusinessMemberCommandHandler.cs deleted file mode 100644 index b51bd31..0000000 --- a/src/Application/BusinessMembers/Create/CreateBusinessMemberCommandHandler.cs +++ /dev/null @@ -1,74 +0,0 @@ -using Application.Abstractions.Data; -using Application.Abstractions.Messaging; -using Domain.BusinessMembers; -using Microsoft.EntityFrameworkCore; -using SharedKernel; - -namespace Application.BusinessMembers.Create; - -public sealed class CreateBusinessMemberCommandHandler : ICommandHandler -{ - private readonly IApplicationDbContext _context; - private readonly IDateTimeProvider _dateTimeProvider; - - public CreateBusinessMemberCommandHandler(IApplicationDbContext context, IDateTimeProvider dateTimeProvider) - { - _context = context; - _dateTimeProvider = dateTimeProvider; - } - - public async Task> Handle(CreateBusinessMemberCommand command, CancellationToken cancellationToken) - { - bool businessExists = await _context.Businesses - .AnyAsync(b => b.Id == command.BusinessId, cancellationToken); - - if (!businessExists) - { - return Result.Failure( - Error.NotFound("Business.NotFound", "The specified business does not exist.")); - } - - bool userExists = await _context.Users - .AnyAsync(u => u.Id == command.UserId, cancellationToken); - - if (!userExists) - { - return Result.Failure( - Error.NotFound("User.NotFound", "The specified user does not exist.")); - } - - bool roleExists = await _context.Roles - .AnyAsync(r => r.Id == command.RoleId, cancellationToken); - - if (!roleExists) - { - return Result.Failure( - Error.NotFound("Role.NotFound", "The specified role does not exist.")); - } - - bool alreadyMember = await _context.BusinessMembers - .AnyAsync(m => m.BusinessId == command.BusinessId - && m.UserId == command.UserId, cancellationToken); - - if (alreadyMember) - { - return Result.Failure( - Error.Conflict("BusinessMember.Exists", "This user is already a member of the business.")); - } - - var member = new BusinessMember - { - Id = Guid.NewGuid(), - BusinessId = command.BusinessId, - UserId = command.UserId, - RoleId = command.RoleId, - JoinedAt = _dateTimeProvider.UtcNow - }; - - await _context.BusinessMembers.AddAsync(member, cancellationToken); - await _context.SaveChangesAsync(cancellationToken); - - return Result.Success(member.Id); - } - -} diff --git a/src/Application/BusinessMembers/Create/CreateBusinessMemberCommandValidator.cs b/src/Application/BusinessMembers/Create/CreateBusinessMemberCommandValidator.cs deleted file mode 100644 index 63c6cc5..0000000 --- a/src/Application/BusinessMembers/Create/CreateBusinessMemberCommandValidator.cs +++ /dev/null @@ -1,16 +0,0 @@ -using FluentValidation; - -namespace Application.BusinessMembers.Create; - -public sealed class CreateBusinessMemberCommandValidator : AbstractValidator -{ - public CreateBusinessMemberCommandValidator() - { - RuleFor(x => x.BusinessId) - .NotEmpty().WithMessage("BusinessId is required."); - RuleFor(x => x.UserId) - .NotEmpty().WithMessage("UserId is required."); - RuleFor(x => x.RoleId) - .NotEmpty().WithMessage("RoleId is required."); - } -} diff --git a/src/Application/BusinessMembers/Delete/DeleteBusinessMemberCommand.cs b/src/Application/BusinessMembers/Delete/DeleteBusinessMemberCommand.cs deleted file mode 100644 index eb80b5e..0000000 --- a/src/Application/BusinessMembers/Delete/DeleteBusinessMemberCommand.cs +++ /dev/null @@ -1,5 +0,0 @@ -using Application.Abstractions.Messaging; - -namespace Application.BusinessMembers.Delete; - -public sealed record DeleteBusinessMemberCommand(Guid Id) : ICommand; diff --git a/src/Application/BusinessMembers/Delete/DeleteBusinessMemberCommandHandler.cs b/src/Application/BusinessMembers/Delete/DeleteBusinessMemberCommandHandler.cs deleted file mode 100644 index 3353a59..0000000 --- a/src/Application/BusinessMembers/Delete/DeleteBusinessMemberCommandHandler.cs +++ /dev/null @@ -1,34 +0,0 @@ -using Application.Abstractions.Data; -using Application.Abstractions.Messaging; -using Microsoft.EntityFrameworkCore; -using SharedKernel; - -namespace Application.BusinessMembers.Delete; - -public sealed class DeleteBusinessMemberCommandHandler - : ICommandHandler -{ - private readonly IApplicationDbContext _context; - public DeleteBusinessMemberCommandHandler(IApplicationDbContext context) - { - _context = context; - } - - public async Task> Handle( - DeleteBusinessMemberCommand command, - CancellationToken cancellationToken) - { - Domain.BusinessMembers.BusinessMember? member = await _context.BusinessMembers - .FirstOrDefaultAsync(m => m.Id == command.Id, cancellationToken); - - if (member is null) - { - return Result.Failure( - Error.NotFound("BusinessMember.NotFound", "Business member not found")); - } - - _context.BusinessMembers.Remove(member); - await _context.SaveChangesAsync(cancellationToken); - return Result.Success(command.Id); - } -} diff --git a/src/Application/BusinessMembers/Delete/DeleteBusinessMemberCommandValidator.cs b/src/Application/BusinessMembers/Delete/DeleteBusinessMemberCommandValidator.cs deleted file mode 100644 index d7ead8f..0000000 --- a/src/Application/BusinessMembers/Delete/DeleteBusinessMemberCommandValidator.cs +++ /dev/null @@ -1,13 +0,0 @@ -using FluentValidation; - -namespace Application.BusinessMembers.Delete; - -public sealed class DeleteBusinessMemberCommandValidator - : AbstractValidator -{ - public DeleteBusinessMemberCommandValidator() - { - RuleFor(x => x.Id) - .NotEmpty().WithMessage("Id is required."); - } -} diff --git a/src/Application/BusinessMembers/Get/BusinessMemberResponse.cs b/src/Application/BusinessMembers/Get/BusinessMemberResponse.cs deleted file mode 100644 index cb13f98..0000000 --- a/src/Application/BusinessMembers/Get/BusinessMemberResponse.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Application.BusinessMembers.Get; - -public sealed class BusinessMemberResponse -{ - public Guid Id { get; set; } - public Guid BusinessId { get; set; } - public Guid UserId { get; set; } - public Guid RoleId { get; set; } - public DateTime JoinedAt { get; set; } -} diff --git a/src/Application/BusinessMembers/Get/GetBusinessMembersQuery.cs b/src/Application/BusinessMembers/Get/GetBusinessMembersQuery.cs deleted file mode 100644 index 0e66066..0000000 --- a/src/Application/BusinessMembers/Get/GetBusinessMembersQuery.cs +++ /dev/null @@ -1,8 +0,0 @@ -using Application.Abstractions.Messaging; - -namespace Application.BusinessMembers.Get; - -public sealed record GetBusinessMembersQuery() : IQuery> -{ - -} diff --git a/src/Application/BusinessMembers/Get/GetBusinessMembersQueryHandler.cs b/src/Application/BusinessMembers/Get/GetBusinessMembersQueryHandler.cs deleted file mode 100644 index 960e526..0000000 --- a/src/Application/BusinessMembers/Get/GetBusinessMembersQueryHandler.cs +++ /dev/null @@ -1,32 +0,0 @@ -using Application.Abstractions.Data; -using Application.Abstractions.Messaging; -using Microsoft.EntityFrameworkCore; -using SharedKernel; - -namespace Application.BusinessMembers.Get; - -internal sealed class GetAllBusinessMembersQueryHandler : IQueryHandler> -{ - private readonly IApplicationDbContext _context; - public GetAllBusinessMembersQueryHandler(IApplicationDbContext context) - { - _context = context; - } - - public async Task>> Handle(GetBusinessMembersQuery query, CancellationToken cancellationToken) - { - List members = await _context.BusinessMembers - .Select(bm => new BusinessMemberResponse - { - Id = bm.Id, - BusinessId = bm.BusinessId, - UserId = bm.UserId, - RoleId = bm.RoleId, - JoinedAt = bm.JoinedAt - }) - .ToListAsync(cancellationToken); - return Result.Success(members); - } -} - - diff --git a/src/Application/BusinessMembers/GetById/BusinessMemberResponse.cs b/src/Application/BusinessMembers/GetById/BusinessMemberResponse.cs deleted file mode 100644 index 3df878c..0000000 --- a/src/Application/BusinessMembers/GetById/BusinessMemberResponse.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Application.BusinessMembers.GetById; - -public sealed class BusinessMemberResponse -{ - public Guid Id { get; set; } - public Guid BusinessId { get; set; } - public Guid UserId { get; set; } - public Guid RoleId { get; set; } - public DateTime JoinedAt { get; set; } -} diff --git a/src/Application/BusinessMembers/GetById/GetBusinessMemberByIdQuery.cs b/src/Application/BusinessMembers/GetById/GetBusinessMemberByIdQuery.cs deleted file mode 100644 index ee99d35..0000000 --- a/src/Application/BusinessMembers/GetById/GetBusinessMemberByIdQuery.cs +++ /dev/null @@ -1,4 +0,0 @@ -using Application.Abstractions.Messaging; - -namespace Application.BusinessMembers.GetById; -public sealed record GetBusinessMemberByIdQuery(Guid Id) : IQuery; diff --git a/src/Application/BusinessMembers/GetById/GetBusinessMemberByIdQueryHandler.cs b/src/Application/BusinessMembers/GetById/GetBusinessMemberByIdQueryHandler.cs deleted file mode 100644 index fdfa8e4..0000000 --- a/src/Application/BusinessMembers/GetById/GetBusinessMemberByIdQueryHandler.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Application.Abstractions.Data; -using Application.Abstractions.Messaging; -using Microsoft.EntityFrameworkCore; -using SharedKernel; - -namespace Application.BusinessMembers.GetById; - -internal sealed class GetBusinessMemberByIdQueryHandler : IQueryHandler -{ - private readonly IApplicationDbContext _context; - - public GetBusinessMemberByIdQueryHandler(IApplicationDbContext context) - { - _context = context; - } - - public async Task> Handle(GetBusinessMemberByIdQuery query, CancellationToken cancellationToken) - { - BusinessMemberResponse? member = await _context.BusinessMembers - .Where(bm => bm.Id == query.Id) - .Select(bm => new BusinessMemberResponse - { - Id = bm.Id, - BusinessId = bm.BusinessId, - UserId = bm.UserId, - RoleId = bm.RoleId, - JoinedAt = bm.JoinedAt - }) - .FirstOrDefaultAsync(cancellationToken); - - if (member == null) - { - return Result.Failure( - SharedKernel.Error.NotFound("BusinessMember.NotFound", "The specified business member does not exist.") - ); - } - - return Result.Success(member); - } -} diff --git a/src/Application/BusinessMembers/Update/UpdateBusinessMemberCommand.cs b/src/Application/BusinessMembers/Update/UpdateBusinessMemberCommand.cs deleted file mode 100644 index 49b192f..0000000 --- a/src/Application/BusinessMembers/Update/UpdateBusinessMemberCommand.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Application.Abstractions.Messaging; - -namespace Application.BusinessMembers.Update; - -public sealed record UpdateBusinessMemberCommand( - Guid Id, - Guid BusinessId, - Guid UserId, - Guid RoleId -) : ICommand; diff --git a/src/Application/BusinessMembers/Update/UpdateBusinessMemberCommandHandler.cs b/src/Application/BusinessMembers/Update/UpdateBusinessMemberCommandHandler.cs deleted file mode 100644 index b87c325..0000000 --- a/src/Application/BusinessMembers/Update/UpdateBusinessMemberCommandHandler.cs +++ /dev/null @@ -1,36 +0,0 @@ -using Application.Abstractions.Data; -using Application.Abstractions.Messaging; -using Microsoft.EntityFrameworkCore; -using SharedKernel; - -namespace Application.BusinessMembers.Update; - -internal sealed class UpdateBusinessMemberCommandHandler : ICommandHandler -{ - private readonly IApplicationDbContext _context; - - public UpdateBusinessMemberCommandHandler(IApplicationDbContext context) - { - _context = context; - } - - public async Task> Handle(UpdateBusinessMemberCommand command, CancellationToken cancellationToken) - { - Domain.BusinessMembers.BusinessMember? member = await _context.BusinessMembers - .FirstOrDefaultAsync(bm => bm.Id == command.Id, cancellationToken); - - if (member == null) - { - return Result.Failure( - Error.NotFound("BusinessMember.NotFound", "The specified business member does not exist.") - ); - } - - member.BusinessId = command.BusinessId; - member.UserId = command.UserId; - member.RoleId = command.RoleId; - - await _context.SaveChangesAsync(cancellationToken); - return Result.Success(member.Id); - } -} diff --git a/src/Application/Businesses/Create/CreateBusinessCommand.cs b/src/Application/Businesses/Create/CreateBusinessCommand.cs deleted file mode 100644 index 5edff3e..0000000 --- a/src/Application/Businesses/Create/CreateBusinessCommand.cs +++ /dev/null @@ -1,14 +0,0 @@ -using Application.Abstractions.Messaging; -using Domain.Businesses; - -namespace Application.Businesses.Create; - -public class CreateBusinessCommand : ICommand -{ - public Guid OwnerUserId { get; set; } - public string BusinessName { get; set; } - public string IndustryType { get; set; } - public string LogoUrl { get; set; } - public BusinessStatus Status { get; set; } -} - diff --git a/src/Application/Businesses/Create/CreateBusinessCommandHandler.cs b/src/Application/Businesses/Create/CreateBusinessCommandHandler.cs deleted file mode 100644 index 3a5e700..0000000 --- a/src/Application/Businesses/Create/CreateBusinessCommandHandler.cs +++ /dev/null @@ -1,34 +0,0 @@ -using Application.Abstractions.Data; -using Application.Abstractions.Messaging; -using Domain.Businesses; -using SharedKernel; - -namespace Application.Businesses.Create; - -public class CreateBusinessCommandHandler : ICommandHandler -{ - private readonly IApplicationDbContext _context; - public CreateBusinessCommandHandler(IApplicationDbContext context) - { - _context = context; - } - - public async Task> Handle(CreateBusinessCommand request, CancellationToken cancellationToken) - { - - var business = new Business - { - Id = Guid.NewGuid(), - OwnerUserId = request.OwnerUserId, - BusinessName = request.BusinessName, - IndustryType = request.IndustryType, - LogoUrl = request.LogoUrl, - Status = request.Status, - CreatedAt = DateTime.UtcNow - }; - - _context.Businesses.Add(business); - await _context.SaveChangesAsync(cancellationToken); - return Result.Success(business.Id); - } -} diff --git a/src/Application/Businesses/Create/CreateBusinessValidator.cs b/src/Application/Businesses/Create/CreateBusinessValidator.cs deleted file mode 100644 index eeb0443..0000000 --- a/src/Application/Businesses/Create/CreateBusinessValidator.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Domain.Businesses; -using FluentValidation; - -namespace Application.Businesses.Create; - -public class CreateBusinessValidator : AbstractValidator -{ - public CreateBusinessValidator() - { - RuleFor(x => x.OwnerUserId).NotEmpty().WithMessage("OwnerUserId is required."); - RuleFor(x => x.BusinessName).NotEmpty().MaximumLength(200).WithMessage("BusinessName is required and max 200 chars."); - RuleFor(x => x.IndustryType).MaximumLength(100).WithMessage("IndustryType max 100 chars."); - RuleFor(x => x.LogoUrl).MaximumLength(255).WithMessage("LogoUrl max 255 chars."); - RuleFor(x => x.Status) - .IsInEnum() - .WithMessage("Status must be a valid value (Active or Inactive)."); - } -} diff --git a/src/Application/Businesses/Delete/DeleteBusinessCommand.cs b/src/Application/Businesses/Delete/DeleteBusinessCommand.cs deleted file mode 100644 index 3ad3409..0000000 --- a/src/Application/Businesses/Delete/DeleteBusinessCommand.cs +++ /dev/null @@ -1,5 +0,0 @@ -using Application.Abstractions.Messaging; - -namespace Application.Businesses.Delete; - -public sealed record DeleteBusinessCommand(Guid Id) : ICommand; diff --git a/src/Application/Businesses/Delete/DeleteBusinessCommandHandler.cs b/src/Application/Businesses/Delete/DeleteBusinessCommandHandler.cs deleted file mode 100644 index 881ccb2..0000000 --- a/src/Application/Businesses/Delete/DeleteBusinessCommandHandler.cs +++ /dev/null @@ -1,36 +0,0 @@ -using Application.Abstractions.Data; -using Application.Abstractions.Messaging; -using Domain.Businesses; -using Microsoft.EntityFrameworkCore; -using SharedKernel; - -namespace Application.Businesses.Delete; - -internal sealed class DeleteBusinessCommandHandler : ICommandHandler -{ - private readonly IApplicationDbContext _context; - public DeleteBusinessCommandHandler(IApplicationDbContext context) - { - _context = context; - } - - public async Task Handle(DeleteBusinessCommand command, CancellationToken cancellationToken) - { - Business? business = await _context.Businesses - .SingleOrDefaultAsync(b => b.Id == command.Id, cancellationToken); - - if (business is null) - { - return Result.Failure( - Error.NotFound( - "Business.NotFound", - $"Business with Id {command.Id} not found." - ) - ); - } - - _context.Businesses.Remove(business); - await _context.SaveChangesAsync(cancellationToken); - return Result.Success(); - } -} diff --git a/src/Application/Businesses/Delete/DeleteBusinessCommandValidator.cs b/src/Application/Businesses/Delete/DeleteBusinessCommandValidator.cs deleted file mode 100644 index 3b7d6e4..0000000 --- a/src/Application/Businesses/Delete/DeleteBusinessCommandValidator.cs +++ /dev/null @@ -1,11 +0,0 @@ -using FluentValidation; - -namespace Application.Businesses.Delete; -public sealed class DeleteBusinessCommandValidator : AbstractValidator -{ - public DeleteBusinessCommandValidator() - { - RuleFor(x => x.Id) - .NotEmpty().WithMessage("Business Id is required."); - } -} diff --git a/src/Application/Businesses/Get/GetBusinessResponse.cs b/src/Application/Businesses/Get/GetBusinessResponse.cs deleted file mode 100644 index e1a0e4e..0000000 --- a/src/Application/Businesses/Get/GetBusinessResponse.cs +++ /dev/null @@ -1,14 +0,0 @@ -using Domain.Businesses; - -namespace Application.Businesses.Get; - -public sealed class GetBusinessResponse -{ - public Guid Id { get; set; } - public Guid OwnerUserId { get; set; } - public string BusinessName { get; set; } - public string IndustryType { get; set; } - public string LogoUrl { get; set; } - public BusinessStatus Status { get; set; } - public DateTime CreatedAt { get; set; } -} diff --git a/src/Application/Businesses/Get/GetBusinessesQuery.cs b/src/Application/Businesses/Get/GetBusinessesQuery.cs deleted file mode 100644 index 5f4bc89..0000000 --- a/src/Application/Businesses/Get/GetBusinessesQuery.cs +++ /dev/null @@ -1,6 +0,0 @@ -using Application.Abstractions.Messaging; -using SharedKernel; - -namespace Application.Businesses.Get; - -public sealed record GetBusinessesQuery() : IQuery>; diff --git a/src/Application/Businesses/Get/GetBusinessesQueryHandler.cs b/src/Application/Businesses/Get/GetBusinessesQueryHandler.cs deleted file mode 100644 index 00d0d84..0000000 --- a/src/Application/Businesses/Get/GetBusinessesQueryHandler.cs +++ /dev/null @@ -1,41 +0,0 @@ -using Application.Abstractions.Authentication; -using Application.Abstractions.Data; -using Application.Abstractions.Messaging; -using Microsoft.EntityFrameworkCore; -using SharedKernel; - -namespace Application.Businesses.Get; - -internal sealed class GetBusinessesQueryHandler : IQueryHandler> -{ - private readonly IApplicationDbContext _context; - private readonly IUserContext _userContext; - - public GetBusinessesQueryHandler(IApplicationDbContext context, IUserContext userContext) - { - _context = context; - _userContext = userContext; - } - - public async Task>> Handle( - GetBusinessesQuery request, - CancellationToken cancellationToken) - { - Guid userId = _userContext.UserId; - - List businesses = await _context.Businesses - .Where(b => b.OwnerUserId == userId) - .Select(b => new GetBusinessResponse - { - Id = b.Id, - OwnerUserId = b.OwnerUserId, - BusinessName = b.BusinessName, - IndustryType = b.IndustryType, - LogoUrl = b.LogoUrl, - Status = b.Status, - CreatedAt = b.CreatedAt - }) - .ToListAsync(cancellationToken); - return Result.Success(businesses); - } -} diff --git a/src/Application/Businesses/GetById/GetBusinessByIdQuery.cs b/src/Application/Businesses/GetById/GetBusinessByIdQuery.cs deleted file mode 100644 index 0eaac6f..0000000 --- a/src/Application/Businesses/GetById/GetBusinessByIdQuery.cs +++ /dev/null @@ -1,5 +0,0 @@ -using Application.Abstractions.Messaging; - -namespace Application.Businesses.GetById; - -public sealed record GetBusinessByIdQuery(Guid Id) : IQuery; diff --git a/src/Application/Businesses/GetById/GetBusinessByIdQueryHandler.cs b/src/Application/Businesses/GetById/GetBusinessByIdQueryHandler.cs deleted file mode 100644 index 03a038f..0000000 --- a/src/Application/Businesses/GetById/GetBusinessByIdQueryHandler.cs +++ /dev/null @@ -1,41 +0,0 @@ -using Application.Abstractions.Data; -using Application.Abstractions.Messaging; -using Microsoft.EntityFrameworkCore; -using SharedKernel; - -namespace Application.Businesses.GetById; - -internal sealed class GetBusinessByIdQueryHandler : IQueryHandler -{ - private readonly IApplicationDbContext _context; - public GetBusinessByIdQueryHandler(IApplicationDbContext context) - { - _context = context; - } - - public async Task> Handle(GetBusinessByIdQuery request, CancellationToken cancellationToken) - { - GetBusinessByIdResponse? business = await _context.Businesses - .Where(b => b.Id == request.Id) - .Select(b => new GetBusinessByIdResponse - { - Id = b.Id, - OwnerUserId = b.OwnerUserId, - BusinessName = b.BusinessName, - IndustryType = b.IndustryType, - LogoUrl = b.LogoUrl, - Status = b.Status, - CreatedAt = b.CreatedAt - }) - .FirstOrDefaultAsync(cancellationToken); - - if (business is null) - { - return Result.Failure( - Error.NotFound("Business.NotFound", $"Business with Id {request.Id} not found.") - ); - } - - return Result.Success(business); - } -} diff --git a/src/Application/Businesses/GetById/GetBusinessByIdResponse.cs b/src/Application/Businesses/GetById/GetBusinessByIdResponse.cs deleted file mode 100644 index fde36da..0000000 --- a/src/Application/Businesses/GetById/GetBusinessByIdResponse.cs +++ /dev/null @@ -1,14 +0,0 @@ -using Domain.Businesses; - -namespace Application.Businesses.GetById; - -public sealed class GetBusinessByIdResponse -{ - public Guid Id { get; set; } - public Guid OwnerUserId { get; set; } - public string BusinessName { get; set; } - public string IndustryType { get; set; } - public string LogoUrl { get; set; } - public BusinessStatus Status { get; set; } - public DateTime CreatedAt { get; set; } -} diff --git a/src/Application/Businesses/Update/UpdateBusinessCommand.cs b/src/Application/Businesses/Update/UpdateBusinessCommand.cs deleted file mode 100644 index 6b28de5..0000000 --- a/src/Application/Businesses/Update/UpdateBusinessCommand.cs +++ /dev/null @@ -1,17 +0,0 @@ -using Application.Abstractions.Messaging; -using Domain.Businesses; - -namespace Application.Businesses.Update; - -public sealed class UpdateBusinessCommand() : ICommand -{ - public Guid Id { get; init; } - - public string BusinessName { get; init; } - - public string IndustryType { get; init; } - - public string LogoUrl { get; init; } - - public BusinessStatus Status { get; init; } -} diff --git a/src/Application/Businesses/Update/UpdateBusinessCommandHandler.cs b/src/Application/Businesses/Update/UpdateBusinessCommandHandler.cs deleted file mode 100644 index 8771785..0000000 --- a/src/Application/Businesses/Update/UpdateBusinessCommandHandler.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Application.Abstractions.Data; -using Application.Abstractions.Messaging; -using Microsoft.EntityFrameworkCore; -using SharedKernel; - -namespace Application.Businesses.Update; - -internal sealed class UpdateBusinessCommandHandler : ICommandHandler -{ - private readonly IApplicationDbContext _context; - - public UpdateBusinessCommandHandler(IApplicationDbContext context) - { - _context = context; - } - - public async Task Handle(UpdateBusinessCommand command, CancellationToken cancellationToken) - { - Domain.Businesses.Business? business = await _context.Businesses - .FirstOrDefaultAsync(b => b.Id == command.Id, cancellationToken); - - if (business is null) - { - return Result.Failure( - Error.NotFound( - "Business.NotFound", - $"Business with Id {command.Id} not found." - ) - ); - } - - business.BusinessName = command.BusinessName; - business.IndustryType = command.IndustryType; - business.LogoUrl = command.LogoUrl; - business.Status = command.Status; - - await _context.SaveChangesAsync(cancellationToken); - return Result.Success(); - } -} diff --git a/src/Application/Businesses/Update/UpdateBusinessCommandValidator.cs b/src/Application/Businesses/Update/UpdateBusinessCommandValidator.cs deleted file mode 100644 index 0ddaa99..0000000 --- a/src/Application/Businesses/Update/UpdateBusinessCommandValidator.cs +++ /dev/null @@ -1,41 +0,0 @@ -using FluentValidation; - -namespace Application.Businesses.Update; - -public sealed class UpdateBusinessCommandValidator : AbstractValidator -{ - public UpdateBusinessCommandValidator() - { - RuleFor(x => x.Id) - .NotEmpty().WithMessage("Business Id is required."); - - RuleFor(x => x.BusinessName) - .NotEmpty().WithMessage("Business Name is required."); - - RuleFor(x => x.IndustryType) - .NotEmpty().WithMessage("Industry Type is required."); - - RuleFor(x => x.LogoUrl) - .NotEmpty().WithMessage("Logo Url is required.") - .Must(BeUrl).WithMessage("Logo Url must be a valid url.") - .MaximumLength(255).WithMessage("Url must not exceed 255 char"); - - RuleFor(x => x.Status) - .IsInEnum().WithMessage("Status must be either Active or Inactive."); - } - - private static bool BeUrl(string x) - { - try - { - var uri = new Uri(x); - // Check that it's an absolute URL - return uri.IsAbsoluteUri && - (uri.Scheme == Uri.UriSchemeHttp || uri.Scheme == Uri.UriSchemeHttps); - } - catch - { - return false; - } - } -} diff --git a/src/Application/Customers/Create/CreateCustomerCommand.cs b/src/Application/Customers/Create/CreateCustomerCommand.cs deleted file mode 100644 index 564108d..0000000 --- a/src/Application/Customers/Create/CreateCustomerCommand.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Application.Abstractions.Messaging; - -namespace Application.Customers.Create; - -public sealed class CreateCustomerCommand : ICommand -{ - public string Name { get; set; } - public string Email { get; set; } - public string Address { get; set; } -} diff --git a/src/Application/Customers/Create/CreateCustomerCommandHandler.cs b/src/Application/Customers/Create/CreateCustomerCommandHandler.cs deleted file mode 100644 index 7c3ab60..0000000 --- a/src/Application/Customers/Create/CreateCustomerCommandHandler.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Application.Abstractions.Data; -using Application.Abstractions.Messaging; -using Domain.Customers; -using SharedKernel; - -namespace Application.Customers.Create; - -public class CreateCustomerCommandHandler : ICommandHandler -{ - private readonly IApplicationDbContext context; - - public CreateCustomerCommandHandler(IApplicationDbContext context) - { - this.context = context; - } - - public async Task> Handle(CreateCustomerCommand command, CancellationToken cancellationToken) - { - var existingCustomer = new Customer - { - Name = command.Name, - Email = command.Email, - Address = command.Address - }; - - await context.Customers.AddAsync(existingCustomer, cancellationToken); - await context.SaveChangesAsync(cancellationToken); - - return Result.Success(existingCustomer.Id); - } -} diff --git a/src/Application/Customers/Create/CreateCustomerCommandValidator.cs b/src/Application/Customers/Create/CreateCustomerCommandValidator.cs deleted file mode 100644 index c8d3702..0000000 --- a/src/Application/Customers/Create/CreateCustomerCommandValidator.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using FluentValidation; - -namespace Application.Customers.Create; - -public class CreateCustomerValidator : AbstractValidator -{ - public CreateCustomerValidator() - { - RuleFor(c => c.Name) - .NotEmpty() - .WithMessage("Name is required."); - - RuleFor(c => c.Email) - .NotEmpty() - .WithMessage("Email is required.") - .EmailAddress() - .WithMessage("Invalid email format."); - - RuleFor(c => c.Address) - .NotEmpty() - .WithMessage("Address is required."); - } -} diff --git a/src/Application/MfaLogs/Create/CreateMfaLogCommand.cs b/src/Application/MfaLogs/Create/CreateMfaLogCommand.cs deleted file mode 100644 index 6b09bc9..0000000 --- a/src/Application/MfaLogs/Create/CreateMfaLogCommand.cs +++ /dev/null @@ -1,13 +0,0 @@ -using Application.Abstractions.Messaging; -using Domain.MfaLogs; - -namespace Application.MfaLogs.Create; - -public sealed class CreateMfaLogCommand : ICommand -{ - public Guid UserId { get; set; } - public DateTime LoginTime { get; set; } = DateTime.UtcNow; - public string IpAddress { get; set; } = string.Empty; - public string Device { get; set; } = string.Empty; - public MfaLogStatus Status { get; set; } // Use enum directly -} diff --git a/src/Application/MfaLogs/Create/CreateMfaLogCommandHandler.cs b/src/Application/MfaLogs/Create/CreateMfaLogCommandHandler.cs deleted file mode 100644 index b8f015b..0000000 --- a/src/Application/MfaLogs/Create/CreateMfaLogCommandHandler.cs +++ /dev/null @@ -1,37 +0,0 @@ -using Application.Abstractions.Data; -using Application.Abstractions.Messaging; -using Domain.MfaLogs; -using SharedKernel; - -namespace Application.MfaLogs.Create; - -public class CreateMfaLogCommandHandler - : ICommandHandler -{ - private readonly IApplicationDbContext context; - - public CreateMfaLogCommandHandler(IApplicationDbContext context) - { - this.context = context; - } - - public async Task> Handle( - CreateMfaLogCommand command, - CancellationToken cancellationToken) - { - var mfaLog = new MfaLog - { - Id = Guid.NewGuid(), - UserId = command.UserId, - LoginTime = command.LoginTime, - IpAddress = command.IpAddress, - Device = command.Device, - Status = command.Status - }; - - await context.MfaLogs.AddAsync(mfaLog, cancellationToken); - await context.SaveChangesAsync(cancellationToken); - - return Result.Success(mfaLog.Id); - } -} diff --git a/src/Application/MfaLogs/Create/CreateMfaLogValidator.cs b/src/Application/MfaLogs/Create/CreateMfaLogValidator.cs deleted file mode 100644 index 4abad4b..0000000 --- a/src/Application/MfaLogs/Create/CreateMfaLogValidator.cs +++ /dev/null @@ -1,33 +0,0 @@ -using FluentValidation; - -namespace Application.MfaLogs.Create; - -internal sealed class CreateMfaLogValidator : AbstractValidator -{ - public CreateMfaLogValidator() - { - RuleFor(x => x.UserId) - .NotEmpty() - .WithMessage("UserId is required."); - - RuleFor(x => x.LoginTime) - .NotEmpty() - .WithMessage("LoginTime is required."); - - RuleFor(x => x.IpAddress) - .NotEmpty() - .WithMessage("IpAddress is required.") - .MaximumLength(50) - .WithMessage("IpAddress cannot exceed 50 characters."); - - RuleFor(x => x.Device) - .NotEmpty() - .WithMessage("Device is required.") - .MaximumLength(100) - .WithMessage("Device cannot exceed 100 characters."); - - RuleFor(x => x.Status) - .IsInEnum() - .WithMessage("MFA status must be one of: Success (1), Failed (2)."); - } -} diff --git a/src/Application/MfaLogs/Delete/DeleteMfaLogCommand.cs b/src/Application/MfaLogs/Delete/DeleteMfaLogCommand.cs deleted file mode 100644 index bd92f55..0000000 --- a/src/Application/MfaLogs/Delete/DeleteMfaLogCommand.cs +++ /dev/null @@ -1,6 +0,0 @@ -using System; -using Application.Abstractions.Messaging; - -namespace Application.MfaLogs.Delete; - -public sealed record DeleteMfaLogCommand(Guid Id) : ICommand; diff --git a/src/Application/MfaLogs/Delete/DeleteMfaLogCommandHandler.cs b/src/Application/MfaLogs/Delete/DeleteMfaLogCommandHandler.cs deleted file mode 100644 index 9a3048f..0000000 --- a/src/Application/MfaLogs/Delete/DeleteMfaLogCommandHandler.cs +++ /dev/null @@ -1,35 +0,0 @@ -using Application.Abstractions.Data; -using Application.Abstractions.Messaging; -using Domain.MfaLogs; -using Microsoft.EntityFrameworkCore; -using SharedKernel; - -namespace Application.MfaLogs.Delete; - -internal sealed class DeleteMfaLogCommandHandler - : ICommandHandler -{ - private readonly IApplicationDbContext _context; - - public DeleteMfaLogCommandHandler(IApplicationDbContext context) - { - _context = context; - } - - public async Task Handle(DeleteMfaLogCommand command, CancellationToken cancellationToken) - { - MfaLog? mfaLog = await _context.MfaLogs - .SingleOrDefaultAsync(x => x.Id == command.Id, cancellationToken); - - if (mfaLog is null) - { - return Result.Failure(MfaLogErrors.NotFound(command.Id)); - } - - _context.MfaLogs.Remove(mfaLog); - - await _context.SaveChangesAsync(cancellationToken); - - return Result.Success(); - } -} diff --git a/src/Application/MfaLogs/Delete/DeleteMfaLogCommandValidator.cs b/src/Application/MfaLogs/Delete/DeleteMfaLogCommandValidator.cs deleted file mode 100644 index fbfcfeb..0000000 --- a/src/Application/MfaLogs/Delete/DeleteMfaLogCommandValidator.cs +++ /dev/null @@ -1,14 +0,0 @@ -using FluentValidation; - -namespace Application.MfaLogs.Delete; - -public sealed class DeleteMfaLogCommandValidator - : AbstractValidator -{ - public DeleteMfaLogCommandValidator() - { - RuleFor(x => x.Id) - .NotEmpty() - .WithMessage("MfaLog Id is required."); - } -} diff --git a/src/Application/MfaLogs/Get/GetMfaLogQuery.cs b/src/Application/MfaLogs/Get/GetMfaLogQuery.cs deleted file mode 100644 index 50e90eb..0000000 --- a/src/Application/MfaLogs/Get/GetMfaLogQuery.cs +++ /dev/null @@ -1,5 +0,0 @@ -using Application.Abstractions.Messaging; - -namespace Application.MfaLogs.Get; - -public sealed record GetMfaLogQuery : IQuery>; diff --git a/src/Application/MfaLogs/Get/GetMfaLogQueryHandler.cs b/src/Application/MfaLogs/Get/GetMfaLogQueryHandler.cs deleted file mode 100644 index d292f9b..0000000 --- a/src/Application/MfaLogs/Get/GetMfaLogQueryHandler.cs +++ /dev/null @@ -1,60 +0,0 @@ -using Application.Abstractions.Authentication; -using Application.Abstractions.Data; -using Application.Abstractions.Messaging; -using Microsoft.EntityFrameworkCore; -using SharedKernel; - -namespace Application.MfaLogs.Get; - -internal sealed class GetMfaLogQueryHandler : IQueryHandler> -{ - private readonly IApplicationDbContext _context; - private readonly IUserContext _userContext; - - public GetMfaLogQueryHandler(IApplicationDbContext context, IUserContext userContext) - { - _context = context; - _userContext = userContext; - } - - public async Task>> Handle( - GetMfaLogQuery query, - CancellationToken cancellationToken) - { - try - { - Guid userId = _userContext.UserId; - - if (userId == Guid.Empty) - { - return Result.Failure>(Error.NotFound( - "User.NotAuthenticated", - "User is not authenticated.")); - } - - List logs = await _context.MfaLogs - .Where(x => x.UserId == userId) - .OrderByDescending(x => x.LoginTime) - .Select(x => new MfaLogResponse - { - Id = x.Id, - UserId = x.UserId, - LoginTime = x.LoginTime, - IpAddress = x.IpAddress, - Device = x.Device, - Status = x.Status, - CreatedAt = x.CreatedAt, - UpdatedAt = x.UpdatedAt - }) - .ToListAsync(cancellationToken); - - return Result>.Success(logs); - } - catch (Exception ex) - { - return Result.Failure>(Error.Failure( - "MfaLogs.Get", - $"Failed to retrieve MFA logs: {ex.Message}")); - } - } -} diff --git a/src/Application/MfaLogs/Get/MfaLogResponse.cs b/src/Application/MfaLogs/Get/MfaLogResponse.cs deleted file mode 100644 index 0ea6d60..0000000 --- a/src/Application/MfaLogs/Get/MfaLogResponse.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; -using Domain.MfaLogs; - -namespace Application.MfaLogs.Get; -public sealed class MfaLogResponse -{ - public Guid Id { get; set; } - public Guid UserId { get; set; } - public DateTime LoginTime { get; set; } - public string IpAddress { get; set; } - public string Device { get; set; } - public MfaLogStatus Status { get; set; } - public DateTime CreatedAt { get; set; } - public DateTime? UpdatedAt { get; set; } -} diff --git a/src/Application/MfaLogs/GetById/GetMfaLogByIdQuery.cs b/src/Application/MfaLogs/GetById/GetMfaLogByIdQuery.cs deleted file mode 100644 index 67a027f..0000000 --- a/src/Application/MfaLogs/GetById/GetMfaLogByIdQuery.cs +++ /dev/null @@ -1,6 +0,0 @@ -using System; -using Application.Abstractions.Messaging; - -namespace Application.MfaLogs.GetById; - -public sealed record GetMfaLogByIdQuery(Guid Id) : IQuery; diff --git a/src/Application/MfaLogs/GetById/GetMfaLogByIdQueryHandler.cs b/src/Application/MfaLogs/GetById/GetMfaLogByIdQueryHandler.cs deleted file mode 100644 index 0ce2cd6..0000000 --- a/src/Application/MfaLogs/GetById/GetMfaLogByIdQueryHandler.cs +++ /dev/null @@ -1,46 +0,0 @@ -using Application.Abstractions.Data; -using Application.Abstractions.Messaging; -using Domain.MfaLogs; -using Microsoft.EntityFrameworkCore; -using SharedKernel; - -namespace Application.MfaLogs.GetById; - -internal sealed class GetMfaLogByIdQueryHandler - : IQueryHandler -{ - private readonly IApplicationDbContext _context; - - public GetMfaLogByIdQueryHandler(IApplicationDbContext context) - { - _context = context; - } - - public async Task> Handle( - GetMfaLogByIdQuery query, - CancellationToken cancellationToken) - { - MfaLog? mfaLog = await _context.MfaLogs - .AsNoTracking() - .FirstOrDefaultAsync(x => x.Id == query.Id, cancellationToken); - - if (mfaLog is null) - { - return Result.Failure(MfaLogErrors.NotFound(query.Id)); - } - - var response = new MfaLogResponse - { - Id = mfaLog.Id, - UserId = mfaLog.UserId, - LoginTime = mfaLog.LoginTime, - IpAddress = mfaLog.IpAddress, - Device = mfaLog.Device, - Status = mfaLog.Status, - CreatedAt = mfaLog.CreatedAt, - UpdatedAt = mfaLog.UpdatedAt - }; - - return response; - } -} diff --git a/src/Application/MfaLogs/GetById/MfaLogResponse.cs b/src/Application/MfaLogs/GetById/MfaLogResponse.cs deleted file mode 100644 index 446c2a1..0000000 --- a/src/Application/MfaLogs/GetById/MfaLogResponse.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System; -using Domain.MfaLogs; - -namespace Application.MfaLogs.GetById; - -public sealed class MfaLogResponse -{ - public Guid Id { get; set; } - public Guid UserId { get; set; } - public DateTime LoginTime { get; set; } - public string IpAddress { get; set; } = null!; - public string Device { get; set; } = null!; - public MfaLogStatus Status { get; set; } - public DateTime CreatedAt { get; set; } - public DateTime? UpdatedAt { get; set; } -} diff --git a/src/Application/MfaLogs/Update/UpdateMfaLogCommand.cs b/src/Application/MfaLogs/Update/UpdateMfaLogCommand.cs deleted file mode 100644 index 3a1faed..0000000 --- a/src/Application/MfaLogs/Update/UpdateMfaLogCommand.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Application.Abstractions.Messaging; -using Domain.MfaLogs; - -namespace Application.MfaLogs.Update; - -public sealed record UpdateMfaLogCommand( - Guid MfaLogId, - DateTime LoginTime, - string IpAddress, - string Device, - MfaLogStatus Status -) : ICommand; diff --git a/src/Application/MfaLogs/Update/UpdateMfaLogCommandHandler.cs b/src/Application/MfaLogs/Update/UpdateMfaLogCommandHandler.cs deleted file mode 100644 index 4d648a2..0000000 --- a/src/Application/MfaLogs/Update/UpdateMfaLogCommandHandler.cs +++ /dev/null @@ -1,34 +0,0 @@ -using Application.Abstractions.Data; -using Application.Abstractions.Messaging; -using Domain.MfaLogs; -using Microsoft.EntityFrameworkCore; -using SharedKernel; - -namespace Application.MfaLogs.Update; - -internal sealed class UpdateMfaLogCommandHandler(IApplicationDbContext context) - : ICommandHandler -{ - public async Task Handle(UpdateMfaLogCommand command, CancellationToken cancellationToken) - { - MfaLog? mfaLog = await context.MfaLogs - .SingleOrDefaultAsync(l => l.Id == command.MfaLogId, cancellationToken); - - if (mfaLog is null) - { - return Result.Failure(Error.NotFound( - "MfaLog.NotFound", - $"MfaLog with Id {command.MfaLogId} not found.")); - } - - mfaLog.LoginTime = command.LoginTime; - mfaLog.IpAddress = command.IpAddress; - mfaLog.Device = command.Device; - mfaLog.Status = command.Status; - mfaLog.UpdatedAt = DateTime.UtcNow; - - await context.SaveChangesAsync(cancellationToken); - - return Result.Success(); - } -} diff --git a/src/Application/MfaLogs/Update/UpdateMfaLogValidator.cs b/src/Application/MfaLogs/Update/UpdateMfaLogValidator.cs deleted file mode 100644 index 40ec24f..0000000 --- a/src/Application/MfaLogs/Update/UpdateMfaLogValidator.cs +++ /dev/null @@ -1,33 +0,0 @@ -using FluentValidation; - -namespace Application.MfaLogs.Update; - -public sealed class UpdateMfaLogValidator : AbstractValidator -{ - public UpdateMfaLogValidator() - { - RuleFor(x => x.MfaLogId) - .NotEmpty() - .WithMessage("MfaLogId is required."); - - RuleFor(x => x.LoginTime) - .NotEmpty() - .WithMessage("LoginTime is required."); - - RuleFor(x => x.IpAddress) - .NotEmpty() - .WithMessage("IpAddress is required.") - .MaximumLength(50) - .WithMessage("IpAddress cannot exceed 50 characters."); - - RuleFor(x => x.Device) - .NotEmpty() - .WithMessage("Device is required.") - .MaximumLength(100) - .WithMessage("Device cannot exceed 100 characters."); - - RuleFor(x => x.Status) - .IsInEnum() - .WithMessage("Invalid MFA status value."); - } -} diff --git a/src/Application/MfaSettings/Create/CreateMfaSettingCommand.cs b/src/Application/MfaSettings/Create/CreateMfaSettingCommand.cs deleted file mode 100644 index 989aca0..0000000 --- a/src/Application/MfaSettings/Create/CreateMfaSettingCommand.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System; -using Application.Abstractions.Messaging; -using Domain.MfaSettings; - - -namespace Application.MfaSettings.Create; - - -public sealed class CreateMfaSettingCommand : ICommand -{ - public Guid UserId { get; set; } - public string SecretKey { get; set; } - public string BackupCodes { get; set; } - public MfaMethod Method { get; set; } - public bool Enabled { get; set; } -} diff --git a/src/Application/MfaSettings/Create/CreateMfaSettingValidator.cs b/src/Application/MfaSettings/Create/CreateMfaSettingValidator.cs deleted file mode 100644 index 44cc6dc..0000000 --- a/src/Application/MfaSettings/Create/CreateMfaSettingValidator.cs +++ /dev/null @@ -1,38 +0,0 @@ -using FluentValidation; -using Domain.MfaSettings; - - -namespace Application.MfaSettings.Create; - - -internal sealed class CreateMfaSettingValidator : AbstractValidator -{ - public CreateMfaSettingValidator() - { - RuleFor(m => m.UserId) - .NotEmpty() - .WithMessage("UserId is required."); - - - RuleFor(m => m.SecretKey) - .NotEmpty() - .WithMessage("Secret key is required.") - .MaximumLength(255); - - - - RuleFor(m => m.Method) - .IsInEnum() - .WithMessage("MFA method must be one of: TOTP, SMS, or EMAIL."); - - - RuleFor(m => m.BackupCodes) - .NotEmpty() - .WithMessage("Backup codes are required."); - - - RuleFor(m => m.Enabled) - .NotNull() - .WithMessage("Enabled status must be specified."); - } -} diff --git a/src/Application/MfaSettings/Create/CreateMfasettingCommandHandler.cs b/src/Application/MfaSettings/Create/CreateMfasettingCommandHandler.cs deleted file mode 100644 index 3aee9ed..0000000 --- a/src/Application/MfaSettings/Create/CreateMfasettingCommandHandler.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System; -using System.Threading; -using System.Threading.Tasks; -using Application.Abstractions.Data; -using Application.Abstractions.Messaging; -using Domain.MfaSettings; -using SharedKernel; - -namespace Application.MfaSettings.Create; - -internal sealed class CreateMfaSettingCommandHandler(IApplicationDbContext context) - : ICommandHandler -{ - public async Task> Handle(CreateMfaSettingCommand command, CancellationToken cancellationToken) - { - var mfaSetting = new MfaSetting - { - UserId = command.UserId, - SecretKey = command.SecretKey, - BackupCodes = command.BackupCodes, - Method = command.Method, - Enabled = command.Enabled - }; - - await context.MfaSettings.AddAsync(mfaSetting, cancellationToken); - await context.SaveChangesAsync(cancellationToken); - - return Result.Success(mfaSetting.Id); - } -} diff --git a/src/Application/MfaSettings/Delete/DeleteMfaSettingCommand.cs b/src/Application/MfaSettings/Delete/DeleteMfaSettingCommand.cs deleted file mode 100644 index 3f536f0..0000000 --- a/src/Application/MfaSettings/Delete/DeleteMfaSettingCommand.cs +++ /dev/null @@ -1,6 +0,0 @@ -using System; -using Application.Abstractions.Messaging; - -namespace Application.MfaSettings.Delete; - -public sealed record DeleteMfaSettingCommand(Guid Id) : ICommand; diff --git a/src/Application/MfaSettings/Delete/DeleteMfaSettingCommandHandler.cs b/src/Application/MfaSettings/Delete/DeleteMfaSettingCommandHandler.cs deleted file mode 100644 index 4a1b384..0000000 --- a/src/Application/MfaSettings/Delete/DeleteMfaSettingCommandHandler.cs +++ /dev/null @@ -1,39 +0,0 @@ -using System.Threading; -using System.Threading.Tasks; -using Application.Abstractions.Data; -using Application.Abstractions.Messaging; -using Domain.MfaSettings; -using Microsoft.EntityFrameworkCore; -using SharedKernel; - -namespace Application.MfaSettings.Delete; - -internal sealed class DeleteMfaSettingCommandHandler - : ICommandHandler -{ - private readonly IApplicationDbContext _context; - - public DeleteMfaSettingCommandHandler(IApplicationDbContext context) - { - _context = context; - } - - public async Task Handle(DeleteMfaSettingCommand command, CancellationToken cancellationToken) - { - MfaSetting? mfa = await _context.MfaSettings - .SingleOrDefaultAsync(x => x.Id == command.Id, cancellationToken); - - if (mfa is null) - { - return Result.Failure( - Error.NotFound("MfaSetting.NotFound", $"MfaSetting with Id {command.Id} not found.") - ); - } - - _context.MfaSettings.Remove(mfa); - - await _context.SaveChangesAsync(cancellationToken); - - return Result.Success(); - } -} diff --git a/src/Application/MfaSettings/Delete/DeleteMfaSettingCommandValidator.cs b/src/Application/MfaSettings/Delete/DeleteMfaSettingCommandValidator.cs deleted file mode 100644 index 3c06f00..0000000 --- a/src/Application/MfaSettings/Delete/DeleteMfaSettingCommandValidator.cs +++ /dev/null @@ -1,14 +0,0 @@ -using FluentValidation; - -namespace Application.MfaSettings.Delete; - -public sealed class DeleteMfaSettingCommandValidator - : AbstractValidator -{ - public DeleteMfaSettingCommandValidator() - { - RuleFor(x => x.Id) - .NotEmpty() - .WithMessage("MfaSetting Id is required."); - } -} diff --git a/src/Application/MfaSettings/Get/GetMfaSettingQuery.cs b/src/Application/MfaSettings/Get/GetMfaSettingQuery.cs deleted file mode 100644 index 9fd5628..0000000 --- a/src/Application/MfaSettings/Get/GetMfaSettingQuery.cs +++ /dev/null @@ -1,7 +0,0 @@ -using System.Collections.Generic; -using Application.Abstractions.Messaging; - -namespace Application.MfaSettings.Get; - -public sealed record GetMfaSettingQuery() - : IQuery>; diff --git a/src/Application/MfaSettings/Get/GetMfaSettingQueryHandler.cs b/src/Application/MfaSettings/Get/GetMfaSettingQueryHandler.cs deleted file mode 100644 index ea7e9bb..0000000 --- a/src/Application/MfaSettings/Get/GetMfaSettingQueryHandler.cs +++ /dev/null @@ -1,40 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using Application.Abstractions.Authentication; -using Application.Abstractions.Data; -using Application.Abstractions.Messaging; -using Domain.MfaSettings; -using Microsoft.EntityFrameworkCore; -using SharedKernel; - -namespace Application.MfaSettings.Get; - -internal sealed class GetMfaSettingQueryHandler( - IApplicationDbContext context, - IUserContext userContext) - : IQueryHandler> -{ - public async Task>> Handle( - GetMfaSettingQuery query, - CancellationToken cancellationToken) - { - Guid userId = userContext.UserId; - - List settings = await context.MfaSettings - .Where(x => x.UserId == userId) - .Select(x => new MfaSettingResponse - { - Id = x.Id, - UserId = x.UserId, - SecretKey = x.SecretKey, - BackupCodes = x.BackupCodes, - Method = x.Method.ToString(), - Enabled = x.Enabled - }) - .ToListAsync(cancellationToken); - - return settings; - } -} diff --git a/src/Application/MfaSettings/Get/MfaSettingResponse.cs b/src/Application/MfaSettings/Get/MfaSettingResponse.cs deleted file mode 100644 index 04458c7..0000000 --- a/src/Application/MfaSettings/Get/MfaSettingResponse.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; - -namespace Application.MfaSettings.Get; - -public sealed class MfaSettingResponse -{ - public Guid Id { get; set; } - public Guid UserId { get; set; } - public string SecretKey { get; set; } = string.Empty; - public string? BackupCodes { get; set; } - public string Method { get; set; } = string.Empty; - public bool Enabled { get; set; } -} diff --git a/src/Application/MfaSettings/GetById/GetMfaSettingByIdQuery.cs b/src/Application/MfaSettings/GetById/GetMfaSettingByIdQuery.cs deleted file mode 100644 index f8d066c..0000000 --- a/src/Application/MfaSettings/GetById/GetMfaSettingByIdQuery.cs +++ /dev/null @@ -1,6 +0,0 @@ -using Application.Abstractions.Messaging; - -namespace Application.MfaSettings.GetById; - -public sealed record GetMfaSettingByIdQuery(Guid Id) - : IQuery; diff --git a/src/Application/MfaSettings/GetById/GetMfaSettingByIdQueryHandler.cs b/src/Application/MfaSettings/GetById/GetMfaSettingByIdQueryHandler.cs deleted file mode 100644 index 5e5851b..0000000 --- a/src/Application/MfaSettings/GetById/GetMfaSettingByIdQueryHandler.cs +++ /dev/null @@ -1,48 +0,0 @@ -using System.Threading; -using System.Threading.Tasks; -using Application.Abstractions.Data; -using Application.Abstractions.Messaging; -using Domain.MfaSettings; -using Microsoft.EntityFrameworkCore; -using SharedKernel; - -namespace Application.MfaSettings.GetById; - -internal sealed class GetMfaSettingByIdQueryHandler - : IQueryHandler -{ - private readonly IApplicationDbContext _context; - - public GetMfaSettingByIdQueryHandler(IApplicationDbContext context) - { - _context = context; - } - - public async Task> Handle( - GetMfaSettingByIdQuery query, - CancellationToken cancellationToken) - { - MfaSetting? mfa = await _context.MfaSettings - .AsNoTracking() - .FirstOrDefaultAsync(x => x.Id == query.Id, cancellationToken); - - if (mfa is null) - { - return Result.Failure( - Error.NotFound("MfaSetting.NotFound", $"MfaSetting with Id {query.Id} not found.") - ); - } - - var response = new MfaSettingResponse - { - Id = mfa.Id, - UserId = mfa.UserId, - SecretKey = mfa.SecretKey, - BackupCodes = mfa.BackupCodes, - Method = mfa.Method.ToString(), - Enabled = mfa.Enabled - }; - - return response; - } -} diff --git a/src/Application/MfaSettings/GetById/MfaSettingResponse.cs b/src/Application/MfaSettings/GetById/MfaSettingResponse.cs deleted file mode 100644 index f65b3f6..0000000 --- a/src/Application/MfaSettings/GetById/MfaSettingResponse.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace Application.MfaSettings.GetById; - -public sealed class MfaSettingResponse -{ - public Guid Id { get; set; } - public Guid UserId { get; set; } - public string SecretKey { get; set; } = string.Empty; - public string? BackupCodes { get; set; } - public string Method { get; set; } = string.Empty; - public bool Enabled { get; set; } -} diff --git a/src/Application/MfaSettings/Update/UpdateMfaSettingCommand.cs b/src/Application/MfaSettings/Update/UpdateMfaSettingCommand.cs deleted file mode 100644 index 9aa75d8..0000000 --- a/src/Application/MfaSettings/Update/UpdateMfaSettingCommand.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System; -using Application.Abstractions.Messaging; -using Domain.MfaSettings; - -namespace Application.MfaSettings.Update; - -public sealed record UpdateMfaSettingCommand( - Guid MfaSettingId, - Guid UserId, - string? SecretKey, - string? BackupCodes, - MfaMethod Method, - bool Enabled -) : ICommand; diff --git a/src/Application/MfaSettings/Update/UpdateMfaSettingCommandHandler.cs b/src/Application/MfaSettings/Update/UpdateMfaSettingCommandHandler.cs deleted file mode 100644 index 2b79b90..0000000 --- a/src/Application/MfaSettings/Update/UpdateMfaSettingCommandHandler.cs +++ /dev/null @@ -1,39 +0,0 @@ -using System.Threading; -using System.Threading.Tasks; -using Application.Abstractions.Data; -using Application.Abstractions.Messaging; -using Domain.MfaSettings; -using Microsoft.EntityFrameworkCore; -using SharedKernel; - -namespace Application.MfaSettings.Update; - -internal sealed class UpdateMfaSettingCommandHandler( - IApplicationDbContext context -) : ICommandHandler -{ - public async Task Handle(UpdateMfaSettingCommand command, CancellationToken cancellationToken) - { - // Find existing MFA setting - MfaSetting? mfa = await context.MfaSettings - .SingleOrDefaultAsync(a => a.Id == command.MfaSettingId, cancellationToken); - - if (mfa is null) - { - return Result.Failure(Error.NotFound( - "MfaSetting.NotFound", - $"MfaSetting with Id {command.MfaSettingId} not found.")); - } - - // Update fields - mfa.UserId = command.UserId; - mfa.SecretKey = command.SecretKey ?? mfa.SecretKey; - mfa.BackupCodes = command.BackupCodes ?? mfa.BackupCodes; - mfa.Method = command.Method; - mfa.Enabled = command.Enabled; - - await context.SaveChangesAsync(cancellationToken); - - return Result.Success(); - } -} diff --git a/src/Application/MfaSettings/Update/UpdateMfaSettingValidator.cs b/src/Application/MfaSettings/Update/UpdateMfaSettingValidator.cs deleted file mode 100644 index 83e8884..0000000 --- a/src/Application/MfaSettings/Update/UpdateMfaSettingValidator.cs +++ /dev/null @@ -1,22 +0,0 @@ -using FluentValidation; -using Domain.MfaSettings; - -namespace Application.MfaSettings.Update; - -public sealed class UpdateMfaSettingValidator : AbstractValidator -{ - public UpdateMfaSettingValidator() - { - RuleFor(m => m.MfaSettingId) - .NotEmpty() - .WithMessage("MfaSettingId is required."); - - RuleFor(m => m.UserId) - .NotEmpty() - .WithMessage("UserId is required."); - - RuleFor(m => m.Method) - .IsInEnum() - .WithMessage("Method must be one of: TOTP, SMS, EMAIL."); - } -} diff --git a/src/Application/PasswordResets/Create/CreatePasswordResetCommand.cs b/src/Application/PasswordResets/Create/CreatePasswordResetCommand.cs deleted file mode 100644 index a6b8f95..0000000 --- a/src/Application/PasswordResets/Create/CreatePasswordResetCommand.cs +++ /dev/null @@ -1,11 +0,0 @@ -using Application.Abstractions.Messaging; - -namespace Application.PasswordResets.Create; - -public sealed class CreatePasswordResetCommand : ICommand -{ - public Guid UserId { get; set; } - public string Token { get; set; } - public DateTime ExpiresAt { get; set; } - public bool Used { get; set; } -} diff --git a/src/Application/PasswordResets/Create/CreatePasswordResetCommandHandler.cs b/src/Application/PasswordResets/Create/CreatePasswordResetCommandHandler.cs deleted file mode 100644 index 3d1bb7a..0000000 --- a/src/Application/PasswordResets/Create/CreatePasswordResetCommandHandler.cs +++ /dev/null @@ -1,50 +0,0 @@ -using Application.Abstractions.Authentication; -using Application.Abstractions.Data; -using Application.Abstractions.Messaging; -using Domain.PasswordResets; -using Domain.Users; -using Microsoft.EntityFrameworkCore; -using SharedKernel; - -namespace Application.PasswordResets.Create; - -internal sealed class CreatePasswordResetCommandHandler( - IApplicationDbContext context, - IDateTimeProvider dateTimeProvider, - IUserContext userContext) - : ICommandHandler -{ - public async Task> Handle(CreatePasswordResetCommand command, CancellationToken cancellationToken) - { - if (userContext.UserId != command.UserId) - { - return Result.Failure(UserErrors.Unauthorized()); - } - - User? user = await context.Users.AsNoTracking() - .SingleOrDefaultAsync(u => u.Id == command.UserId, cancellationToken); - - if (user is null) - { - return Result.Failure(UserErrors.NotFound(command.UserId)); - } - - var passwordReset = new PasswordReset - { - UserId = command.UserId, - Token = command.Token, - ExpiresAt = command.ExpiresAt == default - ? dateTimeProvider.UtcNow - : command.ExpiresAt, - Used = command.Used - }; - - passwordReset.Raise(new PasswordResetCreatedDomainEvent(passwordReset.PrId)); - - context.PasswordReset.Add(passwordReset); - - await context.SaveChangesAsync(cancellationToken); - - return passwordReset.PrId; - } -} diff --git a/src/Application/PasswordResets/Create/CreatePasswordResetCommandValidator.cs b/src/Application/PasswordResets/Create/CreatePasswordResetCommandValidator.cs deleted file mode 100644 index 9401f38..0000000 --- a/src/Application/PasswordResets/Create/CreatePasswordResetCommandValidator.cs +++ /dev/null @@ -1,19 +0,0 @@ -using FluentValidation; - -namespace Application.PasswordResets.Create; - -public class CreatePasswordResetCommandValidator : AbstractValidator -{ - public CreatePasswordResetCommandValidator() - { - RuleFor(x => x.UserId) - .NotEmpty().WithMessage("User ID is required."); - RuleFor(x => x.Token) - .NotEmpty().WithMessage("Token is required.") - .MaximumLength(256).WithMessage("Token must not exceed 256 characters."); - RuleFor(x => x.ExpiresAt) - .GreaterThan(DateTime.UtcNow).WithMessage("Expiration date must be in the future."); - RuleFor(x => x.Used) - .NotNull().WithMessage("Used status must be specified."); - } -} diff --git a/src/Application/PasswordResets/Delete/DeletePasswordResetCommand.cs b/src/Application/PasswordResets/Delete/DeletePasswordResetCommand.cs deleted file mode 100644 index ad52232..0000000 --- a/src/Application/PasswordResets/Delete/DeletePasswordResetCommand.cs +++ /dev/null @@ -1,5 +0,0 @@ -using Application.Abstractions.Messaging; - -namespace Application.PasswordResets.Delete; - -public sealed record DeletePasswordResetCommand(Guid PrId) : ICommand; diff --git a/src/Application/PasswordResets/Delete/DeletePasswordResetCommandHandler.cs b/src/Application/PasswordResets/Delete/DeletePasswordResetCommandHandler.cs deleted file mode 100644 index 66d7f7c..0000000 --- a/src/Application/PasswordResets/Delete/DeletePasswordResetCommandHandler.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Application.Abstractions.Authentication; -using Application.Abstractions.Data; -using Application.Abstractions.Messaging; -using Domain.PasswordResets; -using Microsoft.EntityFrameworkCore; -using SharedKernel; - -namespace Application.PasswordResets.Delete; - -internal sealed class DeletePasswordResetCommandHandler(IApplicationDbContext context, IUserContext userContext) - : ICommandHandler -{ - public async Task Handle(DeletePasswordResetCommand command, CancellationToken cancellationToken) - { - PasswordReset? passwordReset = await context.PasswordReset - .SingleOrDefaultAsync(t => t.PrId == command.PrId && t.UserId == userContext.UserId, cancellationToken); - - if (passwordReset is null) - { - return Result.Failure(PasswordResetsErrors.NotFound(command.PrId)); - } - - context.PasswordReset.Remove(passwordReset); - - passwordReset.Raise(new PasswordResetDeletedDomainEvent(passwordReset.PrId)); - - await context.SaveChangesAsync(cancellationToken); - - return Result.Success(); - } -} diff --git a/src/Application/PasswordResets/Delete/DeletePasswordResetCommandValidator.cs b/src/Application/PasswordResets/Delete/DeletePasswordResetCommandValidator.cs deleted file mode 100644 index 083b2a9..0000000 --- a/src/Application/PasswordResets/Delete/DeletePasswordResetCommandValidator.cs +++ /dev/null @@ -1,13 +0,0 @@ -using FluentValidation; - -namespace Application.PasswordResets.Delete; - -internal sealed class DeletePasswordResetCommandValidator : AbstractValidator -{ - public DeletePasswordResetCommandValidator() - { - RuleFor(x => x.PrId) - .NotEmpty().WithMessage("Password reset ID is required."); - } -} - diff --git a/src/Application/PasswordResets/Get/GetPasswordResetQuery.cs b/src/Application/PasswordResets/Get/GetPasswordResetQuery.cs deleted file mode 100644 index 90c7122..0000000 --- a/src/Application/PasswordResets/Get/GetPasswordResetQuery.cs +++ /dev/null @@ -1,5 +0,0 @@ -using Application.Abstractions.Messaging; - -namespace Application.PasswordResets.Get; - -public sealed record GetPasswordResetQuery(Guid UserId) : IQuery>; diff --git a/src/Application/PasswordResets/Get/GetPasswordResetQueryHandler.cs b/src/Application/PasswordResets/Get/GetPasswordResetQueryHandler.cs deleted file mode 100644 index abf4c03..0000000 --- a/src/Application/PasswordResets/Get/GetPasswordResetQueryHandler.cs +++ /dev/null @@ -1,34 +0,0 @@ -using Application.Abstractions.Authentication; -using Application.Abstractions.Data; -using Application.Abstractions.Messaging; -using Domain.Users; -using Microsoft.EntityFrameworkCore; -using SharedKernel; - -namespace Application.PasswordResets.Get; - -internal sealed class GetPasswordResetQueryHandler(IApplicationDbContext context, IUserContext userContext) - : IQueryHandler> -{ - public async Task>> Handle(GetPasswordResetQuery query, CancellationToken cancellationToken) - { - if (query.UserId != userContext.UserId) - { - return Result.Failure>(UserErrors.Unauthorized()); - } - - List passwordResetResponse = await context.PasswordReset - .Where(passwordResetResponse => passwordResetResponse.UserId == query.UserId) - .Select(passwordResetResponse => new PasswordResetResponse - { - PrId = passwordResetResponse.PrId, - UserId = passwordResetResponse.UserId, - Token = passwordResetResponse.Token, - ExpiresAt = passwordResetResponse.ExpiresAt, - Used = passwordResetResponse.Used - - }).ToListAsync(cancellationToken); - - return passwordResetResponse; - } -} diff --git a/src/Application/PasswordResets/Get/PasswordResetResponse.cs b/src/Application/PasswordResets/Get/PasswordResetResponse.cs deleted file mode 100644 index 9c9744c..0000000 --- a/src/Application/PasswordResets/Get/PasswordResetResponse.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Application.PasswordResets.Get; - -public sealed class PasswordResetResponse -{ - public Guid PrId { get; set; } - public Guid UserId { get; set; } - public string Token { get; set; } - public DateTime ExpiresAt { get; set; } - public bool Used { get; set; } -} diff --git a/src/Application/PasswordResets/GetById/GetPasswordResetByIdQuery.cs b/src/Application/PasswordResets/GetById/GetPasswordResetByIdQuery.cs deleted file mode 100644 index 8472a70..0000000 --- a/src/Application/PasswordResets/GetById/GetPasswordResetByIdQuery.cs +++ /dev/null @@ -1,5 +0,0 @@ -using Application.Abstractions.Messaging; - -namespace Application.PasswordResets.GetById; - -public sealed record GetPasswordResetByIdQuery(Guid PrId) : IQuery; diff --git a/src/Application/PasswordResets/GetById/GetPasswordResetByIdQueryHandler.cs b/src/Application/PasswordResets/GetById/GetPasswordResetByIdQueryHandler.cs deleted file mode 100644 index 80115a2..0000000 --- a/src/Application/PasswordResets/GetById/GetPasswordResetByIdQueryHandler.cs +++ /dev/null @@ -1,32 +0,0 @@ -using Application.Abstractions.Authentication; -using Application.Abstractions.Data; -using Application.Abstractions.Messaging; -using Domain.PasswordResets; -using Microsoft.EntityFrameworkCore; -using SharedKernel; - -namespace Application.PasswordResets.GetById; - -internal sealed class GetPasswordResetByIdQueryHandler(IApplicationDbContext context, IUserContext userContext) - : IQueryHandler -{ - public async Task> Handle(GetPasswordResetByIdQuery query, CancellationToken cancellationToken) - { - PasswordResetResponse? passwordResetResponse = await context.PasswordReset - .Where(passwordResetResponse => passwordResetResponse.PrId == query.PrId && passwordResetResponse.UserId == userContext.UserId) - .Select(passwordResetResponse => new PasswordResetResponse - { - User_Id = passwordResetResponse.UserId, - Token = passwordResetResponse.Token, - Expires_at = passwordResetResponse.ExpiresAt, - Used = passwordResetResponse.Used - }).SingleOrDefaultAsync(cancellationToken); - - if (passwordResetResponse is null) - { - return Result.Failure(PasswordResetsErrors.NotFound(query.PrId)); - } - - return passwordResetResponse; - } -} diff --git a/src/Application/PasswordResets/GetById/PasswordResetResponse.cs b/src/Application/PasswordResets/GetById/PasswordResetResponse.cs deleted file mode 100644 index f412731..0000000 --- a/src/Application/PasswordResets/GetById/PasswordResetResponse.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Application.PasswordResets.GetById; - -public sealed class PasswordResetResponse -{ - public Guid PrId { get; set; } - public Guid User_Id { get; set; } - public string Token { get; set; } - public DateTime Expires_at { get; set; } - public bool Used { get; set; } -} diff --git a/src/Application/PasswordResets/Update/UpdatePasswordResetCommand.cs b/src/Application/PasswordResets/Update/UpdatePasswordResetCommand.cs deleted file mode 100644 index c56fcf4..0000000 --- a/src/Application/PasswordResets/Update/UpdatePasswordResetCommand.cs +++ /dev/null @@ -1,7 +0,0 @@ -using Application.Abstractions.Messaging; - -namespace Application.PasswordResets.Update; - -public sealed record UpdatePasswordResetCommand( - Guid PrId, - string Token) : ICommand; diff --git a/src/Application/PasswordResets/Update/UpdatePasswordResetCommandHandler.cs b/src/Application/PasswordResets/Update/UpdatePasswordResetCommandHandler.cs deleted file mode 100644 index e0267b5..0000000 --- a/src/Application/PasswordResets/Update/UpdatePasswordResetCommandHandler.cs +++ /dev/null @@ -1,29 +0,0 @@ -using Application.Abstractions.Data; -using Application.Abstractions.Messaging; -using Domain.PasswordResets; -using Microsoft.EntityFrameworkCore; -using SharedKernel; - -namespace Application.PasswordResets.Update; - -internal sealed class UpdatePasswordResetCommandHandler( - IApplicationDbContext context) - : ICommandHandler -{ - public async Task Handle(UpdatePasswordResetCommand command, CancellationToken cancellationToken) - { - PasswordReset? passwordReset = await context.PasswordReset - .SingleOrDefaultAsync(t => t.PrId == command.PrId, cancellationToken); - - if (passwordReset is null) - { - return Result.Failure(PasswordResetsErrors.NotFound(command.PrId)); - } - - passwordReset.Token = command.Token; - - await context.SaveChangesAsync(cancellationToken); - - return Result.Success(); - } -} diff --git a/src/Application/Tokens/Delete/DeleteTokenCommand.cs b/src/Application/Tokens/Delete/DeleteTokenCommand.cs deleted file mode 100644 index 32cf4a4..0000000 --- a/src/Application/Tokens/Delete/DeleteTokenCommand.cs +++ /dev/null @@ -1,5 +0,0 @@ -using Application.Abstractions.Messaging; - -namespace Application.Tokens.Delete; - -public sealed record DeleteTokenCommand(string TokenId) : ICommand; diff --git a/src/Application/Tokens/Delete/DeleteTokenCommandHandler.cs b/src/Application/Tokens/Delete/DeleteTokenCommandHandler.cs deleted file mode 100644 index 7e0907d..0000000 --- a/src/Application/Tokens/Delete/DeleteTokenCommandHandler.cs +++ /dev/null @@ -1,28 +0,0 @@ -using Application.Abstractions.Authentication; -using Application.Abstractions.Data; -using Application.Abstractions.Openiddict; -using Application.Abstractions.Messaging; -using Microsoft.EntityFrameworkCore; -using SharedKernel; -using SharedKernel.Models; - - -namespace Application.Tokens.Delete; - -internal sealed class DeleteTokenCommandHandler( - IOpeniddictTokenService tokenService) : ICommandHandler -{ - public async Task Handle(DeleteTokenCommand command, CancellationToken cancellationToken) - { - try - { - await tokenService.DeleteByIdAsync(command.TokenId, cancellationToken); - return Result.Success(); - } - catch (Exception ex) - { - return Result.Failure( - $"Failed to fetch tokens: {ex.Message}"); - } - } -} diff --git a/src/Application/Tokens/Delete/DeleteTokenCommandValidator.cs b/src/Application/Tokens/Delete/DeleteTokenCommandValidator.cs deleted file mode 100644 index 5092ccc..0000000 --- a/src/Application/Tokens/Delete/DeleteTokenCommandValidator.cs +++ /dev/null @@ -1,12 +0,0 @@ -using FluentValidation; - -namespace Application.Tokens.Delete; - -internal sealed class DeleteTokenCommandValidator : AbstractValidator -{ - public DeleteTokenCommandValidator() - { - RuleFor(x => x.TokenId) - .NotEmpty().WithMessage("Token ID is required."); - } -} diff --git a/src/Application/Tokens/Get/GetTokensQuery.cs b/src/Application/Tokens/Get/GetTokensQuery.cs deleted file mode 100644 index b3111c7..0000000 --- a/src/Application/Tokens/Get/GetTokensQuery.cs +++ /dev/null @@ -1,5 +0,0 @@ -using Application.Abstractions.Messaging; - -namespace Application.Tokens.Get; - -public sealed record GetTokensQuery() : IQuery>; diff --git a/src/Application/Tokens/Get/GetTokensQueryHandler.cs b/src/Application/Tokens/Get/GetTokensQueryHandler.cs deleted file mode 100644 index 26c55ed..0000000 --- a/src/Application/Tokens/Get/GetTokensQueryHandler.cs +++ /dev/null @@ -1,27 +0,0 @@ -using Application.Abstractions.Authentication; -using Application.Abstractions.Data; -using Application.Abstractions.Openiddict; -using Application.Abstractions.Messaging; -using Microsoft.EntityFrameworkCore; -using SharedKernel; -using SharedKernel.Models; - -namespace Application.Tokens.Get; - -internal sealed class GetTokensQueryHandler( - IOpeniddictTokenService tokenService) : IQueryHandler> -{ - public async Task>> Handle(GetTokensQuery query, CancellationToken cancellationToken) - { - try - { - IReadOnlyList tokens = await tokenService.GetAllAsync(cancellationToken); - return Result.Success(tokens); - } - catch (Exception ex) - { - return Result.Failure>( - $"Failed to fetch tokens: {ex.Message}"); - } - } -} diff --git a/src/Application/Tokens/Get/TokenResponse.cs b/src/Application/Tokens/Get/TokenResponse.cs deleted file mode 100644 index 33b86f6..0000000 --- a/src/Application/Tokens/Get/TokenResponse.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace Application.Tokens.Get; - -public sealed class TokenResponse -{ - public Guid TokenId { get; set; } - public Guid UserId { get; set; } - public Guid AppId { get; set; } - public string Accesstoken { get; set; } //text - public string Refreshtoken { get; set; } // text - public DateTime IssuedAt { get; set; } -} diff --git a/src/Application/UserLoginHistories/Create/CreateUserLoginHistoryCommand.cs b/src/Application/UserLoginHistories/Create/CreateUserLoginHistoryCommand.cs deleted file mode 100644 index 28ae7ea..0000000 --- a/src/Application/UserLoginHistories/Create/CreateUserLoginHistoryCommand.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Application.Abstractions.Messaging; -using Domain.UserLoginHistories; - -namespace Application.UserLoginHistories.Create; - -public sealed class CreateUserLoginHistoryCommand : ICommand -{ - public Guid UserId { get; set; } - public string IpAddress { get; set; } - public string Country { get; set; } - public string City { get; set; } - public string Browser { get; set; } - public string OS { get; set; } - public string Device { get; set; } - public DateTime? LogoutTime { get; set; } -} diff --git a/src/Application/UserLoginHistories/Create/CreateUserLoginHistoryCommandHandler.cs b/src/Application/UserLoginHistories/Create/CreateUserLoginHistoryCommandHandler.cs deleted file mode 100644 index 11c4c6b..0000000 --- a/src/Application/UserLoginHistories/Create/CreateUserLoginHistoryCommandHandler.cs +++ /dev/null @@ -1,53 +0,0 @@ -using Application.Abstractions.Authentication; -using Application.Abstractions.Data; -using Application.Abstractions.Messaging; -using Domain.UserLoginHistories; -using Domain.Users; -using Microsoft.EntityFrameworkCore; -using SharedKernel; -using LoginStatus = Domain.UserLoginHistories.LoginStatus; - -namespace Application.UserLoginHistories.Create; - -internal sealed class CreateUserLoginHistoryCommandHandler( - IApplicationDbContext context, - IDateTimeProvider dateTimeProvider, - IUserContext userContext) : ICommandHandler -{ - public async Task> Handle(CreateUserLoginHistoryCommand command, CancellationToken cancellationToken) - { - if (userContext.UserId != command.UserId) - { - return Result.Failure(UserErrors.Unauthorized()); - } - - User? user = await context.Users.AsNoTracking() - .SingleOrDefaultAsync(u => u.Id == command.UserId, cancellationToken); - - if (user is null) - { - return Result.Failure(UserErrors.NotFound(command.UserId)); - } - - var history = new UserLoginHistory - { - Id = Guid.NewGuid(), - UserId = command.UserId, - IpAddress = command.IpAddress, - Country = command.Country, - City = command.City, - Browser = command.Browser, - OS = command.OS, - Device = command.Device, - LogInTime = dateTimeProvider.UtcNow, - LogoutTime = command.LogoutTime, - Status = LoginStatus.Succeed - }; - - await context.UserLoginHistory.AddAsync(history, cancellationToken); - - await context.SaveChangesAsync(cancellationToken); - - return history.Id; - } -} diff --git a/src/Application/UserLoginHistories/Create/CreateUserLoginHistoryCommandValidator.cs b/src/Application/UserLoginHistories/Create/CreateUserLoginHistoryCommandValidator.cs deleted file mode 100644 index 8814b3a..0000000 --- a/src/Application/UserLoginHistories/Create/CreateUserLoginHistoryCommandValidator.cs +++ /dev/null @@ -1,37 +0,0 @@ -using FluentValidation; - -namespace Application.UserLoginHistories.Create; - -internal sealed class CreateUserLoginHistoryCommandValidator : AbstractValidator -{ - public CreateUserLoginHistoryCommandValidator() - { - RuleFor(x => x.UserId) - .NotEmpty().WithMessage("UserId is required."); - - RuleFor(x => x.IpAddress) - .NotEmpty().WithMessage("IP Address is required.") - .MaximumLength(50).WithMessage("IP Address cannot exceed 50 characters.") - .Must(BeValidIp).WithMessage("IP Address must be a valid IPv4 or IPv6 address."); - - RuleFor(x => x.Country) - .MaximumLength(100).WithMessage("Country cannot exceed 100 characters."); - - RuleFor(x => x.City) - .MaximumLength(100).WithMessage("City cannot exceed 100 characters."); - - RuleFor(x => x.Browser) - .MaximumLength(100).WithMessage("Browser cannot exceed 100 characters."); - - RuleFor(x => x.OS) - .MaximumLength(100).WithMessage("Operating System cannot exceed 100 characters."); - - RuleFor(x => x.Device) - .MaximumLength(50).WithMessage("Device cannot exceed 50 characters."); - } - - private bool BeValidIp(string ip) - { - return System.Net.IPAddress.TryParse(ip, out _); - } -} diff --git a/src/Application/UserLoginHistories/Delete/DeleteUserloginHistoryCommand.cs b/src/Application/UserLoginHistories/Delete/DeleteUserloginHistoryCommand.cs deleted file mode 100644 index 893b0c9..0000000 --- a/src/Application/UserLoginHistories/Delete/DeleteUserloginHistoryCommand.cs +++ /dev/null @@ -1,5 +0,0 @@ -using Application.Abstractions.Messaging; - -namespace Application.UserLoginHistories.Delete; - -public sealed record DeleteUserloginHistoryCommand(Guid Id) : ICommand; diff --git a/src/Application/UserLoginHistories/Delete/DeleteUserloginHistoryCommandHandler.cs b/src/Application/UserLoginHistories/Delete/DeleteUserloginHistoryCommandHandler.cs deleted file mode 100644 index edf4bf0..0000000 --- a/src/Application/UserLoginHistories/Delete/DeleteUserloginHistoryCommandHandler.cs +++ /dev/null @@ -1,30 +0,0 @@ -using Application.Abstractions.Authentication; -using Application.Abstractions.Data; -using Application.Abstractions.Messaging; -using Domain.UserLoginHistories; -using Microsoft.EntityFrameworkCore; -using SharedKernel; - -namespace Application.UserLoginHistories.Delete; - -internal class DeleteUserloginHistoryCommandHandler(IApplicationDbContext context, IUserContext userContext) - : ICommandHandler -{ - - public async Task Handle(DeleteUserloginHistoryCommand command, CancellationToken cancellationToken) - { - UserLoginHistory? UserLoginHistory = await context.UserLoginHistory - .SingleOrDefaultAsync(t => t.Id == command.Id && t.UserId == userContext.UserId, cancellationToken); - - if (UserLoginHistory is null) - { - return Result.Failure(UserloginHistoryErrors.NotFound(command.Id)); - } - - context.UserLoginHistory.Remove(UserLoginHistory); - - await context.SaveChangesAsync(cancellationToken); - - return Result.Success(); - } -} diff --git a/src/Application/UserLoginHistories/Delete/DeleteUserloginHistoryCommandValidator.cs b/src/Application/UserLoginHistories/Delete/DeleteUserloginHistoryCommandValidator.cs deleted file mode 100644 index 97afc07..0000000 --- a/src/Application/UserLoginHistories/Delete/DeleteUserloginHistoryCommandValidator.cs +++ /dev/null @@ -1,11 +0,0 @@ -using FluentValidation; - -namespace Application.UserLoginHistories.Delete; - -internal sealed class DeleteUserloginHistoryCommandValidator : AbstractValidator -{ - public DeleteUserloginHistoryCommandValidator() - { - RuleFor(c => c.Id).NotEmpty(); - } -} diff --git a/src/Application/UserLoginHistories/GetByUserId/GetUserLoginHistoryByUserIdQuery.cs b/src/Application/UserLoginHistories/GetByUserId/GetUserLoginHistoryByUserIdQuery.cs deleted file mode 100644 index 781f191..0000000 --- a/src/Application/UserLoginHistories/GetByUserId/GetUserLoginHistoryByUserIdQuery.cs +++ /dev/null @@ -1,13 +0,0 @@ -using Application.Abstractions.Messaging; - -namespace Application.UserLoginHistories.GetByUserId; - -public sealed record GetUserLoginHistoryByUserIdQuery : IQuery> -{ - public Guid UserId { get; } - - public GetUserLoginHistoryByUserIdQuery(Guid userId) - { - UserId = userId; - } -} diff --git a/src/Application/UserLoginHistories/GetByUserId/GetUserLoginHistoryByUserIdQueryHandler.cs b/src/Application/UserLoginHistories/GetByUserId/GetUserLoginHistoryByUserIdQueryHandler.cs deleted file mode 100644 index 7e2361e..0000000 --- a/src/Application/UserLoginHistories/GetByUserId/GetUserLoginHistoryByUserIdQueryHandler.cs +++ /dev/null @@ -1,41 +0,0 @@ -using Application.Abstractions.Authentication; -using Application.Abstractions.Data; -using Application.Abstractions.Messaging; -using Domain.Users; -using Microsoft.EntityFrameworkCore; -using SharedKernel; - -namespace Application.UserLoginHistories.GetByUserId; - -internal sealed class GetUserLoginHistoryByUserIdQueryHandler( - IApplicationDbContext context, IUserContext userContext) - : IQueryHandler> -{ - public async Task>> Handle(GetUserLoginHistoryByUserIdQuery query, CancellationToken cancellationToken) - { - if (query.UserId != userContext.UserId) - { - return Result.Failure>(UserErrors.Unauthorized()); - } - - List HistoryEntities = await context.UserLoginHistory - .Where(h => h.UserId == query.UserId) - .Select(entity => new UserLoginHistoryResponse - { - Id = entity.Id, - UserId = entity.UserId, - IpAddress = entity.IpAddress, - Country = entity.Country, - City = entity.City, - Browser = entity.Browser, - OS = entity.OS, - Device = entity.Device, - LogInTime = entity.LogInTime, - LogoutTime = entity.LogoutTime, - Status = entity.Status, - }) - .ToListAsync(cancellationToken); - - return HistoryEntities; - } -} diff --git a/src/Application/UserLoginHistories/GetByUserId/UserLoginHistoryResponse.cs b/src/Application/UserLoginHistories/GetByUserId/UserLoginHistoryResponse.cs deleted file mode 100644 index f826f48..0000000 --- a/src/Application/UserLoginHistories/GetByUserId/UserLoginHistoryResponse.cs +++ /dev/null @@ -1,19 +0,0 @@ -using Domain.UserLoginHistories; - -namespace Application.UserLoginHistories.GetByUserId; - -public sealed class UserLoginHistoryResponse -{ - public Guid Id { get; set; } - public Guid UserId { get; set; } - public string IpAddress { get; set; } - public string Country { get; set; } - public string City { get; set; } - public string Browser { get; set; } - public string OS { get; set; } - public string Device { get; set; } - public DateTime LogInTime { get; set; } - public DateTime? LogoutTime { get; set; } - public LoginStatus Status { get; set; } -} - diff --git a/src/Application/UserProfiles/Create/CreateUserProfileCommand.cs b/src/Application/UserProfiles/Create/CreateUserProfileCommand.cs deleted file mode 100644 index d194351..0000000 --- a/src/Application/UserProfiles/Create/CreateUserProfileCommand.cs +++ /dev/null @@ -1,15 +0,0 @@ -using Application.Abstractions.Messaging; - -namespace Application.UserProfiles.Create; - -public sealed class CreateUserProfileCommand : ICommand -{ - public Guid UserId { get; set; } // Fk of User.Id - public string Address { get; set; } - public string City { get; set; } - public string Country { get; set; } - public string PostalCode { get; set; } - public string ProfileImageUrl { get; set; } - public DateOnly DateOfBirth { get; set; } - -} diff --git a/src/Application/UserProfiles/Create/CreateUserProfileCommandHandler.cs b/src/Application/UserProfiles/Create/CreateUserProfileCommandHandler.cs deleted file mode 100644 index 89d8243..0000000 --- a/src/Application/UserProfiles/Create/CreateUserProfileCommandHandler.cs +++ /dev/null @@ -1,69 +0,0 @@ -using Application.Abstractions.Authentication; -using Application.Abstractions.Data; -using Application.Abstractions.Messaging; -using Domain.UserProfiles; -using Domain.Users; -using Microsoft.EntityFrameworkCore; -using SharedKernel; - -namespace Application.UserProfiles.Create; - -// this is technically create and update operation - -internal sealed class CreateUserProfileCommandHandler( - IApplicationDbContext context, - IUserContext userContext) : ICommandHandler -{ - public async Task> Handle(CreateUserProfileCommand command, CancellationToken cancellationToken) - { - - if (userContext.UserId != command.UserId) - { - return Result.Failure(UserErrors.Unauthorized()); - } - - User? existingUser = await context.Users.AsNoTracking() - .SingleOrDefaultAsync(u => u.Id == command.UserId, cancellationToken); - - if (existingUser is null) - { - return Result.Failure(UserErrors.NotFound(command.UserId)); - } - - // Check if a profile exists - UserProfile? existingProfile = await context.UserProfile - .SingleOrDefaultAsync(up => up.UserId == command.UserId, cancellationToken); - - if (existingProfile is not null) - { - // Override existing profile - existingProfile.Address = command.Address; - existingProfile.City = command.City; - existingProfile.Country = command.Country; - existingProfile.PostalCode = command.PostalCode; - existingProfile.ProfileImageUrl = command.ProfileImageUrl; - existingProfile.DateOfBirth = command.DateOfBirth; - } - else - { - // Create new profile - var userProfile = new UserProfile - { - UserId = command.UserId, - Address = command.Address, - City = command.City, - Country = command.Country, - PostalCode = command.PostalCode, - ProfileImageUrl = command.ProfileImageUrl, - DateOfBirth = command.DateOfBirth, - }; - - await context.UserProfile.AddAsync(userProfile, cancellationToken); - } - - await context.SaveChangesAsync(cancellationToken); - - return Result.Success(command.UserId); - } -} - diff --git a/src/Application/UserProfiles/Create/CreateUserProfileCommandValidator.cs b/src/Application/UserProfiles/Create/CreateUserProfileCommandValidator.cs deleted file mode 100644 index a102eb3..0000000 --- a/src/Application/UserProfiles/Create/CreateUserProfileCommandValidator.cs +++ /dev/null @@ -1,48 +0,0 @@ -using FluentValidation; - -namespace Application.UserProfiles.Create; - -internal sealed class CreateUserProfileCommandValidator : AbstractValidator -{ - public CreateUserProfileCommandValidator() - { - RuleFor(x => x.UserId) - .NotEmpty().WithMessage("UserId is required."); - - RuleFor(x => x.Address) - .NotEmpty().WithMessage("Address is required.") - .MaximumLength(255); - - RuleFor(x => x.City) - .NotEmpty().WithMessage("City is required.") - .MaximumLength(100); - - RuleFor(x => x.Country) - .NotEmpty().WithMessage("Country is required.") - .MaximumLength(100); - - RuleFor(x => x.PostalCode) - .NotEmpty().WithMessage("Postal code is required.") - .MaximumLength(100); - - RuleFor(x => x.ProfileImageUrl) - .NotEmpty().WithMessage("Profile image URL is required.") - .MaximumLength(255) - .Must(BeAValidUrl).WithMessage("Profile image URL must be a valid URL."); - - RuleFor(x => x.DateOfBirth) - .NotEmpty().WithMessage("Date of birth is required.") - .Must(BeAValidBirthDate).WithMessage("Date of birth must be a valid past date."); - } - - private bool BeAValidBirthDate(DateOnly date) - { - return date < DateOnly.FromDateTime(DateTime.Today); // Must be in the past and at least 10 years ago - } - - private bool BeAValidUrl(string url) - { - return Uri.TryCreate(url, UriKind.Absolute, out _); - } - -} diff --git a/src/Application/UserProfiles/Get/GetUserProfileQuery.cs b/src/Application/UserProfiles/Get/GetUserProfileQuery.cs deleted file mode 100644 index f6a13fd..0000000 --- a/src/Application/UserProfiles/Get/GetUserProfileQuery.cs +++ /dev/null @@ -1,6 +0,0 @@ -using Application.Abstractions.Messaging; -using Application.UserProfiles.Get; - -namespace Application.UserProfiles.Get; - -public sealed record GetUserProfileQuery(Guid UserId) : IQuery; diff --git a/src/Application/UserProfiles/Get/GetUserProfileQueryHandler.cs b/src/Application/UserProfiles/Get/GetUserProfileQueryHandler.cs deleted file mode 100644 index e345265..0000000 --- a/src/Application/UserProfiles/Get/GetUserProfileQueryHandler.cs +++ /dev/null @@ -1,44 +0,0 @@ -using Application.Abstractions.Authentication; -using Application.Abstractions.Data; -using Application.Abstractions.Messaging; -using Application.UserProfiles.Create; -using Domain.Users; -using Microsoft.EntityFrameworkCore; -using SharedKernel; - -namespace Application.UserProfiles.Get; - -internal sealed class GetUserProfileQueryHandler( - IApplicationDbContext context, - IUserContext userContext) - : IQueryHandler -{ - public async Task> Handle(GetUserProfileQuery query, CancellationToken cancellationToken) - { - if (query.UserId != userContext.UserId) - { - return Result.Failure(UserErrors.Unauthorized()); - } - - UserProfileResponse? userProfile = await context.UserProfile - .Where(up => up.UserId == query.UserId) - .Select(up => new UserProfileResponse - { - UserId = up.UserId, - Address = up.Address, - City = up.City, - Country = up.Country, - PostalCode = up.PostalCode, - ProfileImageUrl = up.ProfileImageUrl, - DateOfBirth = up.DateOfBirth - }) - .SingleOrDefaultAsync(cancellationToken); - - if (userProfile is null) - { - return Result.Failure(UserErrors.NotFound(query.UserId)); - } - - return Result.Success(userProfile); - } -} diff --git a/src/Application/UserProfiles/Get/UserProfileResponse.cs b/src/Application/UserProfiles/Get/UserProfileResponse.cs deleted file mode 100644 index be17070..0000000 --- a/src/Application/UserProfiles/Get/UserProfileResponse.cs +++ /dev/null @@ -1,13 +0,0 @@ - -namespace Application.UserProfiles.Get; - -public sealed class UserProfileResponse -{ - public Guid UserId { get; set; } // Fk of User.Id - public string Address { get; set; } - public string City { get; set; } - public string Country { get; set; } - public string PostalCode { get; set; } - public string ProfileImageUrl { get; set; } - public DateOnly DateOfBirth { get; set; } -} diff --git a/src/Domain/BusinessMembers/BusinessMember.cs b/src/Domain/BusinessMembers/BusinessMember.cs deleted file mode 100644 index 3254d99..0000000 --- a/src/Domain/BusinessMembers/BusinessMember.cs +++ /dev/null @@ -1,12 +0,0 @@ -using SharedKernel; - -namespace Domain.BusinessMembers; - -public class BusinessMember : Entity -{ - public Guid Id { get; set; } - public Guid BusinessId { get; set; } - public Guid UserId { get; set; } - public Guid RoleId { get; set; } - public DateTime JoinedAt { get; set; } -} diff --git a/src/Domain/Businesses/Business.cs b/src/Domain/Businesses/Business.cs deleted file mode 100644 index 468ff7a..0000000 --- a/src/Domain/Businesses/Business.cs +++ /dev/null @@ -1,20 +0,0 @@ -using SharedKernel; - -namespace Domain.Businesses; - -public sealed class Business : Entity -{ - public Guid Id { get; set; } - - public Guid OwnerUserId { get; set; } - - public string BusinessName { get; set; } - - public string IndustryType { get; set; } - - public string LogoUrl { get; set; } - - public BusinessStatus Status { get; set; } - - public DateTime CreatedAt { get; set; } -} diff --git a/src/Domain/Businesses/BusinessStatus.cs b/src/Domain/Businesses/BusinessStatus.cs deleted file mode 100644 index 47d6de4..0000000 --- a/src/Domain/Businesses/BusinessStatus.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Domain.Businesses; - -public enum BusinessStatus -{ - Inactive = 0, - Active = 1, -} diff --git a/src/Domain/Customers/Customer.cs b/src/Domain/Customers/Customer.cs deleted file mode 100644 index 075e676..0000000 --- a/src/Domain/Customers/Customer.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using SharedKernel; - -namespace Domain.Customers; - -public class Customer : Entity -{ - public Guid Id { get; set; } - public string Name { get; set; } - public string Email { get; set; } - public string Address { get; set; } -} diff --git a/src/Domain/Enums/Status.cs b/src/Domain/Enums/Status.cs index 97a16da..b3ae6ec 100644 --- a/src/Domain/Enums/Status.cs +++ b/src/Domain/Enums/Status.cs @@ -1,7 +1,7 @@ -namespace Domain.Enums; +//namespace Domain.Enums; -public enum Status -{ - Active = 1, - Inactive = 0 -} +//public enum Status +//{ +// Active = 1, +// Inactive = 0 +//} diff --git a/src/Domain/MfaLogs/MfaLog.cs b/src/Domain/MfaLogs/MfaLog.cs deleted file mode 100644 index 5bd90e8..0000000 --- a/src/Domain/MfaLogs/MfaLog.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System; - -namespace Domain.MfaLogs; - -public class MfaLog -{ - public Guid Id { get; set; } - - public Guid UserId { get; set; } - - public DateTime LoginTime { get; set; } - - public DateTime CreatedAt { get; set; } = DateTime.UtcNow; - - public DateTime? UpdatedAt { get; set; } - - public string IpAddress { get; set; } = null!; - - public string Device { get; set; } = null!; - - // Remove JsonConverter - let EF Core handle the conversion - public MfaLogStatus Status { get; set; } -} - -public enum MfaLogStatus -{ - Success = 1, - Failed = 2 -} diff --git a/src/Domain/MfaLogs/MfaLogErrors.cs b/src/Domain/MfaLogs/MfaLogErrors.cs deleted file mode 100644 index 70abe5b..0000000 --- a/src/Domain/MfaLogs/MfaLogErrors.cs +++ /dev/null @@ -1,11 +0,0 @@ - -using SharedKernel; - -namespace Domain.MfaLogs; - -public static class MfaLogErrors -{ - public static Error NotFound(Guid id) => - Error.NotFound("MfaLog.NotFound", $"MfaLog with Id {id} not found."); -} - diff --git a/src/Domain/MfaSettings/MfaSetting.cs b/src/Domain/MfaSettings/MfaSetting.cs deleted file mode 100644 index 7ee327c..0000000 --- a/src/Domain/MfaSettings/MfaSetting.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System; -using System.Text.Json.Serialization; -using Domain.Users; -using SharedKernel; - -namespace Domain.MfaSettings; - -public class MfaSetting : Entity -{ - public Guid Id { get; set; } - - public Guid UserId { get; set; } - public User User { get; set; } - - public string SecretKey { get; set; } = string.Empty; - - public string? BackupCodes { get; set; } - - public MfaMethod Method { get; set; } - - public bool Enabled { get; set; } -} - - -public enum MfaMethod -{ - TOTP = 0, - SMS = 1, - EMAIL = 2 -} diff --git a/src/Domain/PasswordResets/PasswordReset.cs b/src/Domain/PasswordResets/PasswordReset.cs deleted file mode 100644 index 9cedb6e..0000000 --- a/src/Domain/PasswordResets/PasswordReset.cs +++ /dev/null @@ -1,12 +0,0 @@ -using SharedKernel; - -namespace Domain.PasswordResets; - -public class PasswordReset : Entity -{ - public Guid PrId { get; set; } - public Guid UserId { get; set; } - public string Token { get; set; } = string.Empty; - public DateTime ExpiresAt { get; set; } - public bool Used { get; set; } -} diff --git a/src/Domain/PasswordResets/PasswordResetCreatedDomainEvent.cs b/src/Domain/PasswordResets/PasswordResetCreatedDomainEvent.cs deleted file mode 100644 index e73d572..0000000 --- a/src/Domain/PasswordResets/PasswordResetCreatedDomainEvent.cs +++ /dev/null @@ -1,5 +0,0 @@ -using SharedKernel; - -namespace Domain.PasswordResets; - -public sealed record PasswordResetCreatedDomainEvent(Guid PrId) : IDomainEvent; diff --git a/src/Domain/PasswordResets/PasswordResetDeletedDomainEvent.cs b/src/Domain/PasswordResets/PasswordResetDeletedDomainEvent.cs deleted file mode 100644 index d22a7cc..0000000 --- a/src/Domain/PasswordResets/PasswordResetDeletedDomainEvent.cs +++ /dev/null @@ -1,5 +0,0 @@ -using SharedKernel; - -namespace Domain.PasswordResets; - -public sealed record PasswordResetDeletedDomainEvent(Guid PrId) : IDomainEvent; diff --git a/src/Domain/PasswordResets/PasswordResetErrors.cs b/src/Domain/PasswordResets/PasswordResetErrors.cs deleted file mode 100644 index 1497d96..0000000 --- a/src/Domain/PasswordResets/PasswordResetErrors.cs +++ /dev/null @@ -1,14 +0,0 @@ -using SharedKernel; - -namespace Domain.PasswordResets; - -public static class PasswordResetsErrors -{ - public static Error AlreadyCompleted(Guid PrId) => Error.Problem( - "PasswordReset.AlreadyCompleted", - $"The Password reset with Id = '{PrId}' is already completed."); - - public static Error NotFound(Guid PrId) => Error.NotFound( - "PasswordReset.NotFound", - $"The password reset with the Id = '{PrId}' was not found"); -} diff --git a/src/Domain/UserLoginHistories/LoginStatus.cs b/src/Domain/UserLoginHistories/LoginStatus.cs deleted file mode 100644 index d3b80a9..0000000 --- a/src/Domain/UserLoginHistories/LoginStatus.cs +++ /dev/null @@ -1,8 +0,0 @@ - -namespace Domain.UserLoginHistories; - -public enum LoginStatus -{ - Succeed = 1, - Failed = 0, -} diff --git a/src/Domain/UserLoginHistories/UserLoginHistory.cs b/src/Domain/UserLoginHistories/UserLoginHistory.cs deleted file mode 100644 index 46e5cb7..0000000 --- a/src/Domain/UserLoginHistories/UserLoginHistory.cs +++ /dev/null @@ -1,20 +0,0 @@ -using Domain.Users; -using SharedKernel; - -namespace Domain.UserLoginHistories; - -public sealed class UserLoginHistory : Entity -{ - public Guid Id { get; set; } - public Guid UserId { get; set; } - public string IpAddress { get; set; } - public string Country { get; set; } - public string City { get; set; } - public string Browser { get; set; } - public string OS { get; set; } - public string Device { get; set; } - public DateTime LogInTime { get; set; } - public DateTime? LogoutTime { get; set; } - public LoginStatus Status { get; set; } // Default value = login succeed - public User? User { get; set; } // Navigation property to User (only used for configuring ER) -} diff --git a/src/Domain/UserLoginHistories/UserLoginHistoryErrors.cs b/src/Domain/UserLoginHistories/UserLoginHistoryErrors.cs deleted file mode 100644 index 761de10..0000000 --- a/src/Domain/UserLoginHistories/UserLoginHistoryErrors.cs +++ /dev/null @@ -1,12 +0,0 @@ -using SharedKernel; - -namespace Domain.UserLoginHistories; - -public static class UserloginHistoryErrors -{ - - public static Error NotFound(Guid Id) => Error.NotFound( - "UserloginHistory.NotFound", - $"The user history with the Id = '{Id}' was not found"); -} - diff --git a/src/Domain/UserProfiles/UserProfile.cs b/src/Domain/UserProfiles/UserProfile.cs deleted file mode 100644 index 7b4b10f..0000000 --- a/src/Domain/UserProfiles/UserProfile.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Domain.Users; -using SharedKernel; - -namespace Domain.UserProfiles; - -public sealed class UserProfile : Entity -{ - public Guid UserId { get; set; } // Fk of User.Id - public string Address { get; set; } - public string City { get; set; } - public string Country { get; set; } - public string PostalCode { get; set; } - public string ProfileImageUrl { get; set; } - public DateOnly DateOfBirth { get; set; } - public User User { get; set; } //Navigation property to User -} diff --git a/src/Domain/Users/User.cs b/src/Domain/Users/User.cs index 78f51bb..0375cf1 100644 --- a/src/Domain/Users/User.cs +++ b/src/Domain/Users/User.cs @@ -1,6 +1,4 @@ -using Domain.UserLoginHistories; -using Domain.UserProfiles; -using SharedKernel; +using SharedKernel; namespace Domain.Users; @@ -25,8 +23,4 @@ public sealed class User : Entity public DateTime CreatedAt { get; set; } public DateTime UpdatedAt { get; set; } - - public UserProfile? Profile { get; set; } // Navigation property to UserProfile 1:1 - - public ICollection LoginHistories { get; set; } = []; // Navigation collection property to LoginHistory 1:N } diff --git a/src/Infrastructure/BusinessMembers/BusinessMemberConfiguration.cs b/src/Infrastructure/BusinessMembers/BusinessMemberConfiguration.cs deleted file mode 100644 index 516d538..0000000 --- a/src/Infrastructure/BusinessMembers/BusinessMemberConfiguration.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Domain.Businesses; -using Domain.BusinessMembers; -using Domain.Roles; -using Domain.Users; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Metadata.Builders; - -namespace Infrastructure.BusinessMembers; - -public class BusinessMemberConfiguration : IEntityTypeConfiguration -{ - public void Configure(EntityTypeBuilder builder) - { - builder.HasKey(bm => bm.Id); - - builder.HasOne() - .WithMany() - .HasForeignKey(bm => bm.BusinessId); - - builder.HasOne() - .WithMany() - .HasForeignKey(bm => bm.UserId); - - builder.HasOne() - .WithMany() - .HasForeignKey(bm => bm.RoleId); - - builder.Property(bm => bm.JoinedAt) - .IsRequired(); - } -} \ No newline at end of file diff --git a/src/Infrastructure/Businesses/BusinessConfiguration.cs b/src/Infrastructure/Businesses/BusinessConfiguration.cs deleted file mode 100644 index afd3d4b..0000000 --- a/src/Infrastructure/Businesses/BusinessConfiguration.cs +++ /dev/null @@ -1,35 +0,0 @@ -using Domain.Businesses; -using Domain.Users; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Metadata.Builders; - -namespace Infrastructure.Businesses; - -internal sealed class BusinessConfiguration : IEntityTypeConfiguration -{ - public void Configure(EntityTypeBuilder builder) - { - builder.HasKey(x => x.Id); - - builder.Property(x => x.BusinessName) - .IsRequired() - .HasMaxLength(200); - - builder.Property(x => x.IndustryType) - .HasMaxLength(100); - - builder.Property(x => x.LogoUrl) - .HasMaxLength(255); - - builder.Property(x => x.CreatedAt) - .HasDefaultValueSql("CURRENT_TIMESTAMP"); - - builder.Property(x => x.OwnerUserId) - .IsRequired(); - - builder.HasOne() - .WithMany() - .HasForeignKey(x => x.OwnerUserId) - .OnDelete(DeleteBehavior.Cascade); - } -} diff --git a/src/Infrastructure/Database/ApplicationDbContext.cs b/src/Infrastructure/Database/ApplicationDbContext.cs index 61616e4..97a0c57 100644 --- a/src/Infrastructure/Database/ApplicationDbContext.cs +++ b/src/Infrastructure/Database/ApplicationDbContext.cs @@ -1,18 +1,11 @@ -using System.Collections.Generic; using Application.Abstractions.Data; using Domain.Areas; using Domain.AuditLogs; -using Domain.Businesses; -using Domain.BusinessMembers; using Domain.Countries; -using Domain.Customers; using Domain.Districts; using Domain.EmailVerification; using Domain.Localities; -using Domain.MfaLogs; -using Domain.MfaSettings; using Domain.Otps; -using Domain.PasswordResets; using Domain.Permissions; using Domain.Regions; using Domain.RolePermissions; @@ -20,17 +13,11 @@ using Domain.SmsConfigs; using Domain.SmtpConfigs; using Domain.Todos; -using Domain.UserLoginHistories; -using Domain.UserProfiles; using Domain.Users; -using Infrastructure.Authentication; using Infrastructure.DomainEvents; -using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.ChangeTracking; -using Org.BouncyCastle.Crypto.Generators; using SharedKernel; -using static Microsoft.EntityFrameworkCore.DbLoggerCategory.Database; namespace Infrastructure.Database; @@ -41,19 +28,11 @@ public sealed class ApplicationDbContext( { public DbSet Users { get; set; } public DbSet EmailVerifications { get; set; } - public DbSet PasswordReset { get; set; } - public DbSet Customers { get; set; } public DbSet TodoItems { get; set; } - public DbSet UserLoginHistory { get; set; } - public DbSet UserProfile { get; set; } public DbSet Permissions { get; set; } public DbSet RolePermissions { get; set; } public DbSet Roles { get; set; } - public DbSet Businesses { get; set; } - public DbSet BusinessMembers { get; set; } public DbSet AuditLogs { get; set; } - public DbSet MfaLogs { get; set; } - public DbSet MfaSettings { get; set; } public DbSet Otp { get; set; } public DbSet SmtpConfig { get; set; } public DbSet SmsConfig { get; set; } diff --git a/src/Infrastructure/Database/Migrations/20251228090611_Stable_5.1.Designer.cs b/src/Infrastructure/Database/Migrations/20251228090611_Stable_5.1.Designer.cs new file mode 100644 index 0000000..9bf25ec --- /dev/null +++ b/src/Infrastructure/Database/Migrations/20251228090611_Stable_5.1.Designer.cs @@ -0,0 +1,1117 @@ +// +using System; +using System.Collections.Generic; +using Infrastructure.Database; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace Infrastructure.Migrations +{ + [DbContext(typeof(ApplicationDbContext))] + [Migration("20251228090611_Stable_5.1")] + partial class Stable_51 + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasDefaultSchema("public") + .HasAnnotation("ProductVersion", "10.0.0") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("Domain.Areas.Area", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("CountryId") + .HasColumnType("uuid") + .HasColumnName("country_id"); + + b.Property("DistrictId") + .HasColumnType("uuid") + .HasColumnName("district_id"); + + b.Property("IsActive") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(true) + .HasColumnName("is_active"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)") + .HasColumnName("name"); + + b.Property("Type") + .HasColumnType("integer") + .HasColumnName("type"); + + b.HasKey("Id") + .HasName("pk_areas"); + + b.HasIndex("CountryId") + .HasDatabaseName("ix_areas_country_id"); + + b.HasIndex("DistrictId") + .HasDatabaseName("ix_areas_district_id"); + + b.HasIndex("Name") + .HasDatabaseName("ix_areas_name"); + + b.HasIndex("Type") + .HasDatabaseName("ix_areas_type"); + + b.ToTable("areas", "public"); + }); + + modelBuilder.Entity("Domain.AuditLogs.AuditLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("Action") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)") + .HasColumnName("action"); + + b.Property("BusinessId") + .HasColumnType("uuid") + .HasColumnName("business_id"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text") + .HasColumnName("description"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.Property("UserId") + .HasColumnType("uuid") + .HasColumnName("user_id"); + + b.HasKey("Id") + .HasName("pk_audit_logs"); + + b.HasIndex("BusinessId") + .HasDatabaseName("ix_audit_logs_business_id"); + + b.HasIndex("UserId") + .HasDatabaseName("ix_audit_logs_user_id"); + + b.ToTable("audit_logs", "public"); + }); + + modelBuilder.Entity("Domain.Countries.Country", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("Capital") + .IsRequired() + .HasMaxLength(150) + .HasColumnType("character varying(150)") + .HasColumnName("capital"); + + b.Property("IsActive") + .HasColumnType("boolean") + .HasColumnName("is_active"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(150) + .HasColumnType("character varying(150)") + .HasColumnName("name"); + + b.Property("PhoneCode") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("character varying(20)") + .HasColumnName("phone_code"); + + b.HasKey("Id") + .HasName("pk_countries"); + + b.ToTable("countries", "public"); + }); + + modelBuilder.Entity("Domain.Districts.District", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("CountryId") + .HasColumnType("uuid") + .HasColumnName("country_id"); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at") + .HasDefaultValueSql("NOW()"); + + b.Property("IsActive") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(true) + .HasColumnName("is_active"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)") + .HasColumnName("name"); + + b.Property("RegionId") + .HasColumnType("uuid") + .HasColumnName("region_id"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.HasKey("Id") + .HasName("pk_districts"); + + b.HasIndex("CountryId") + .HasDatabaseName("ix_districts_country_id"); + + b.HasIndex("RegionId") + .HasDatabaseName("ix_districts_region_id"); + + b.ToTable("districts", "public"); + }); + + modelBuilder.Entity("Domain.EmailVerification.EmailVerifications", b => + { + b.Property("EvId") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("ev_id"); + + b.Property("ExpiresAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("expires_at"); + + b.Property("Token") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)") + .HasColumnName("token"); + + b.Property("UserId") + .HasColumnType("uuid") + .HasColumnName("user_id"); + + b.Property("VerifiedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("verified_at"); + + b.HasKey("EvId") + .HasName("pk_email_verifications"); + + b.ToTable("email_verifications", "public"); + }); + + modelBuilder.Entity("Domain.Localities.Locality", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("AreaId") + .HasColumnType("uuid") + .HasColumnName("area_id"); + + b.Property("CountryId") + .HasColumnType("uuid") + .HasColumnName("country_id"); + + b.Property("IsActive") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(true) + .HasColumnName("is_active"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)") + .HasColumnName("name"); + + b.Property("Type") + .HasColumnType("integer") + .HasColumnName("type"); + + b.HasKey("Id") + .HasName("pk_localities"); + + b.HasIndex("AreaId") + .HasDatabaseName("ix_localities_area_id"); + + b.HasIndex("CountryId") + .HasDatabaseName("ix_localities_country_id"); + + b.HasIndex("IsActive") + .HasDatabaseName("ix_localities_is_active"); + + b.HasIndex("Name") + .HasDatabaseName("ix_localities_name"); + + b.HasIndex("Type") + .HasDatabaseName("ix_localities_type"); + + b.HasIndex("AreaId", "IsActive") + .HasDatabaseName("ix_localities_area_id_is_active"); + + b.HasIndex("AreaId", "Name") + .IsUnique() + .HasDatabaseName("ix_localities_area_id_name"); + + b.HasIndex("AreaId", "Type", "IsActive") + .HasDatabaseName("ix_localities_area_id_type_is_active"); + + b.HasIndex("CountryId", "AreaId", "IsActive") + .HasDatabaseName("ix_localities_country_id_area_id_is_active"); + + b.ToTable("localities", "public"); + }); + + modelBuilder.Entity("Domain.Otps.Otp", b => + { + b.Property("OtpId") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("otp_id"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at"); + + b.Property("Delay") + .HasColumnType("interval") + .HasColumnName("delay"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("email"); + + b.Property("IsExpired") + .HasColumnType("boolean") + .HasColumnName("is_expired"); + + b.Property("OtpToken") + .IsRequired() + .HasMaxLength(16) + .HasColumnType("character varying(16)") + .HasColumnName("otp_token"); + + b.Property("PhoneNumber") + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("phone_number"); + + b.HasKey("OtpId") + .HasName("pk_otp"); + + b.ToTable("otp", "public"); + }); + + modelBuilder.Entity("Domain.Permissions.Permission", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("Code") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)") + .HasColumnName("code"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text") + .HasColumnName("description"); + + b.HasKey("Id") + .HasName("pk_permissions"); + + b.HasIndex("Code") + .IsUnique() + .HasDatabaseName("ix_permissions_code"); + + b.ToTable("permissions", "public"); + }); + + modelBuilder.Entity("Domain.Regions.Region", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("CountryId") + .HasColumnType("uuid") + .HasColumnName("country_id"); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at") + .HasDefaultValueSql("NOW()"); + + b.Property("IsActive") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(true) + .HasColumnName("is_active"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)") + .HasColumnName("name"); + + b.Property("RegionType") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)") + .HasColumnName("region_type"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.HasKey("Id") + .HasName("pk_regions"); + + b.HasIndex("CountryId") + .HasDatabaseName("ix_regions_country_id"); + + b.ToTable("regions", "public"); + }); + + modelBuilder.Entity("Domain.RolePermissions.RolePermission", b => + { + b.Property("RoleId") + .HasColumnType("uuid") + .HasColumnName("role_id"); + + b.Property("PermissionId") + .HasColumnType("uuid") + .HasColumnName("permission_id"); + + b.HasKey("RoleId", "PermissionId") + .HasName("pk_role_permissions"); + + b.HasIndex("PermissionId") + .HasDatabaseName("ix_role_permissions_permission_id"); + + b.HasIndex("RoleId") + .HasDatabaseName("ix_role_permissions_role_id"); + + b.ToTable("role_permissions", "public"); + }); + + modelBuilder.Entity("Domain.Roles.Role", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text") + .HasColumnName("description"); + + b.Property("RoleName") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)") + .HasColumnName("role_name"); + + b.HasKey("Id") + .HasName("pk_roles"); + + b.HasIndex("RoleName") + .IsUnique() + .HasDatabaseName("ix_roles_role_name"); + + b.ToTable("roles", "public"); + + b.HasData( + new + { + Id = new Guid("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"), + Description = "System Administrator with full access", + RoleName = "Administrator" + }, + new + { + Id = new Guid("bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb"), + Description = "Support Engineers", + RoleName = "Support" + }, + new + { + Id = new Guid("cccccccc-cccc-cccc-cccc-cccccccccccc"), + Description = "Helps in Analysis", + RoleName = "Analytics" + }, + new + { + Id = new Guid("dddddddd-dddd-dddd-dddd-dddddddddddd"), + Description = "Asses the payments", + RoleName = "PaymentAdmin" + }, + new + { + Id = new Guid("eeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee"), + Description = "Common User", + RoleName = "Client" + }); + }); + + modelBuilder.Entity("Domain.SmsConfigs.SmsConfig", b => + { + b.Property("SmsId") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("sms_id"); + + b.Property("SmsToken") + .IsRequired() + .HasMaxLength(4) + .HasColumnType("character varying(4)") + .HasColumnName("sms_token"); + + b.HasKey("SmsId") + .HasName("pk_sms_config"); + + b.ToTable("sms_config", "public"); + }); + + modelBuilder.Entity("Domain.SmtpConfigs.SmtpConfig", b => + { + b.Property("SmtpId") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("smtp_id"); + + b.Property("EnableSsl") + .HasColumnType("boolean") + .HasColumnName("enable_ssl"); + + b.Property("Host") + .IsRequired() + .HasColumnType("text") + .HasColumnName("host"); + + b.Property("Password") + .IsRequired() + .HasMaxLength(16) + .HasColumnType("character varying(16)") + .HasColumnName("password"); + + b.Property("Port") + .HasColumnType("integer") + .HasColumnName("port"); + + b.Property("SenderEmail") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("sender_email"); + + b.Property("Username") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("username"); + + b.HasKey("SmtpId") + .HasName("pk_smtp_config"); + + b.ToTable("smtp_config", "public"); + }); + + modelBuilder.Entity("Domain.Todos.TodoItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("CompletedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("completed_at"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text") + .HasColumnName("description"); + + b.Property("DueDate") + .HasColumnType("timestamp with time zone") + .HasColumnName("due_date"); + + b.Property("IsCompleted") + .HasColumnType("boolean") + .HasColumnName("is_completed"); + + b.PrimitiveCollection>("Labels") + .IsRequired() + .HasColumnType("text[]") + .HasColumnName("labels"); + + b.Property("Priority") + .HasColumnType("integer") + .HasColumnName("priority"); + + b.Property("UserId") + .HasColumnType("uuid") + .HasColumnName("user_id"); + + b.HasKey("Id") + .HasName("pk_todo_items"); + + b.HasIndex("UserId") + .HasDatabaseName("ix_todo_items_user_id"); + + b.ToTable("todo_items", "public"); + }); + + modelBuilder.Entity("Domain.Users.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at"); + + b.Property("Email") + .IsRequired() + .HasMaxLength(150) + .HasColumnType("character varying(150)") + .HasColumnName("email"); + + b.Property("FullName") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)") + .HasColumnName("full_name"); + + b.Property("IsEmailVerified") + .HasColumnType("boolean") + .HasColumnName("is_email_verified"); + + b.Property("IsMFAEnabled") + .HasColumnType("boolean") + .HasColumnName("is_mfa_enabled"); + + b.Property("PasswordHash") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)") + .HasColumnName("password_hash"); + + b.Property("Phone") + .HasMaxLength(20) + .HasColumnType("character varying(20)") + .HasColumnName("phone"); + + b.Property("Status") + .HasColumnType("integer") + .HasColumnName("status"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.HasKey("Id") + .HasName("pk_users"); + + b.HasIndex("Email") + .IsUnique() + .HasDatabaseName("ix_users_email"); + + b.ToTable("users", "public"); + + b.HasData( + new + { + Id = new Guid("11111111-1111-1111-1111-111111111111"), + CreatedAt = new DateTime(2025, 12, 16, 0, 0, 0, 0, DateTimeKind.Utc), + Email = "user1@gmail.com", + FullName = "System Admin", + IsEmailVerified = false, + IsMFAEnabled = false, + PasswordHash = "0CB47CF84CA0824A48EB7CDAD0B13AC83D6742E85A21B8A0FF58A235C2050DE9-ED1FD94795D453D2320B0A5444D4B31E", + Status = 0, + UpdatedAt = new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified) + }, + new + { + Id = new Guid("22222222-2222-2222-2222-222222222222"), + CreatedAt = new DateTime(2025, 12, 16, 0, 0, 0, 0, DateTimeKind.Utc), + Email = "user2@gmail.com", + FullName = "Normal User", + IsEmailVerified = false, + IsMFAEnabled = false, + PasswordHash = "CDFCF4E8D89841B7A49EC50581EC9F5CA3AB0A93A9F23B78C69839B18BE43752-C4F0917170B9972DDE5015CBCFE31786", + Status = 0, + UpdatedAt = new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified) + }, + new + { + Id = new Guid("33333333-3333-3333-3333-333333333333"), + CreatedAt = new DateTime(2025, 12, 16, 0, 0, 0, 0, DateTimeKind.Utc), + Email = "user3@gmail.com", + FullName = "Demo User", + IsEmailVerified = false, + IsMFAEnabled = false, + PasswordHash = "D3A38C51393060353567AF0865FC91B4E435AB433D177AF056F79BA1AEEADA0B-852250D8F97163710CF73F51EF6EE70D", + Status = 0, + UpdatedAt = new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified) + }); + }); + + modelBuilder.Entity("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreApplication", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("text") + .HasColumnName("id"); + + b.Property("ApplicationType") + .HasMaxLength(50) + .HasColumnType("character varying(50)") + .HasColumnName("application_type"); + + b.Property("ClientId") + .HasMaxLength(100) + .HasColumnType("character varying(100)") + .HasColumnName("client_id"); + + b.Property("ClientSecret") + .HasColumnType("text") + .HasColumnName("client_secret"); + + b.Property("ClientType") + .HasMaxLength(50) + .HasColumnType("character varying(50)") + .HasColumnName("client_type"); + + b.Property("ConcurrencyToken") + .IsConcurrencyToken() + .HasMaxLength(50) + .HasColumnType("character varying(50)") + .HasColumnName("concurrency_token"); + + b.Property("ConsentType") + .HasMaxLength(50) + .HasColumnType("character varying(50)") + .HasColumnName("consent_type"); + + b.Property("DisplayName") + .HasColumnType("text") + .HasColumnName("display_name"); + + b.Property("DisplayNames") + .HasColumnType("text") + .HasColumnName("display_names"); + + b.Property("JsonWebKeySet") + .HasColumnType("text") + .HasColumnName("json_web_key_set"); + + b.Property("Permissions") + .HasColumnType("text") + .HasColumnName("permissions"); + + b.Property("PostLogoutRedirectUris") + .HasColumnType("text") + .HasColumnName("post_logout_redirect_uris"); + + b.Property("Properties") + .HasColumnType("text") + .HasColumnName("properties"); + + b.Property("RedirectUris") + .HasColumnType("text") + .HasColumnName("redirect_uris"); + + b.Property("Requirements") + .HasColumnType("text") + .HasColumnName("requirements"); + + b.Property("Settings") + .HasColumnType("text") + .HasColumnName("settings"); + + b.HasKey("Id") + .HasName("pk_open_iddict_applications"); + + b.HasIndex("ClientId") + .IsUnique() + .HasDatabaseName("ix_open_iddict_applications_client_id"); + + b.ToTable("OpenIddictApplications", "public"); + }); + + modelBuilder.Entity("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreAuthorization", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("text") + .HasColumnName("id"); + + b.Property("ApplicationId") + .HasColumnType("text") + .HasColumnName("application_id"); + + b.Property("ConcurrencyToken") + .IsConcurrencyToken() + .HasMaxLength(50) + .HasColumnType("character varying(50)") + .HasColumnName("concurrency_token"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone") + .HasColumnName("creation_date"); + + b.Property("Properties") + .HasColumnType("text") + .HasColumnName("properties"); + + b.Property("Scopes") + .HasColumnType("text") + .HasColumnName("scopes"); + + b.Property("Status") + .HasMaxLength(50) + .HasColumnType("character varying(50)") + .HasColumnName("status"); + + b.Property("Subject") + .HasMaxLength(400) + .HasColumnType("character varying(400)") + .HasColumnName("subject"); + + b.Property("Type") + .HasMaxLength(50) + .HasColumnType("character varying(50)") + .HasColumnName("type"); + + b.HasKey("Id") + .HasName("pk_open_iddict_authorizations"); + + b.HasIndex("ApplicationId", "Status", "Subject", "Type") + .HasDatabaseName("ix_open_iddict_authorizations_application_id_status_subject_type"); + + b.ToTable("OpenIddictAuthorizations", "public"); + }); + + modelBuilder.Entity("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreScope", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("text") + .HasColumnName("id"); + + b.Property("ConcurrencyToken") + .IsConcurrencyToken() + .HasMaxLength(50) + .HasColumnType("character varying(50)") + .HasColumnName("concurrency_token"); + + b.Property("Description") + .HasColumnType("text") + .HasColumnName("description"); + + b.Property("Descriptions") + .HasColumnType("text") + .HasColumnName("descriptions"); + + b.Property("DisplayName") + .HasColumnType("text") + .HasColumnName("display_name"); + + b.Property("DisplayNames") + .HasColumnType("text") + .HasColumnName("display_names"); + + b.Property("Name") + .HasMaxLength(200) + .HasColumnType("character varying(200)") + .HasColumnName("name"); + + b.Property("Properties") + .HasColumnType("text") + .HasColumnName("properties"); + + b.Property("Resources") + .HasColumnType("text") + .HasColumnName("resources"); + + b.HasKey("Id") + .HasName("pk_open_iddict_scopes"); + + b.HasIndex("Name") + .IsUnique() + .HasDatabaseName("ix_open_iddict_scopes_name"); + + b.ToTable("OpenIddictScopes", "public"); + }); + + modelBuilder.Entity("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreToken", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("text") + .HasColumnName("id"); + + b.Property("ApplicationId") + .HasColumnType("text") + .HasColumnName("application_id"); + + b.Property("AuthorizationId") + .HasColumnType("text") + .HasColumnName("authorization_id"); + + b.Property("ConcurrencyToken") + .IsConcurrencyToken() + .HasMaxLength(50) + .HasColumnType("character varying(50)") + .HasColumnName("concurrency_token"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone") + .HasColumnName("creation_date"); + + b.Property("ExpirationDate") + .HasColumnType("timestamp with time zone") + .HasColumnName("expiration_date"); + + b.Property("Payload") + .HasColumnType("text") + .HasColumnName("payload"); + + b.Property("Properties") + .HasColumnType("text") + .HasColumnName("properties"); + + b.Property("RedemptionDate") + .HasColumnType("timestamp with time zone") + .HasColumnName("redemption_date"); + + b.Property("ReferenceId") + .HasMaxLength(100) + .HasColumnType("character varying(100)") + .HasColumnName("reference_id"); + + b.Property("Status") + .HasMaxLength(50) + .HasColumnType("character varying(50)") + .HasColumnName("status"); + + b.Property("Subject") + .HasMaxLength(400) + .HasColumnType("character varying(400)") + .HasColumnName("subject"); + + b.Property("Type") + .HasMaxLength(150) + .HasColumnType("character varying(150)") + .HasColumnName("type"); + + b.HasKey("Id") + .HasName("pk_open_iddict_tokens"); + + b.HasIndex("AuthorizationId") + .HasDatabaseName("ix_open_iddict_tokens_authorization_id"); + + b.HasIndex("ReferenceId") + .IsUnique() + .HasDatabaseName("ix_open_iddict_tokens_reference_id"); + + b.HasIndex("ApplicationId", "Status", "Subject", "Type") + .HasDatabaseName("ix_open_iddict_tokens_application_id_status_subject_type"); + + b.ToTable("OpenIddictTokens", "public"); + }); + + modelBuilder.Entity("Domain.Areas.Area", b => + { + b.HasOne("Domain.Districts.District", null) + .WithMany() + .HasForeignKey("DistrictId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired() + .HasConstraintName("fk_areas_districts_district_id"); + }); + + modelBuilder.Entity("Domain.AuditLogs.AuditLog", b => + { + b.HasOne("Domain.Users.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_audit_logs_users_user_id"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Domain.Districts.District", b => + { + b.HasOne("Domain.Countries.Country", "Country") + .WithMany() + .HasForeignKey("CountryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_districts_countries_country_id"); + + b.HasOne("Domain.Regions.Region", "Region") + .WithMany() + .HasForeignKey("RegionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_districts_regions_region_id"); + + b.Navigation("Country"); + + b.Navigation("Region"); + }); + + modelBuilder.Entity("Domain.Localities.Locality", b => + { + b.HasOne("Domain.Areas.Area", null) + .WithMany() + .HasForeignKey("AreaId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired() + .HasConstraintName("fk_localities_areas_area_id"); + }); + + modelBuilder.Entity("Domain.Regions.Region", b => + { + b.HasOne("Domain.Countries.Country", "Country") + .WithMany() + .HasForeignKey("CountryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_regions_countries_country_id"); + + b.Navigation("Country"); + }); + + modelBuilder.Entity("Domain.RolePermissions.RolePermission", b => + { + b.HasOne("Domain.Permissions.Permission", "Permission") + .WithMany() + .HasForeignKey("PermissionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_role_permissions_permissions_permission_id"); + + b.HasOne("Domain.Roles.Role", "Role") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_role_permissions_roles_role_id"); + + b.Navigation("Permission"); + + b.Navigation("Role"); + }); + + modelBuilder.Entity("Domain.Todos.TodoItem", b => + { + b.HasOne("Domain.Users.User", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_todo_items_users_user_id"); + }); + + modelBuilder.Entity("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreAuthorization", b => + { + b.HasOne("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreApplication", "Application") + .WithMany("Authorizations") + .HasForeignKey("ApplicationId") + .HasConstraintName("fk_open_iddict_authorizations_open_iddict_applications_application"); + + b.Navigation("Application"); + }); + + modelBuilder.Entity("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreToken", b => + { + b.HasOne("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreApplication", "Application") + .WithMany("Tokens") + .HasForeignKey("ApplicationId") + .HasConstraintName("fk_open_iddict_tokens_open_iddict_applications_application_id"); + + b.HasOne("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreAuthorization", "Authorization") + .WithMany("Tokens") + .HasForeignKey("AuthorizationId") + .HasConstraintName("fk_open_iddict_tokens_open_iddict_authorizations_authorization_id"); + + b.Navigation("Application"); + + b.Navigation("Authorization"); + }); + + modelBuilder.Entity("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreApplication", b => + { + b.Navigation("Authorizations"); + + b.Navigation("Tokens"); + }); + + modelBuilder.Entity("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreAuthorization", b => + { + b.Navigation("Tokens"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/Infrastructure/Database/Migrations/20251228090611_Stable_5.1.cs b/src/Infrastructure/Database/Migrations/20251228090611_Stable_5.1.cs new file mode 100644 index 0000000..564e6a3 --- /dev/null +++ b/src/Infrastructure/Database/Migrations/20251228090611_Stable_5.1.cs @@ -0,0 +1,283 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Infrastructure.Migrations +{ + /// + public partial class Stable_51 : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "business_members", + schema: "public"); + + migrationBuilder.DropTable( + name: "customers", + schema: "public"); + + migrationBuilder.DropTable( + name: "mfa_logs", + schema: "public"); + + migrationBuilder.DropTable( + name: "mfa_settings", + schema: "public"); + + migrationBuilder.DropTable( + name: "password_reset", + schema: "public"); + + migrationBuilder.DropTable( + name: "user_login_history", + schema: "public"); + + migrationBuilder.DropTable( + name: "user_profile", + schema: "public"); + + migrationBuilder.DropTable( + name: "businesses", + schema: "public"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "businesses", + schema: "public", + columns: table => new + { + id = table.Column(type: "uuid", nullable: false), + business_name = table.Column(type: "character varying(200)", maxLength: 200, nullable: false), + created_at = table.Column(type: "timestamp with time zone", nullable: false, defaultValueSql: "CURRENT_TIMESTAMP"), + industry_type = table.Column(type: "character varying(100)", maxLength: 100, nullable: false), + logo_url = table.Column(type: "character varying(255)", maxLength: 255, nullable: false), + owner_user_id = table.Column(type: "uuid", nullable: false), + status = table.Column(type: "integer", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("pk_businesses", x => x.id); + table.ForeignKey( + name: "fk_businesses_users_owner_user_id", + column: x => x.owner_user_id, + principalSchema: "public", + principalTable: "users", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "customers", + schema: "public", + columns: table => new + { + id = table.Column(type: "uuid", nullable: false), + address = table.Column(type: "text", nullable: false), + email = table.Column(type: "text", nullable: false), + name = table.Column(type: "text", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("pk_customers", x => x.id); + }); + + migrationBuilder.CreateTable( + name: "mfa_logs", + schema: "public", + columns: table => new + { + id = table.Column(type: "uuid", nullable: false), + created_at = table.Column(type: "timestamp with time zone", nullable: false, defaultValueSql: "NOW()"), + device = table.Column(type: "character varying(100)", maxLength: 100, nullable: false), + ip_address = table.Column(type: "character varying(50)", maxLength: 50, nullable: false), + login_time = table.Column(type: "timestamp with time zone", nullable: false), + status = table.Column(type: "integer", nullable: false), + updated_at = table.Column(type: "timestamp with time zone", nullable: true), + user_id = table.Column(type: "uuid", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("pk_mfa_logs", x => x.id); + }); + + migrationBuilder.CreateTable( + name: "mfa_settings", + schema: "public", + columns: table => new + { + id = table.Column(type: "uuid", nullable: false), + user_id = table.Column(type: "uuid", nullable: false), + backup_codes = table.Column(type: "text", nullable: true), + enabled = table.Column(type: "boolean", nullable: false, defaultValue: false), + method = table.Column(type: "integer", nullable: false), + secret_key = table.Column(type: "character varying(255)", maxLength: 255, nullable: false) + }, + constraints: table => + { + table.PrimaryKey("pk_mfa_settings", x => x.id); + table.ForeignKey( + name: "fk_mfa_settings_users_user_id", + column: x => x.user_id, + principalSchema: "public", + principalTable: "users", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "password_reset", + schema: "public", + columns: table => new + { + pr_id = table.Column(type: "uuid", nullable: false), + expires_at = table.Column(type: "timestamp with time zone", nullable: false), + token = table.Column(type: "character varying(255)", maxLength: 255, nullable: false), + used = table.Column(type: "boolean", nullable: false), + user_id = table.Column(type: "uuid", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("pk_password_reset", x => x.pr_id); + }); + + migrationBuilder.CreateTable( + name: "user_login_history", + schema: "public", + columns: table => new + { + id = table.Column(type: "uuid", nullable: false), + user_id = table.Column(type: "uuid", nullable: false), + browser = table.Column(type: "character varying(100)", maxLength: 100, nullable: false), + city = table.Column(type: "character varying(100)", maxLength: 100, nullable: false), + country = table.Column(type: "character varying(100)", maxLength: 100, nullable: false), + device = table.Column(type: "character varying(50)", maxLength: 50, nullable: false), + ip_address = table.Column(type: "character varying(50)", maxLength: 50, nullable: false), + log_in_time = table.Column(type: "timestamp with time zone", nullable: false), + logout_time = table.Column(type: "timestamp with time zone", nullable: true), + os = table.Column(type: "character varying(100)", maxLength: 100, nullable: false), + status = table.Column(type: "integer", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("pk_user_login_history", x => x.id); + table.ForeignKey( + name: "fk_user_login_history_users_user_id", + column: x => x.user_id, + principalSchema: "public", + principalTable: "users", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "user_profile", + schema: "public", + columns: table => new + { + user_id = table.Column(type: "uuid", nullable: false), + address = table.Column(type: "character varying(255)", maxLength: 255, nullable: false), + city = table.Column(type: "character varying(100)", maxLength: 100, nullable: false), + country = table.Column(type: "character varying(100)", maxLength: 100, nullable: false), + date_of_birth = table.Column(type: "date", nullable: false), + postal_code = table.Column(type: "character varying(100)", maxLength: 100, nullable: false), + profile_image_url = table.Column(type: "character varying(255)", maxLength: 255, nullable: false) + }, + constraints: table => + { + table.PrimaryKey("pk_user_profile", x => x.user_id); + table.ForeignKey( + name: "fk_user_profile_users_user_id", + column: x => x.user_id, + principalSchema: "public", + principalTable: "users", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "business_members", + schema: "public", + columns: table => new + { + id = table.Column(type: "uuid", nullable: false), + business_id = table.Column(type: "uuid", nullable: false), + joined_at = table.Column(type: "timestamp with time zone", nullable: false), + role_id = table.Column(type: "uuid", nullable: false), + user_id = table.Column(type: "uuid", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("pk_business_members", x => x.id); + table.ForeignKey( + name: "fk_business_members_businesses_business_id", + column: x => x.business_id, + principalSchema: "public", + principalTable: "businesses", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "fk_business_members_roles_role_id", + column: x => x.role_id, + principalSchema: "public", + principalTable: "roles", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "fk_business_members_users_user_id", + column: x => x.user_id, + principalSchema: "public", + principalTable: "users", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "ix_business_members_business_id", + schema: "public", + table: "business_members", + column: "business_id"); + + migrationBuilder.CreateIndex( + name: "ix_business_members_role_id", + schema: "public", + table: "business_members", + column: "role_id"); + + migrationBuilder.CreateIndex( + name: "ix_business_members_user_id", + schema: "public", + table: "business_members", + column: "user_id"); + + migrationBuilder.CreateIndex( + name: "ix_businesses_owner_user_id", + schema: "public", + table: "businesses", + column: "owner_user_id"); + + migrationBuilder.CreateIndex( + name: "ix_mfa_logs_user_id", + schema: "public", + table: "mfa_logs", + column: "user_id"); + + migrationBuilder.CreateIndex( + name: "ix_mfa_settings_user_id", + schema: "public", + table: "mfa_settings", + column: "user_id"); + + migrationBuilder.CreateIndex( + name: "ix_user_login_history_user_id", + schema: "public", + table: "user_login_history", + column: "user_id"); + } + } +} diff --git a/src/Infrastructure/Database/Migrations/ApplicationDbContextModelSnapshot.cs b/src/Infrastructure/Database/Migrations/ApplicationDbContextModelSnapshot.cs index 81adf82..e03978b 100644 --- a/src/Infrastructure/Database/Migrations/ApplicationDbContextModelSnapshot.cs +++ b/src/Infrastructure/Database/Migrations/ApplicationDbContextModelSnapshot.cs @@ -119,92 +119,6 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("audit_logs", "public"); }); - modelBuilder.Entity("Domain.BusinessMembers.BusinessMember", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid") - .HasColumnName("id"); - - b.Property("BusinessId") - .HasColumnType("uuid") - .HasColumnName("business_id"); - - b.Property("JoinedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("joined_at"); - - b.Property("RoleId") - .HasColumnType("uuid") - .HasColumnName("role_id"); - - b.Property("UserId") - .HasColumnType("uuid") - .HasColumnName("user_id"); - - b.HasKey("Id") - .HasName("pk_business_members"); - - b.HasIndex("BusinessId") - .HasDatabaseName("ix_business_members_business_id"); - - b.HasIndex("RoleId") - .HasDatabaseName("ix_business_members_role_id"); - - b.HasIndex("UserId") - .HasDatabaseName("ix_business_members_user_id"); - - b.ToTable("business_members", "public"); - }); - - modelBuilder.Entity("Domain.Businesses.Business", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid") - .HasColumnName("id"); - - b.Property("BusinessName") - .IsRequired() - .HasMaxLength(200) - .HasColumnType("character varying(200)") - .HasColumnName("business_name"); - - b.Property("CreatedAt") - .ValueGeneratedOnAdd() - .HasColumnType("timestamp with time zone") - .HasColumnName("created_at") - .HasDefaultValueSql("CURRENT_TIMESTAMP"); - - b.Property("IndustryType") - .IsRequired() - .HasMaxLength(100) - .HasColumnType("character varying(100)") - .HasColumnName("industry_type"); - - b.Property("LogoUrl") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("character varying(255)") - .HasColumnName("logo_url"); - - b.Property("OwnerUserId") - .HasColumnType("uuid") - .HasColumnName("owner_user_id"); - - b.Property("Status") - .HasColumnType("integer") - .HasColumnName("status"); - - b.HasKey("Id") - .HasName("pk_businesses"); - - b.HasIndex("OwnerUserId") - .HasDatabaseName("ix_businesses_owner_user_id"); - - b.ToTable("businesses", "public"); - }); - modelBuilder.Entity("Domain.Countries.Country", b => { b.Property("Id") @@ -240,34 +154,6 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("countries", "public"); }); - modelBuilder.Entity("Domain.Customers.Customer", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid") - .HasColumnName("id"); - - b.Property("Address") - .IsRequired() - .HasColumnType("text") - .HasColumnName("address"); - - b.Property("Email") - .IsRequired() - .HasColumnType("text") - .HasColumnName("email"); - - b.Property("Name") - .IsRequired() - .HasColumnType("text") - .HasColumnName("name"); - - b.HasKey("Id") - .HasName("pk_customers"); - - b.ToTable("customers", "public"); - }); - modelBuilder.Entity("Domain.Districts.District", b => { b.Property("Id") @@ -413,96 +299,6 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("localities", "public"); }); - modelBuilder.Entity("Domain.MfaLogs.MfaLog", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid") - .HasColumnName("id"); - - b.Property("CreatedAt") - .ValueGeneratedOnAdd() - .HasColumnType("timestamp with time zone") - .HasColumnName("created_at") - .HasDefaultValueSql("NOW()"); - - b.Property("Device") - .IsRequired() - .HasMaxLength(100) - .HasColumnType("character varying(100)") - .HasColumnName("device"); - - b.Property("IpAddress") - .IsRequired() - .HasMaxLength(50) - .HasColumnType("character varying(50)") - .HasColumnName("ip_address"); - - b.Property("LoginTime") - .HasColumnType("timestamp with time zone") - .HasColumnName("login_time"); - - b.Property("Status") - .HasColumnType("integer") - .HasColumnName("status"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("updated_at"); - - b.Property("UserId") - .HasColumnType("uuid") - .HasColumnName("user_id"); - - b.HasKey("Id") - .HasName("pk_mfa_logs"); - - b.HasIndex("UserId") - .HasDatabaseName("ix_mfa_logs_user_id"); - - b.ToTable("mfa_logs", "public"); - }); - - modelBuilder.Entity("Domain.MfaSettings.MfaSetting", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid") - .HasColumnName("id"); - - b.Property("BackupCodes") - .HasColumnType("text") - .HasColumnName("backup_codes"); - - b.Property("Enabled") - .ValueGeneratedOnAdd() - .HasColumnType("boolean") - .HasDefaultValue(false) - .HasColumnName("enabled"); - - b.Property("Method") - .HasColumnType("integer") - .HasColumnName("method"); - - b.Property("SecretKey") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("character varying(255)") - .HasColumnName("secret_key"); - - b.Property("UserId") - .HasColumnType("uuid") - .HasColumnName("user_id"); - - b.HasKey("Id") - .HasName("pk_mfa_settings"); - - b.HasIndex("UserId") - .HasDatabaseName("ix_mfa_settings_user_id"); - - b.ToTable("mfa_settings", "public"); - }); - modelBuilder.Entity("Domain.Otps.Otp", b => { b.Property("OtpId") @@ -544,37 +340,6 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("otp", "public"); }); - modelBuilder.Entity("Domain.PasswordResets.PasswordReset", b => - { - b.Property("PrId") - .ValueGeneratedOnAdd() - .HasColumnType("uuid") - .HasColumnName("pr_id"); - - b.Property("ExpiresAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("expires_at"); - - b.Property("Token") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("character varying(255)") - .HasColumnName("token"); - - b.Property("Used") - .HasColumnType("boolean") - .HasColumnName("used"); - - b.Property("UserId") - .HasColumnType("uuid") - .HasColumnName("user_id"); - - b.HasKey("PrId") - .HasName("pk_password_reset"); - - b.ToTable("password_reset", "public"); - }); - modelBuilder.Entity("Domain.Permissions.Permission", b => { b.Property("Id") @@ -846,120 +611,6 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("todo_items", "public"); }); - modelBuilder.Entity("Domain.UserLoginHistories.UserLoginHistory", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid") - .HasColumnName("id"); - - b.Property("Browser") - .IsRequired() - .HasMaxLength(100) - .HasColumnType("character varying(100)") - .HasColumnName("browser"); - - b.Property("City") - .IsRequired() - .HasMaxLength(100) - .HasColumnType("character varying(100)") - .HasColumnName("city"); - - b.Property("Country") - .IsRequired() - .HasMaxLength(100) - .HasColumnType("character varying(100)") - .HasColumnName("country"); - - b.Property("Device") - .IsRequired() - .HasMaxLength(50) - .HasColumnType("character varying(50)") - .HasColumnName("device"); - - b.Property("IpAddress") - .IsRequired() - .HasMaxLength(50) - .HasColumnType("character varying(50)") - .HasColumnName("ip_address"); - - b.Property("LogInTime") - .HasColumnType("timestamp with time zone") - .HasColumnName("log_in_time"); - - b.Property("LogoutTime") - .HasColumnType("timestamp with time zone") - .HasColumnName("logout_time"); - - b.Property("OS") - .IsRequired() - .HasMaxLength(100) - .HasColumnType("character varying(100)") - .HasColumnName("os"); - - b.Property("Status") - .HasColumnType("integer") - .HasColumnName("status"); - - b.Property("UserId") - .HasColumnType("uuid") - .HasColumnName("user_id"); - - b.HasKey("Id") - .HasName("pk_user_login_history"); - - b.HasIndex("UserId") - .HasDatabaseName("ix_user_login_history_user_id"); - - b.ToTable("user_login_history", "public"); - }); - - modelBuilder.Entity("Domain.UserProfiles.UserProfile", b => - { - b.Property("UserId") - .HasColumnType("uuid") - .HasColumnName("user_id"); - - b.Property("Address") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("character varying(255)") - .HasColumnName("address"); - - b.Property("City") - .IsRequired() - .HasMaxLength(100) - .HasColumnType("character varying(100)") - .HasColumnName("city"); - - b.Property("Country") - .IsRequired() - .HasMaxLength(100) - .HasColumnType("character varying(100)") - .HasColumnName("country"); - - b.Property("DateOfBirth") - .HasColumnType("date") - .HasColumnName("date_of_birth"); - - b.Property("PostalCode") - .IsRequired() - .HasMaxLength(100) - .HasColumnType("character varying(100)") - .HasColumnName("postal_code"); - - b.Property("ProfileImageUrl") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("character varying(255)") - .HasColumnName("profile_image_url"); - - b.HasKey("UserId") - .HasName("pk_user_profile"); - - b.ToTable("user_profile", "public"); - }); - modelBuilder.Entity("Domain.Users.User", b => { b.Property("Id") @@ -1345,40 +996,6 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Navigation("User"); }); - modelBuilder.Entity("Domain.BusinessMembers.BusinessMember", b => - { - b.HasOne("Domain.Businesses.Business", null) - .WithMany() - .HasForeignKey("BusinessId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_business_members_businesses_business_id"); - - b.HasOne("Domain.Roles.Role", null) - .WithMany() - .HasForeignKey("RoleId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_business_members_roles_role_id"); - - b.HasOne("Domain.Users.User", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_business_members_users_user_id"); - }); - - modelBuilder.Entity("Domain.Businesses.Business", b => - { - b.HasOne("Domain.Users.User", null) - .WithMany() - .HasForeignKey("OwnerUserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_businesses_users_owner_user_id"); - }); - modelBuilder.Entity("Domain.Districts.District", b => { b.HasOne("Domain.Countries.Country", "Country") @@ -1410,18 +1027,6 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasConstraintName("fk_localities_areas_area_id"); }); - modelBuilder.Entity("Domain.MfaSettings.MfaSetting", b => - { - b.HasOne("Domain.Users.User", "User") - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_mfa_settings_users_user_id"); - - b.Navigation("User"); - }); - modelBuilder.Entity("Domain.Regions.Region", b => { b.HasOne("Domain.Countries.Country", "Country") @@ -1465,30 +1070,6 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasConstraintName("fk_todo_items_users_user_id"); }); - modelBuilder.Entity("Domain.UserLoginHistories.UserLoginHistory", b => - { - b.HasOne("Domain.Users.User", "User") - .WithMany("LoginHistories") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_user_login_history_users_user_id"); - - b.Navigation("User"); - }); - - modelBuilder.Entity("Domain.UserProfiles.UserProfile", b => - { - b.HasOne("Domain.Users.User", "User") - .WithOne("Profile") - .HasForeignKey("Domain.UserProfiles.UserProfile", "UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_user_profile_users_user_id"); - - b.Navigation("User"); - }); - modelBuilder.Entity("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreAuthorization", b => { b.HasOne("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreApplication", "Application") @@ -1516,13 +1097,6 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Navigation("Authorization"); }); - modelBuilder.Entity("Domain.Users.User", b => - { - b.Navigation("LoginHistories"); - - b.Navigation("Profile"); - }); - modelBuilder.Entity("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreApplication", b => { b.Navigation("Authorizations"); diff --git a/src/Infrastructure/MfaLogs/MfaLogConfiguration.cs b/src/Infrastructure/MfaLogs/MfaLogConfiguration.cs deleted file mode 100644 index ea8e597..0000000 --- a/src/Infrastructure/MfaLogs/MfaLogConfiguration.cs +++ /dev/null @@ -1,27 +0,0 @@ -using Domain.MfaLogs; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Metadata.Builders; - -namespace Infrastructure.MfaLogs; - -public class MfaLogConfiguration : IEntityTypeConfiguration -{ - public void Configure(EntityTypeBuilder builder) - { - builder.HasKey(m => m.Id); - - builder.HasIndex(m => m.UserId); // Let EF Core generate the index name dynamically - - builder.Property(m => m.Id).IsRequired(); - builder.Property(m => m.UserId).IsRequired(); - builder.Property(m => m.LoginTime).IsRequired(); - builder.Property(m => m.CreatedAt).IsRequired().HasDefaultValueSql("NOW()"); - builder.Property(m => m.UpdatedAt).IsRequired(false); - builder.Property(m => m.IpAddress).HasMaxLength(50).IsRequired(); - builder.Property(m => m.Device).HasMaxLength(100).IsRequired(); - - builder.Property(m => m.Status) - .HasConversion() - .IsRequired(); - } -} diff --git a/src/Infrastructure/MfaSettings/MfasettingConfiguration.cs b/src/Infrastructure/MfaSettings/MfasettingConfiguration.cs deleted file mode 100644 index 1f794f1..0000000 --- a/src/Infrastructure/MfaSettings/MfasettingConfiguration.cs +++ /dev/null @@ -1,30 +0,0 @@ -using Domain.MfaSettings; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Metadata.Builders; - -namespace Infrastructure.MfaSettings; - -public class MfaSettingConfiguration : IEntityTypeConfiguration -{ - public void Configure(EntityTypeBuilder builder) - { - builder.HasKey(m => m.Id); - - builder.HasOne(m => m.User) - .WithMany() - .HasForeignKey(m => m.UserId) - .OnDelete(DeleteBehavior.Cascade); - - builder.HasIndex(m => m.UserId); - - builder.Property(m => m.Id).IsRequired(); - builder.Property(m => m.UserId).IsRequired(); - builder.Property(m => m.SecretKey).HasMaxLength(255).IsRequired(); - builder.Property(m => m.BackupCodes).HasColumnType("text").IsRequired(false); - builder.Property(m => m.Enabled).IsRequired().HasDefaultValue(false); - - builder.Property(m => m.Method) - .HasConversion() - .IsRequired(); - } -} diff --git a/src/Infrastructure/PasswordResets/PasswordResetConfiguration.cs b/src/Infrastructure/PasswordResets/PasswordResetConfiguration.cs deleted file mode 100644 index 4b763bd..0000000 --- a/src/Infrastructure/PasswordResets/PasswordResetConfiguration.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Domain.PasswordResets; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Metadata.Builders; -namespace Infrastructure.PasswordResets; - -public class PasswordResetConfiguration : IEntityTypeConfiguration -{ - public void Configure(EntityTypeBuilder builder) - { - builder.HasKey(c => c.PrId); - builder.Property(c => c.UserId).IsRequired(); - builder.Property(c => c.Token).IsRequired().HasMaxLength(255); - builder.Property(c => c.ExpiresAt).IsRequired(); - builder.Property(c => c.Used); - } -} diff --git a/src/Infrastructure/UserLoginHistories/UserLoginHistoryConfiguration.cs b/src/Infrastructure/UserLoginHistories/UserLoginHistoryConfiguration.cs deleted file mode 100644 index 341232d..0000000 --- a/src/Infrastructure/UserLoginHistories/UserLoginHistoryConfiguration.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Domain.UserLoginHistories; -using Domain.Users; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Metadata.Builders; -using LoginStatus = Domain.UserLoginHistories.LoginStatus; - -namespace Infrastructure.UserLoginHistories; - -public sealed class UserLoginHistoryConfiguration : IEntityTypeConfiguration -{ - public void Configure(EntityTypeBuilder builder) - { - builder.HasKey(u => u.Id); - builder.HasIndex(p => p.UserId); - - // Configure 1:N relationship with User - builder.HasOne(h => h.User) // ref nav - .WithMany(u => u.LoginHistories) // collection nav - .HasForeignKey(h => h.UserId) - .OnDelete(DeleteBehavior.Cascade); // gets deleted as primary is deleted. - - builder.Property(u => u.UserId).IsRequired(); - - builder.Property(u => u.IpAddress).IsRequired().HasMaxLength(50); - - builder.Property(u => u.Country).IsRequired().HasMaxLength(100); - - builder.Property(u => u.City).IsRequired().HasMaxLength(100); - - builder.Property(u => u.Browser).IsRequired().HasMaxLength(100); - - builder.Property(u => u.OS).IsRequired().HasMaxLength(100); - - builder.Property(u => u.Device).IsRequired().HasMaxLength(50); - - builder.Property(u => u.LogInTime).IsRequired(); - - builder.Property(u => u.LogoutTime); - - builder.Property(u => u.Status).IsRequired(); - } -} diff --git a/src/Infrastructure/UserProfiles/UserProfileConfiguration.cs b/src/Infrastructure/UserProfiles/UserProfileConfiguration.cs deleted file mode 100644 index bc9caa5..0000000 --- a/src/Infrastructure/UserProfiles/UserProfileConfiguration.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Domain.UserProfiles; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Metadata.Builders; - -namespace Infrastructure.UserProfiles; - -public class UserProfileConfiguration : IEntityTypeConfiguration -{ - public void Configure(EntityTypeBuilder builder) - { - // Configure 1:1 relationship with User - builder.HasOne(n => n.User) // nav - .WithOne(u => u.Profile) // inverse nav - .HasForeignKey(p => p.UserId) - .OnDelete(DeleteBehavior.Cascade); // gets deleted as parent (User) is deleted. - - builder.HasKey(p => p.UserId); - - builder.Property(p => p.Address).IsRequired().HasMaxLength(255); - - builder.Property(p => p.City).IsRequired().HasMaxLength(100); - - builder.Property(p => p.Country).IsRequired().HasMaxLength(100); - - builder.Property(p => p.PostalCode).IsRequired().HasMaxLength(100); - - builder.Property(p => p.ProfileImageUrl).IsRequired().HasMaxLength(255); - - builder.Property(x => x.DateOfBirth).IsRequired().HasColumnType("date"); // date only - } -} diff --git a/src/Web.Api/Endpoints/Auth/LogOut.cs b/src/Web.Api/Endpoints/Auth/LogOut.cs index 504d5b8..fbede83 100644 --- a/src/Web.Api/Endpoints/Auth/LogOut.cs +++ b/src/Web.Api/Endpoints/Auth/LogOut.cs @@ -1,7 +1,4 @@ -using Application.Abstractions.Messaging; -using Application.Businesses.Create; -using Domain.Businesses; -using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Authentication; namespace Web.Api.Endpoints.Auth; diff --git a/src/Web.Api/Endpoints/Auth/Me.cs b/src/Web.Api/Endpoints/Auth/Me.cs index 54bfcae..7b742ff 100644 --- a/src/Web.Api/Endpoints/Auth/Me.cs +++ b/src/Web.Api/Endpoints/Auth/Me.cs @@ -1,8 +1,5 @@ using System.Security.Claims; using Application.Abstractions.Authentication; -using Application.Abstractions.Messaging; -using Application.Businesses.Create; -using Domain.Businesses; using OpenIddict.Abstractions; namespace Web.Api.Endpoints.Auth; diff --git a/src/Web.Api/Endpoints/BusinessMembers/Create.cs b/src/Web.Api/Endpoints/BusinessMembers/Create.cs deleted file mode 100644 index 9e0bff6..0000000 --- a/src/Web.Api/Endpoints/BusinessMembers/Create.cs +++ /dev/null @@ -1,41 +0,0 @@ -using Application.Abstractions.Messaging; -using Application.BusinessMembers.Create; -using Web.Api.Extensions; -using Web.Api.Infrastructure; - -namespace Web.Api.Endpoints.BusinessMembers; - -public class Create : IEndpoint -{ - public sealed class Request - { - public Guid BusinessId { get; set; } - public Guid UserId { get; set; } - public Guid RoleId { get; set; } - } - - public void MapEndpoint(IEndpointRouteBuilder app) - { - app.MapPost("/business-members", async ( - Create.Request request, - ICommandHandler handler, - CancellationToken cancellationToken) => - { - var command = new CreateBusinessMemberCommand( - request.BusinessId, - request.UserId, - request.RoleId - ); - - SharedKernel.Result result = await handler.Handle(command, cancellationToken); - - return result.Match( - id => Results.Created($"/business-members/{id}", new { id }), - CustomResults.Problem - ); - }) - - .WithTags(Tags.BusinessMembers) - .RequireAuthorization(); - } -} diff --git a/src/Web.Api/Endpoints/BusinessMembers/Delete.cs b/src/Web.Api/Endpoints/BusinessMembers/Delete.cs deleted file mode 100644 index 0036878..0000000 --- a/src/Web.Api/Endpoints/BusinessMembers/Delete.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Application.Abstractions.Messaging; -using Application.BusinessMembers.Delete; -using Web.Api.Extensions; -using Web.Api.Infrastructure; - -namespace Web.Api.Endpoints.BusinessMembers; - -internal sealed class Delete : IEndpoint -{ - public void MapEndpoint(IEndpointRouteBuilder app) - { - app.MapDelete("/business-members/{id:guid}", async ( - Guid id, - ICommandHandler handler, - CancellationToken cancellationToken) => - { - var command = new DeleteBusinessMemberCommand(id); - SharedKernel.Result result = await handler.Handle(command, cancellationToken); - return result.Match(Results.Ok, CustomResults.Problem); - }) - .WithTags(Tags.BusinessMembers); - } -} diff --git a/src/Web.Api/Endpoints/BusinessMembers/Get.cs b/src/Web.Api/Endpoints/BusinessMembers/Get.cs deleted file mode 100644 index 3d5ca48..0000000 --- a/src/Web.Api/Endpoints/BusinessMembers/Get.cs +++ /dev/null @@ -1,25 +0,0 @@ -using Application.Abstractions.Messaging; -using Application.BusinessMembers.Get; -using Web.Api.Extensions; -using Web.Api.Infrastructure; - -namespace Web.Api.Endpoints.BusinessMembers; - -public class Get : IEndpoint -{ - public void MapEndpoint(IEndpointRouteBuilder app) - { - app.MapGet("/business-members", async ( - IQueryHandler> handler, - CancellationToken cancellationToken) => - { - var query = new GetBusinessMembersQuery(); - SharedKernel.Result> result = await handler.Handle(query, cancellationToken); - return result.Match(Results.Ok, CustomResults.Problem); - }) - .WithTags(Tags.BusinessMembers) - .RequireAuthorization(); - } -} - - diff --git a/src/Web.Api/Endpoints/BusinessMembers/GetById.cs b/src/Web.Api/Endpoints/BusinessMembers/GetById.cs deleted file mode 100644 index 79fa9d7..0000000 --- a/src/Web.Api/Endpoints/BusinessMembers/GetById.cs +++ /dev/null @@ -1,24 +0,0 @@ -using Application.Abstractions.Messaging; -using Application.BusinessMembers.GetById; -using Web.Api.Extensions; -using Web.Api.Infrastructure; - -namespace Web.Api.Endpoints.BusinessMembers; - -public class GetById : IEndpoint -{ - public void MapEndpoint(IEndpointRouteBuilder app) - { - app.MapGet("/business-members/{id:guid}", async ( - Guid id, - IQueryHandler handler, - CancellationToken cancellationToken) => - { - var query = new GetBusinessMemberByIdQuery(id); - SharedKernel.Result result = await handler.Handle(query, cancellationToken); - return result.Match(Results.Ok, CustomResults.Problem); - }) - .WithTags(Tags.BusinessMembers) - .RequireAuthorization(); - } -} diff --git a/src/Web.Api/Endpoints/BusinessMembers/Update.cs b/src/Web.Api/Endpoints/BusinessMembers/Update.cs deleted file mode 100644 index b8bccc6..0000000 --- a/src/Web.Api/Endpoints/BusinessMembers/Update.cs +++ /dev/null @@ -1,25 +0,0 @@ -using Application.Abstractions.Messaging; -using Application.BusinessMembers.Update; -using Web.Api.Extensions; -using Web.Api.Infrastructure; - -namespace Web.Api.Endpoints.BusinessMembers; - -public class Update : IEndpoint -{ - public void MapEndpoint(IEndpointRouteBuilder app) - { - app.MapPut("/business-members/{id:guid}",async( - Guid id, - UpdateBusinessMemberCommand request, - ICommandHandler handler, - CancellationToken cancellationToken) => - { - UpdateBusinessMemberCommand command = request with { Id = id }; - SharedKernel.Result result = await handler.Handle(command, cancellationToken); - return result.Match(Results.Ok, CustomResults.Problem); - }) - .WithTags(Tags.BusinessMembers) - .RequireAuthorization(); - } -} diff --git a/src/Web.Api/Endpoints/Businesses/Create.cs b/src/Web.Api/Endpoints/Businesses/Create.cs deleted file mode 100644 index 6189f37..0000000 --- a/src/Web.Api/Endpoints/Businesses/Create.cs +++ /dev/null @@ -1,47 +0,0 @@ -using Application.Abstractions.Messaging; -using Application.Businesses.Create; -using Domain.Businesses; -using SharedKernel; -using Web.Api.Extensions; -using Web.Api.Infrastructure; - -namespace Web.Api.Endpoints.Businesses; - -public class Create : IEndpoint -{ - public sealed class Request - { - public Guid OwnerUserId { get; set; } - public string BusinessName { get; set; } - public string IndustryType { get; set; } - public string LogoUrl { get; set; } - public BusinessStatus Status { get; set; } - } - - public void MapEndpoint(IEndpointRouteBuilder app) - { - app.MapPost("/businesses", async ( - Request request, - ICommandHandler handler, - CancellationToken cancellationToken) => - { - var command = new CreateBusinessCommand - { - OwnerUserId = request.OwnerUserId, - BusinessName = request.BusinessName, - IndustryType = request.IndustryType, - LogoUrl = request.LogoUrl, - Status = request.Status, - }; - - Result result = await handler.Handle(command, cancellationToken); - - return result.Match( - id => Results.Created($"/businesses/{id}", new { id }), - CustomResults.Problem - ); - }) - .WithTags(Tags.Businesses) - .RequireAuthorization(); - } -} diff --git a/src/Web.Api/Endpoints/Businesses/Delete.cs b/src/Web.Api/Endpoints/Businesses/Delete.cs deleted file mode 100644 index ff8a520..0000000 --- a/src/Web.Api/Endpoints/Businesses/Delete.cs +++ /dev/null @@ -1,27 +0,0 @@ -using Application.Abstractions.Messaging; -using Application.Businesses.Delete; -using SharedKernel; -using Web.Api.Extensions; -using Web.Api.Infrastructure; - -namespace Web.Api.Endpoints.Businesses; - -internal sealed class Delete : IEndpoint -{ - public void MapEndpoint(IEndpointRouteBuilder app) - { - app.MapDelete("/businesses/{id:guid}", async ( - Guid id, - ICommandHandler handler, - CancellationToken cancellationToken) => - { - var command = new DeleteBusinessCommand(id); - - Result result = await handler.Handle(command, cancellationToken); - - return result.Match(Results.NoContent, CustomResults.Problem); - }) - .WithTags(Tags.Businesses) - .RequireAuthorization(); - } -} diff --git a/src/Web.Api/Endpoints/Businesses/Get.cs b/src/Web.Api/Endpoints/Businesses/Get.cs deleted file mode 100644 index 5ca93d6..0000000 --- a/src/Web.Api/Endpoints/Businesses/Get.cs +++ /dev/null @@ -1,26 +0,0 @@ -using Application.Abstractions.Authentication; -using Application.Abstractions.Messaging; -using Application.Businesses.Get; -using SharedKernel; -using Web.Api.Extensions; -using Web.Api.Infrastructure; - -namespace Web.Api.Endpoints.Businesses; - -public class Get : IEndpoint -{ - public void MapEndpoint(IEndpointRouteBuilder app) - { - app.MapGet("/businesses", async ( - IQueryHandler> handler, - IUserContext userContext, - CancellationToken cancellationToken) => - { - var query = new GetBusinessesQuery(); - Result> result = await handler.Handle(query, cancellationToken); - return result.Match(Results.Ok, CustomResults.Problem); - }) - .WithTags(Tags.Businesses) - .RequireAuthorization(); - } -} diff --git a/src/Web.Api/Endpoints/Businesses/GetById.cs b/src/Web.Api/Endpoints/Businesses/GetById.cs deleted file mode 100644 index d12dfdb..0000000 --- a/src/Web.Api/Endpoints/Businesses/GetById.cs +++ /dev/null @@ -1,24 +0,0 @@ -using Application.Abstractions.Messaging; -using Application.Businesses.GetById; -using Web.Api.Extensions; -using Web.Api.Infrastructure; - -namespace Web.Api.Endpoints.Businesses; - -public class GetById : IEndpoint -{ - public void MapEndpoint(IEndpointRouteBuilder app) - { - app.MapGet("/businesses/{id:guid}", async ( - Guid id, - IQueryHandler handler, - CancellationToken cancellationToken) => - { - var query = new GetBusinessByIdQuery(id); - SharedKernel.Result result = await handler.Handle(query, cancellationToken); - return result.Match(Results.Ok, CustomResults.Problem); - }) - .WithTags(Tags.Businesses) - .RequireAuthorization(); - } -} diff --git a/src/Web.Api/Endpoints/Businesses/Update.cs b/src/Web.Api/Endpoints/Businesses/Update.cs deleted file mode 100644 index 4de1f4d..0000000 --- a/src/Web.Api/Endpoints/Businesses/Update.cs +++ /dev/null @@ -1,43 +0,0 @@ -using Application.Abstractions.Messaging; -using Application.Businesses.Update; -using Domain.Businesses; -using SharedKernel; -using Web.Api.Extensions; -using Web.Api.Infrastructure; - -namespace Web.Api.Endpoints.Businesses; - -public class Update : IEndpoint -{ - public sealed class Request - { - public string BusinessName { get; set; } - public string IndustryType { get; set; } - public string LogoUrl { get; set; } - public BusinessStatus Status { get; set; } - } - - public void MapEndpoint(IEndpointRouteBuilder app) - { - app.MapPut("/businesses/{id:guid}", static async ( - Guid id, - Request request, - ICommandHandler handler, - CancellationToken cancellationToken) => - { - var command = new UpdateBusinessCommand - { - Id = id, - BusinessName = request.BusinessName, - IndustryType = request.IndustryType, - LogoUrl = request.LogoUrl, - Status = request.Status, - }; - - Result result = await handler.Handle(command, cancellationToken); - return result.Match(Results.NoContent, CustomResults.Problem); - }) - .WithTags(Tags.Businesses) - .RequireAuthorization(); - } -} diff --git a/src/Web.Api/Endpoints/ClientApps/Create.cs b/src/Web.Api/Endpoints/ClientApps/Create.cs index 352e891..87ccc47 100644 --- a/src/Web.Api/Endpoints/ClientApps/Create.cs +++ b/src/Web.Api/Endpoints/ClientApps/Create.cs @@ -1,8 +1,6 @@ using Application.Abstractions.Messaging; -using Application.BusinessMembers.Create; using Application.ClientApps.Create; using SharedKernel; -using static Microsoft.EntityFrameworkCore.DbLoggerCategory.Database; namespace Web.Api.Endpoints.ClientApps; diff --git a/src/Web.Api/Endpoints/Customers/Create.cs b/src/Web.Api/Endpoints/Customers/Create.cs deleted file mode 100644 index a2c26f0..0000000 --- a/src/Web.Api/Endpoints/Customers/Create.cs +++ /dev/null @@ -1,41 +0,0 @@ - -using Application.Abstractions.Messaging; -using Application.Customers.Create; -using Application.Todos.Create; -using SharedKernel; -using Web.Api.Extensions; -using Web.Api.Infrastructure; - -namespace Web.Api.Endpoints.Customers; - -public class Create : IEndpoint -{ - public sealed class Request - { - public string Name { get; set; } - public string Email { get; set; } - public string Address { get; set; } - } - - public void MapEndpoint(IEndpointRouteBuilder app) - { - app.MapPost(ApiRoutes.Create(Base.Customers), async ( - Request request, - ICommandHandler handler, - CancellationToken cancellationToken) => - { - var command = new CreateCustomerCommand - { - Name = request.Name, - Email = request.Email, - Address = request.Address - }; - - Result result = await handler.Handle(command, cancellationToken); - - return result.Match(Results.Ok, CustomResults.Problem); - }) - .WithTags(Tags.Customers) - .RequireAuthorization(); - } -} diff --git a/src/Web.Api/Endpoints/MfaLogs/Create.cs b/src/Web.Api/Endpoints/MfaLogs/Create.cs deleted file mode 100644 index b65ae60..0000000 --- a/src/Web.Api/Endpoints/MfaLogs/Create.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Application.Abstractions.Messaging; -using Application.MfaLogs.Create; -using Domain.MfaLogs; -using SharedKernel; -using Web.Api.Extensions; -using Web.Api.Infrastructure; - -namespace Web.Api.Endpoints.MfaLogs; - -public class Create : IEndpoint -{ - public void MapEndpoint(IEndpointRouteBuilder app) - { - app.MapPost(ApiRoutes.Create(Base.Mfalogs), async ( - Request request, - ICommandHandler handler, - CancellationToken cancellationToken) => - { - var command = new CreateMfaLogCommand - { - UserId = request.UserId, - LoginTime = request.LoginTime, - IpAddress = request.IpAddress, - Device = request.Device, - Status = request.Status - }; - - Result result = await handler.Handle(command, cancellationToken); - return result.Match(Results.Ok, CustomResults.Problem); - }) - .WithTags(Tags.MfaLogs) - .RequireAuthorization(); - } - - public sealed record Request( - Guid UserId, - DateTime LoginTime, - string IpAddress, - string Device, - MfaLogStatus Status - ); -} diff --git a/src/Web.Api/Endpoints/MfaLogs/Delete.cs b/src/Web.Api/Endpoints/MfaLogs/Delete.cs deleted file mode 100644 index 0a9f3cc..0000000 --- a/src/Web.Api/Endpoints/MfaLogs/Delete.cs +++ /dev/null @@ -1,35 +0,0 @@ -using Application.Abstractions.Data; -using Domain.MfaLogs; -using Microsoft.EntityFrameworkCore; -using SharedKernel; - -namespace Web.Api.Endpoints.MfaLogs; - -internal sealed class Delete : IEndpoint -{ - public void MapEndpoint(IEndpointRouteBuilder app) - { - app.MapDelete(ApiRoutes.Delete(Base.Mfalogs), async ( - Guid id, - IApplicationDbContext context, - CancellationToken cancellationToken) => - { - MfaLog? mfaLog = await context.MfaLogs - .SingleOrDefaultAsync(x => x.Id == id, cancellationToken); - - if (mfaLog is null) - { - return Results.NotFound(Result.Failure(MfaLogErrors.NotFound(id))); - } - - context.MfaLogs.Remove(mfaLog); - await context.SaveChangesAsync(cancellationToken); - - return Results.Ok(Result.Success()); - }) - .WithTags(Tags.MfaLogs) - .RequireAuthorization() - .WithSummary("Delete an MFA Log entry") - .WithDescription("Deletes an MFA Log entry by Id"); - } -} diff --git a/src/Web.Api/Endpoints/MfaLogs/Get.cs b/src/Web.Api/Endpoints/MfaLogs/Get.cs deleted file mode 100644 index d6d5727..0000000 --- a/src/Web.Api/Endpoints/MfaLogs/Get.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Application.Abstractions.Messaging; -using Application.MfaLogs.Get; -using SharedKernel; -using Web.Api.Extensions; -using Web.Api.Infrastructure; - -namespace Web.Api.Endpoints.MfaLogs; - -internal sealed class Get : IEndpoint -{ - public void MapEndpoint(IEndpointRouteBuilder app) - { - app.MapGet(ApiRoutes.GetAll(Base.Mfalogs), async ( - IQueryHandler> handler, - CancellationToken cancellationToken) => - { - var query = new GetMfaLogQuery(); - - Result> result = await handler.Handle(query, cancellationToken); - - return result.Match( - logs => Results.Ok(logs), - error => CustomResults.Problem(error) - ); - }) - .WithTags(Tags.MfaLogs) - .RequireAuthorization() - .WithSummary("Get MFA logs for current user") - .WithDescription("Retrieves all MFA authentication logs for the currently authenticated user, ordered by most recent login time."); - } -} diff --git a/src/Web.Api/Endpoints/MfaLogs/GetById.cs b/src/Web.Api/Endpoints/MfaLogs/GetById.cs deleted file mode 100644 index 2d95f6d..0000000 --- a/src/Web.Api/Endpoints/MfaLogs/GetById.cs +++ /dev/null @@ -1,28 +0,0 @@ -using Application.Abstractions.Messaging; -using Application.MfaLogs.GetById; -using SharedKernel; -using Web.Api.Extensions; -using Web.Api.Infrastructure; - -namespace Web.Api.Endpoints.MfaLogs; - -internal sealed class GetById : IEndpoint -{ - public void MapEndpoint(IEndpointRouteBuilder app) - { - app.MapGet(ApiRoutes.GetById(Base.Mfalogs), async ( - Guid id, - IQueryHandler handler, - CancellationToken cancellationToken) => - { - var query = new GetMfaLogByIdQuery(id); - - Result result = - await handler.Handle(query, cancellationToken); - - return result.Match(Results.Ok, CustomResults.Problem); - }) - .WithTags(Tags.MfaLogs) - .RequireAuthorization(); - } -} diff --git a/src/Web.Api/Endpoints/MfaLogs/Update.cs b/src/Web.Api/Endpoints/MfaLogs/Update.cs deleted file mode 100644 index 7b2fd6e..0000000 --- a/src/Web.Api/Endpoints/MfaLogs/Update.cs +++ /dev/null @@ -1,47 +0,0 @@ -using Application.Abstractions.Messaging; -using Application.MfaLogs.Update; -using Domain.MfaLogs; -using SharedKernel; -using Web.Api.Extensions; -using Web.Api.Infrastructure; - -namespace Web.Api.Endpoints.MfaLogs; - -internal sealed class Update : IEndpoint -{ - public void MapEndpoint(IEndpointRouteBuilder app) - { - app.MapPut(ApiRoutes.Update(Base.Mfalogs), async ( - Guid id, - Request request, - ICommandHandler handler, - CancellationToken cancellationToken) => - { - var command = new UpdateMfaLogCommand( - MfaLogId: id, - LoginTime: request.LoginTime, - IpAddress: request.IpAddress, - Device: request.Device, - Status: request.Status - ); - - Result result = await handler.Handle(command, cancellationToken); - - return result.Match( - () => Results.Ok(new { Id = id, Message = "MFA log updated successfully." }), - error => CustomResults.Problem(error) - ); - }) - .WithTags(Tags.MfaLogs) - .RequireAuthorization() - .WithSummary("Update an MFA Log entry") - .WithDescription("Updates the LoginTime, IpAddress, Device and Status of an MFA Log"); - } - - public sealed record Request( - DateTime LoginTime, - string IpAddress, - string Device, - MfaLogStatus Status - ); -} diff --git a/src/Web.Api/Endpoints/MfaSettings/Create.cs b/src/Web.Api/Endpoints/MfaSettings/Create.cs deleted file mode 100644 index 01906fa..0000000 --- a/src/Web.Api/Endpoints/MfaSettings/Create.cs +++ /dev/null @@ -1,44 +0,0 @@ -using Application.Abstractions.Messaging; -using Application.MfaSettings.Create; -using Domain.MfaSettings; -using SharedKernel; -using Web.Api.Extensions; -using Web.Api.Infrastructure; - -namespace Web.Api.Endpoints.MfaSettings; - -internal sealed class Create : IEndpoint -{ - public sealed class Request - { - public Guid UserId { get; set; } - public string SecretKey { get; set; } = string.Empty; - public string BackupCodes { get; set; } = string.Empty; - public MfaMethod Method { get; set; } - public bool Enabled { get; set; } - } - - public void MapEndpoint(IEndpointRouteBuilder app) - { - app.MapPost(ApiRoutes.Create(Base.MfaSettings), async ( - Request request, - ICommandHandler handler, - CancellationToken cancellationToken) => - { - var command = new CreateMfaSettingCommand - { - UserId = request.UserId, - SecretKey = request.SecretKey, - BackupCodes = request.BackupCodes, - Method = request.Method, - Enabled = request.Enabled - }; - - Result result = await handler.Handle(command, cancellationToken); - - return result.Match(Results.Ok, CustomResults.Problem); - }) - .WithTags(Tags.MfaSettings) - .RequireAuthorization(); - } -} diff --git a/src/Web.Api/Endpoints/MfaSettings/Delete.cs b/src/Web.Api/Endpoints/MfaSettings/Delete.cs deleted file mode 100644 index e6c03fe..0000000 --- a/src/Web.Api/Endpoints/MfaSettings/Delete.cs +++ /dev/null @@ -1,27 +0,0 @@ -using Application.Abstractions.Messaging; -using Application.MfaSettings.Delete; -using SharedKernel; -using Web.Api.Extensions; -using Web.Api.Infrastructure; - -namespace Web.Api.Endpoints.MfaSettings; - -internal sealed class Delete : IEndpoint -{ - public void MapEndpoint(IEndpointRouteBuilder app) - { - app.MapDelete(ApiRoutes.Delete(Base.MfaSettings), async ( - Guid id, - ICommandHandler handler, - CancellationToken cancellationToken) => - { - var command = new DeleteMfaSettingCommand(id); - - Result result = await handler.Handle(command, cancellationToken); - - return result.Match(Results.NoContent, CustomResults.Problem); - }) - .WithTags(Tags.MfaSettings) - .RequireAuthorization(); - } -} diff --git a/src/Web.Api/Endpoints/MfaSettings/Get.cs b/src/Web.Api/Endpoints/MfaSettings/Get.cs deleted file mode 100644 index a961061..0000000 --- a/src/Web.Api/Endpoints/MfaSettings/Get.cs +++ /dev/null @@ -1,27 +0,0 @@ -using Application.Abstractions.Messaging; -using Application.MfaSettings.Get; -using SharedKernel; -using Web.Api.Extensions; -using Web.Api.Infrastructure; - -namespace Web.Api.Endpoints.MfaSettings; - -internal sealed class Get : IEndpoint -{ - public void MapEndpoint(IEndpointRouteBuilder app) - { - app.MapGet(ApiRoutes.GetAll(Base.MfaSettings), async ( - IQueryHandler> handler, - CancellationToken cancellationToken) => - { - var query = new GetMfaSettingQuery(); - - Result> result = - await handler.Handle(query, cancellationToken); - - return result.Match(Results.Ok, CustomResults.Problem); - }) - .WithTags(Tags.MfaSettings) - .RequireAuthorization(); - } -} diff --git a/src/Web.Api/Endpoints/MfaSettings/GetById.cs b/src/Web.Api/Endpoints/MfaSettings/GetById.cs deleted file mode 100644 index 9c23bd5..0000000 --- a/src/Web.Api/Endpoints/MfaSettings/GetById.cs +++ /dev/null @@ -1,28 +0,0 @@ -using Application.Abstractions.Messaging; -using Application.MfaSettings.GetById; -using SharedKernel; -using Web.Api.Extensions; -using Web.Api.Infrastructure; - -namespace Web.Api.Endpoints.MfaSettings; - -internal sealed class GetById : IEndpoint -{ - public void MapEndpoint(IEndpointRouteBuilder app) - { - app.MapGet(ApiRoutes.GetById(Base.MfaSettings), async ( - Guid id, - IQueryHandler handler, - CancellationToken cancellationToken) => - { - var query = new GetMfaSettingByIdQuery(id); - - Result result = - await handler.Handle(query, cancellationToken); - - return result.Match(Results.Ok, CustomResults.Problem); - }) - .WithTags(Tags.MfaSettings) - .RequireAuthorization(); - } -} diff --git a/src/Web.Api/Endpoints/MfaSettings/Update.cs b/src/Web.Api/Endpoints/MfaSettings/Update.cs deleted file mode 100644 index 6b92ee8..0000000 --- a/src/Web.Api/Endpoints/MfaSettings/Update.cs +++ /dev/null @@ -1,44 +0,0 @@ -using Application.Abstractions.Messaging; -using Application.MfaSettings.Update; -using SharedKernel; -using Web.Api.Extensions; -using Web.Api.Infrastructure; -using Domain.MfaSettings; - -namespace Web.Api.Endpoints.MfaSettings; - -internal sealed class Update : IEndpoint -{ - public void MapEndpoint(IEndpointRouteBuilder app) - { - app.MapPut(ApiRoutes.Update(Base.MfaSettings), async ( - Guid id, - UpdateMfaSettingRequest request, - ICommandHandler handler, - CancellationToken cancellationToken) => - { - var command = new UpdateMfaSettingCommand( - id, - request.UserId, - request.SecretKey, - request.BackupCodes, - (MfaMethod)request.Method, - request.Enabled - ); - - Result result = await handler.Handle(command, cancellationToken); - - return result.Match(Results.NoContent, CustomResults.Problem); - }) - .WithTags(Tags.MfaSettings) - .RequireAuthorization(); - } -} - -public sealed record UpdateMfaSettingRequest( - Guid UserId, - string? SecretKey, - string? BackupCodes, - int Method, - bool Enabled -); diff --git a/src/Web.Api/Endpoints/PasswordResets/Create.cs b/src/Web.Api/Endpoints/PasswordResets/Create.cs deleted file mode 100644 index c314b5d..0000000 --- a/src/Web.Api/Endpoints/PasswordResets/Create.cs +++ /dev/null @@ -1,41 +0,0 @@ -using Application.Abstractions.Messaging; -using Application.PasswordResets.Create; -using SharedKernel; -using Web.Api.Extensions; -using Web.Api.Infrastructure; - -namespace Web.Api.Endpoints.PasswordResets; - -public sealed class Create : IEndpoint -{ - public sealed class Request - { - public Guid UserId { get; set; } - public string Token { get; set; } - public DateTime ExpiresAt { get; set; } - public bool Used { get; set; } - } - - public void MapEndpoint(IEndpointRouteBuilder app) - { - app.MapPost(ApiRoutes.Create(Base.PasswordReset), async ( - Request request, - ICommandHandler handler, - CancellationToken cancellationToken) => - { - var command = new CreatePasswordResetCommand - { - ExpiresAt = request.ExpiresAt, - Token = request.Token, - Used = request.Used, - UserId = request.UserId - }; - - Result result = await handler.Handle(command, cancellationToken); - - return result.Match(Results.Ok, CustomResults.Problem); - }) - .WithTags(Tags.PasswordReset) - .RequireAuthorization(); - } -} diff --git a/src/Web.Api/Endpoints/PasswordResets/Delete.cs b/src/Web.Api/Endpoints/PasswordResets/Delete.cs deleted file mode 100644 index 7cae968..0000000 --- a/src/Web.Api/Endpoints/PasswordResets/Delete.cs +++ /dev/null @@ -1,27 +0,0 @@ -using Application.Abstractions.Messaging; -using Application.PasswordResets.Delete; -using SharedKernel; -using Web.Api.Extensions; -using Web.Api.Infrastructure; - -namespace Web.Api.Endpoints.PasswordResets; - -public sealed class Delete : IEndpoint -{ - public void MapEndpoint(IEndpointRouteBuilder app) - { - app.MapDelete(ApiRoutes.Delete(Base.PasswordReset), async ( - Guid id, - ICommandHandler handler, - CancellationToken cancellationToken) => - { - var command = new DeletePasswordResetCommand(id); - - Result result = await handler.Handle(command, cancellationToken); - - return result.Match(Results.NoContent, CustomResults.Problem); - }) - .WithTags(Tags.PasswordReset) - .RequireAuthorization(); - } -} diff --git a/src/Web.Api/Endpoints/PasswordResets/Get.cs b/src/Web.Api/Endpoints/PasswordResets/Get.cs deleted file mode 100644 index 519f0c1..0000000 --- a/src/Web.Api/Endpoints/PasswordResets/Get.cs +++ /dev/null @@ -1,27 +0,0 @@ -using Application.Abstractions.Messaging; -using Application.PasswordResets.Get; -using SharedKernel; -using Web.Api.Extensions; -using Web.Api.Infrastructure; - -namespace Web.Api.Endpoints.PasswordResets; - -public sealed class Get : IEndpoint -{ - public void MapEndpoint(IEndpointRouteBuilder app) - { - app.MapGet(ApiRoutes.GetAll(Base.PasswordReset), async ( - Guid userId, - IQueryHandler> handler, - CancellationToken cancellationToken) => - { - var query = new GetPasswordResetQuery(userId); - - Result> result = await handler.Handle(query, cancellationToken); - - return result.Match(Results.Ok, CustomResults.Problem); - }) - .WithTags(Tags.PasswordReset) - .RequireAuthorization(); - } -} diff --git a/src/Web.Api/Endpoints/PasswordResets/GetById.cs b/src/Web.Api/Endpoints/PasswordResets/GetById.cs deleted file mode 100644 index 8238be5..0000000 --- a/src/Web.Api/Endpoints/PasswordResets/GetById.cs +++ /dev/null @@ -1,27 +0,0 @@ -using Application.Abstractions.Messaging; -using Application.PasswordResets.GetById; -using SharedKernel; -using Web.Api.Extensions; -using Web.Api.Infrastructure; - -namespace Web.Api.Endpoints.PasswordResets; - -public sealed class GetById : IEndpoint -{ - public void MapEndpoint(IEndpointRouteBuilder app) - { - app.MapGet(ApiRoutes.GetById(Base.PasswordReset), async ( - Guid id, - IQueryHandler handler, - CancellationToken cancellationToken) => - { - var query = new GetPasswordResetByIdQuery(id); - - Result result = await handler.Handle(query, cancellationToken); - - return result.Match(Results.Ok, CustomResults.Problem); - }) - .WithTags(Tags.PasswordReset) - .RequireAuthorization(); - } -} diff --git a/src/Web.Api/Endpoints/PasswordResets/Update.cs b/src/Web.Api/Endpoints/PasswordResets/Update.cs deleted file mode 100644 index 6d65a0a..0000000 --- a/src/Web.Api/Endpoints/PasswordResets/Update.cs +++ /dev/null @@ -1,32 +0,0 @@ -using Application.Abstractions.Messaging; -using Application.PasswordResets.Update; -using SharedKernel; -using Web.Api.Extensions; -using Web.Api.Infrastructure; - -namespace Web.Api.Endpoints.PasswordResets; - -public sealed class Update : IEndpoint -{ - public sealed class Request - { - public string Token { get; set; } - } - public void MapEndpoint(IEndpointRouteBuilder app) - { - app.MapPut(ApiRoutes.Update(Base.PasswordReset), async ( - Guid id, - Request request, - ICommandHandler handler, - CancellationToken cancellationToken) => - { - var command = new UpdatePasswordResetCommand(id, request.Token); - - Result result = await handler.Handle(command, cancellationToken); - - return result.Match(Results.NoContent, CustomResults.Problem); - }) - .WithTags(Tags.PasswordReset) - .RequireAuthorization(); - } -} diff --git a/src/Web.Api/Endpoints/SmtpConfigs/Create.cs b/src/Web.Api/Endpoints/SmtpConfigs/Create.cs index cf78265..8dde5a4 100644 --- a/src/Web.Api/Endpoints/SmtpConfigs/Create.cs +++ b/src/Web.Api/Endpoints/SmtpConfigs/Create.cs @@ -19,7 +19,7 @@ public sealed class Request public void MapEndpoint(IEndpointRouteBuilder app) { - app.MapPost("SmtpConfig/Create", async ( + app.MapPost("api/smtp-config/Create", async ( Request request, ICommandHandler handler, CancellationToken cancellationToken) => diff --git a/src/Web.Api/Endpoints/SmtpConfigs/Delete.cs b/src/Web.Api/Endpoints/SmtpConfigs/Delete.cs index c0d47ac..eaded2f 100644 --- a/src/Web.Api/Endpoints/SmtpConfigs/Delete.cs +++ b/src/Web.Api/Endpoints/SmtpConfigs/Delete.cs @@ -10,7 +10,7 @@ public sealed class Delete : IEndpoint { public void MapEndpoint(IEndpointRouteBuilder app) { - app.MapDelete("SmtpConfig/Delete/{id:guid}", async ( + app.MapDelete("api/smtp-config/Delete/{id:guid}", async ( Guid id, ICommandHandler handler, CancellationToken cancellationToken) => diff --git a/src/Web.Api/Endpoints/SmtpConfigs/Get.cs b/src/Web.Api/Endpoints/SmtpConfigs/Get.cs index 599f432..75ecd14 100644 --- a/src/Web.Api/Endpoints/SmtpConfigs/Get.cs +++ b/src/Web.Api/Endpoints/SmtpConfigs/Get.cs @@ -10,7 +10,7 @@ internal sealed class Get : IEndpoint { public void MapEndpoint(IEndpointRouteBuilder app) { - app.MapGet("SmtpConfig", async ( + app.MapGet("api/smtp-config", async ( IQueryHandler> handler, CancellationToken cancellationToken) => { diff --git a/src/Web.Api/Endpoints/SmtpConfigs/GetById.cs b/src/Web.Api/Endpoints/SmtpConfigs/GetById.cs index 9ad3b85..a4a25f8 100644 --- a/src/Web.Api/Endpoints/SmtpConfigs/GetById.cs +++ b/src/Web.Api/Endpoints/SmtpConfigs/GetById.cs @@ -10,7 +10,7 @@ internal sealed class GetById : IEndpoint { public void MapEndpoint(IEndpointRouteBuilder app) { - app.MapGet("SmtpConfigs/{id:guid}", async ( + app.MapGet("api/smtp-config/{id:guid}", async ( Guid id, IQueryHandler handler, CancellationToken cancellationToken) => diff --git a/src/Web.Api/Endpoints/SmtpConfigs/OtpMail.cs b/src/Web.Api/Endpoints/SmtpConfigs/OtpMail.cs index 9b6f63b..bcccc21 100644 --- a/src/Web.Api/Endpoints/SmtpConfigs/OtpMail.cs +++ b/src/Web.Api/Endpoints/SmtpConfigs/OtpMail.cs @@ -15,7 +15,7 @@ public sealed class Request public void MapEndpoint(IEndpointRouteBuilder app) { - app.MapPost("SmtpConfig/SendMail", async ( + app.MapPost("api/smtp-config/SendMail", async ( Request request, ICommandHandler handler, CancellationToken cancellationToken) => diff --git a/src/Web.Api/Endpoints/SmtpConfigs/Update.cs b/src/Web.Api/Endpoints/SmtpConfigs/Update.cs index 648c45c..6823275 100644 --- a/src/Web.Api/Endpoints/SmtpConfigs/Update.cs +++ b/src/Web.Api/Endpoints/SmtpConfigs/Update.cs @@ -17,7 +17,7 @@ public sealed class Request public void MapEndpoint(IEndpointRouteBuilder app) { - app.MapPut("SmtpConfigs/Update/{Id:Guid}", async ( + app.MapPut("api/smtp-config/Update/{Id:Guid}", async ( Guid Id, Request request, ICommandHandler handler, diff --git a/src/Web.Api/Endpoints/Tokens/Delete.cs b/src/Web.Api/Endpoints/Tokens/Delete.cs deleted file mode 100644 index 7d4db79..0000000 --- a/src/Web.Api/Endpoints/Tokens/Delete.cs +++ /dev/null @@ -1,27 +0,0 @@ -using Application.Abstractions.Messaging; -using Application.Tokens.Delete; -using SharedKernel; -using Web.Api.Extensions; -using Web.Api.Infrastructure; - -namespace Web.Api.Endpoints.Tokens; - -public sealed class Delete : IEndpoint -{ - public void MapEndpoint(IEndpointRouteBuilder app) - { - app.MapDelete("api/tokens/{id}", async ( - string id, - ICommandHandler handler, - CancellationToken cancellationToken) => - { - var command = new DeleteTokenCommand(id); - - Result result = await handler.Handle(command, cancellationToken); - - return result.Match(Results.NoContent, CustomResults.Problem); - }) - .WithTags(Tags.Token) - .RequireAuthorization(); - } -} diff --git a/src/Web.Api/Endpoints/Tokens/Get.cs b/src/Web.Api/Endpoints/Tokens/Get.cs deleted file mode 100644 index c5c4f7f..0000000 --- a/src/Web.Api/Endpoints/Tokens/Get.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System.Collections.Generic; -using Application.Abstractions.Messaging; -using Application.Tokens.Get; -using SharedKernel; -using SharedKernel.Models; -using Web.Api.Extensions; -using Web.Api.Infrastructure; - -namespace Web.Api.Endpoints.Tokens; - -public sealed class Get : IEndpoint -{ - public void MapEndpoint(IEndpointRouteBuilder app) - { - app.MapGet("api/tokens", async ( - IQueryHandler> handler, - CancellationToken cancellationToken) => - { - var query = new GetTokensQuery(); - - Result> result = await handler.Handle(query, cancellationToken); - - return result.Match(Results.Ok, CustomResults.Problem); - }) - .WithTags(Tags.Token) - .RequireAuthorization(); - } -} diff --git a/src/Web.Api/Endpoints/UserLoginHistory/Create.cs b/src/Web.Api/Endpoints/UserLoginHistory/Create.cs deleted file mode 100644 index 55a15f1..0000000 --- a/src/Web.Api/Endpoints/UserLoginHistory/Create.cs +++ /dev/null @@ -1,46 +0,0 @@ -using Application.Abstractions.Messaging; -using Application.UserLoginHistories.Create; -using SharedKernel; -using Web.Api.Extensions; -using Web.Api.Infrastructure; - -namespace Web.Api.Endpoints.UserLoginHistory; - -internal sealed class Create : IEndpoint -{ - public sealed class Request - { - public Guid UserId { get; set; } - public string IpAddress { get; set; } - public string Country { get; set; } - public string City { get; set; } - public string Browser { get; set; } - public string OS { get; set; } - public string Device { get; set; } - } - - public void MapEndpoint(IEndpointRouteBuilder app) - { - app.MapPost(ApiRoutes.Create(Base.UserLoginHistory), async ( - Request request, - ICommandHandler handler, - CancellationToken cancellationToken) => - { - var command = new CreateUserLoginHistoryCommand - { - UserId = request.UserId, - IpAddress = request.IpAddress, - Country = request.Country, - City = request.City, - Browser = request.Browser, - OS = request.OS, - Device = request.Device, - }; - - Result result = await handler.Handle(command, cancellationToken); - return result.Match(Results.Ok, CustomResults.Problem); - }) - .WithTags(Tags.UserLoginHistory) - .RequireAuthorization(); - } -} diff --git a/src/Web.Api/Endpoints/UserLoginHistory/Delete.cs b/src/Web.Api/Endpoints/UserLoginHistory/Delete.cs deleted file mode 100644 index 6eba0e9..0000000 --- a/src/Web.Api/Endpoints/UserLoginHistory/Delete.cs +++ /dev/null @@ -1,26 +0,0 @@ -using Application.Abstractions.Messaging; -using Application.UserLoginHistories.Delete; -using SharedKernel; -using Web.Api.Extensions; -using Web.Api.Infrastructure; - -namespace Web.Api.Endpoints.UserLoginHistory; - -internal sealed class Delete : IEndpoint -{ - public void MapEndpoint(IEndpointRouteBuilder app) - { - app.MapDelete(ApiRoutes.Create(Base.UserLoginHistory), async ( - Guid id, - ICommandHandler handler, - CancellationToken cancellationToken) => - { - var command = new DeleteUserloginHistoryCommand(id); - - Result result = await handler.Handle(command, cancellationToken); - return result.Match(Results.NoContent, CustomResults.Problem); - }) - .WithTags(Tags.UserLoginHistory) - .RequireAuthorization(); - } -} diff --git a/src/Web.Api/Endpoints/UserLoginHistory/GetByUserId.cs b/src/Web.Api/Endpoints/UserLoginHistory/GetByUserId.cs deleted file mode 100644 index 8ae40d1..0000000 --- a/src/Web.Api/Endpoints/UserLoginHistory/GetByUserId.cs +++ /dev/null @@ -1,26 +0,0 @@ -using Application.Abstractions.Messaging; -using Application.UserLoginHistories.GetByUserId; -using SharedKernel; -using Web.Api.Extensions; -using Web.Api.Infrastructure; - -namespace Web.Api.Endpoints.UserLoginHistory; - -internal sealed class GetByUserId : IEndpoint -{ - public void MapEndpoint(IEndpointRouteBuilder app) - { - app.MapGet(ApiRoutes.GetById(Base.UserLoginHistory), async ( - Guid id, - IQueryHandler> handler, - CancellationToken cancellationToken) => - { - var query = new GetUserLoginHistoryByUserIdQuery(id); - - Result> result = await handler.Handle(query, cancellationToken); - return result.Match(Results.Ok, CustomResults.Problem); - }) - .WithTags(Tags.UserLoginHistory) - .RequireAuthorization(); - } -} diff --git a/src/Web.Api/Endpoints/UserProfiles/Create.cs b/src/Web.Api/Endpoints/UserProfiles/Create.cs deleted file mode 100644 index cbc5e38..0000000 --- a/src/Web.Api/Endpoints/UserProfiles/Create.cs +++ /dev/null @@ -1,49 +0,0 @@ - -using Application.Abstractions.Messaging; -using Application.UserProfiles.Create; -using SharedKernel; -using Web.Api.Extensions; -using Web.Api.Infrastructure; - -namespace Web.Api.Endpoints.UserProfiles; - -// both create and update used -internal sealed class Create : IEndpoint -{ - public sealed record Request( // req body - string Address, - string City, - string Country, - string PostalCode, - string ProfileImageUrl, - DateOnly DateOfBirth); - - public void MapEndpoint(IEndpointRouteBuilder app) - { - app.MapPost(ApiRoutes.Create(Base.UserProfile), async ( - Guid id, // from route parameter - Request request, - ICommandHandler handler, - CancellationToken cancellationToken - - ) => - { - var command = new CreateUserProfileCommand - { - UserId = id, - Address = request.Address, - City = request.City, - Country = request.Country, - PostalCode = request.PostalCode, - ProfileImageUrl = request.ProfileImageUrl, - DateOfBirth = request.DateOfBirth - }; - - Result result = await handler.Handle(command, cancellationToken); - - return result.Match(Results.Ok, CustomResults.Problem); - }) - .WithTags(Tags.UserProfile) - .RequireAuthorization(); - } -} diff --git a/src/Web.Api/Endpoints/UserProfiles/Get.cs b/src/Web.Api/Endpoints/UserProfiles/Get.cs deleted file mode 100644 index f023d46..0000000 --- a/src/Web.Api/Endpoints/UserProfiles/Get.cs +++ /dev/null @@ -1,30 +0,0 @@ -using Application.Abstractions.Messaging; -using Application.UserProfiles.Create; -using Application.UserProfiles.Get; -using SharedKernel; -using Web.Api.Endpoints.Users; -using Web.Api.Extensions; -using Web.Api.Infrastructure; - -namespace Web.Api.Endpoints.UserProfiles; - -internal sealed class Get : IEndpoint -{ - public void MapEndpoint(IEndpointRouteBuilder app) - { - app.MapGet(ApiRoutes.GetById(Base.UserProfile), async ( - Guid id, - IQueryHandler handler, - CancellationToken cancellationToken) => - { - var query = new GetUserProfileQuery(id); - - Result result = await handler.Handle(query, cancellationToken); - - return result.Match(Results.Ok, CustomResults.Problem); - }) - .HasPermission(UserProfilePermissions.UsersAccess) - .WithTags(Tags.UserProfile) - .RequireAuthorization(); - } -} diff --git a/src/Web.Api/Endpoints/UserProfiles/UserProfilePermissions.cs b/src/Web.Api/Endpoints/UserProfiles/UserProfilePermissions.cs deleted file mode 100644 index cd25e68..0000000 --- a/src/Web.Api/Endpoints/UserProfiles/UserProfilePermissions.cs +++ /dev/null @@ -1,7 +0,0 @@ - -namespace Web.Api.Endpoints.UserProfiles; - -internal static class UserProfilePermissions -{ - internal const string UsersAccess = "users:access"; -} diff --git a/src/Web.Api/Program.cs b/src/Web.Api/Program.cs index 86a3ab6..c627f55 100644 --- a/src/Web.Api/Program.cs +++ b/src/Web.Api/Program.cs @@ -1,19 +1,18 @@ +using System.Net; using System.Reflection; using Application; using HealthChecks.UI.Client; using Infrastructure; using Infrastructure.Database; using Microsoft.AspNetCore.Diagnostics.HealthChecks; -using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.Configuration; +using Microsoft.AspNetCore.HttpOverrides; using OpenIddict.Abstractions; -using OpenIddict.Server.AspNetCore; -using Org.BouncyCastle.Ocsp; using Serilog; using Web.Api; using Web.Api.Extensions; WebApplicationBuilder builder = WebApplication.CreateBuilder(args); + string[] allowedOrigins = builder.Configuration .GetSection("Cors:AllowedOrigins") .Get() ?? []; @@ -22,6 +21,8 @@ builder.Services.AddSwaggerGenWithAuth(); +builder.Services.AddCertificateForwarding(options => options.CertificateHeader = "X-SSL-CERT"); + builder.Services .AddApplication() .AddPresentation() @@ -33,23 +34,6 @@ .WithHeaders("Content-Type", "Authorization") .AllowCredentials())); -builder.Services.AddCors(options => options.AddPolicy("LocalhostPolicy", policy => policy - .SetIsOriginAllowed(origin => - { - if (string.IsNullOrWhiteSpace(origin)) - { - return false; - } - - var uri = new Uri(origin); - - return uri.Host == "localhost" - || uri.Host == "127.0.0.1"; - }) - .AllowAnyMethod() - .AllowAnyHeader() - .AllowCredentials())); - builder.Services.AddEndpoints(Assembly.GetExecutingAssembly()); builder.Services.AddOpenIddict() @@ -64,7 +48,7 @@ options.SetAuthorizationEndpointUris("/connect/authorize"); options.SetTokenEndpointUris("/connect/token"); options.SetUserInfoEndpointUris("/connect/userinfo"); - options.SetIssuer(builder.Configuration["IssuerUrl"] ?? "https://"+"localhost:5001"); // Issuer URL (authapi) + options.SetIssuer(builder.Configuration["IssuerUrl"] ?? "https://" + "localhost:5001"); // Issuer URL (authapi) options.AllowAuthorizationCodeFlow() .RequireProofKeyForCodeExchange(); @@ -82,7 +66,7 @@ .EnableUserInfoEndpointPassthrough(); }); -builder.Services.AddAuthentication( options => +builder.Services.AddAuthentication(options => { options.DefaultAuthenticateScheme = "AuthCookie"; options.DefaultSignInScheme = "AuthCookie"; @@ -92,10 +76,12 @@ { options.Cookie.Name = "auth_server_session"; options.Cookie.HttpOnly = true; - options.Cookie.SecurePolicy = CookieSecurePolicy.Always; //options.Cookie.SameSite = SameSiteMode.Lax; options.Cookie.SameSite = SameSiteMode.None; - options.Cookie.SecurePolicy = CookieSecurePolicy.Always; + + options.Cookie.SecurePolicy = builder.Configuration.GetValue("AuthServer:AlwaysHTTPS") + ? CookieSecurePolicy.Always + : CookieSecurePolicy.SameAsRequest; options.LoginPath = "/login"; // do NOT redirect for API calls options.Events.OnRedirectToLogin = context => @@ -120,15 +106,7 @@ if (app.Environment.IsDevelopment()) { app.UseSwagger(); - app.UseSwaggerUI(options => - { - options.SwaggerEndpoint("/swagger/v1/swagger.json", "API v1"); - options.OAuthClientId("swagger"); - //options.OAuthUsePkce(); - options.OAuthScopes("openid", "profile", "email", "api"); - options.OAuthAppName("Swagger UI"); - }); - + app.UseSwaggerUI(); app.ApplyMigrations(); } @@ -137,24 +115,42 @@ ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse }); -app.UseHttpsRedirection(); +// ------------------ proxy (need for SSL)---------------------- +string[]? knownProxies = builder.Configuration.GetSection("KnownProxies").Get(); -app.UseRequestContextLogging(); +var forwardedHeadersOptions = new ForwardedHeadersOptions +{ + ForwardedHeaders = ForwardedHeaders.XForwardedProto +}; -app.UseSerilogRequestLogging(); +if (knownProxies != null) +{ + foreach (string proxy in knownProxies) + { + if (System.Net.IPAddress.TryParse(proxy, out IPAddress? ip)) + { + forwardedHeadersOptions.KnownProxies.Add(ip); + } + } +} +else +{ + forwardedHeadersOptions.KnownProxies.Add(IPAddress.Parse("172.18.240.206")); +} +app.UseForwardedHeaders(forwardedHeadersOptions); +// ------------------------------------------------------------ + +app.UseCertificateForwarding(); + +app.MapGet("/remote-ip", (HttpContext ctx) => ctx.Connection.RemoteIpAddress?.ToString()); + +app.UseRequestContextLogging(); app.UseExceptionHandler(); -app.UseRouting(); +app.UseSerilogRequestLogging(); -//if (app.Environment.IsDevelopment()) -//{ -// app.UseCors("LocalhostPolicy"); -//} -//else -//{ -// app.UseCors("Allowed_Origins"); -//} +app.UseRouting(); app.UseCors("Allowed_Origins"); @@ -164,9 +160,6 @@ app.MapEndpoints(); -// REMARK: If you want to use Controllers, you'll need this. -app.MapControllers(); - await app.RunAsync(); // REMARK: Required for functional and integration tests to work. diff --git a/src/Web.Api/Properties/launchSettings.json b/src/Web.Api/Properties/launchSettings.json index e1fe618..837eb8a 100644 --- a/src/Web.Api/Properties/launchSettings.json +++ b/src/Web.Api/Properties/launchSettings.json @@ -2,10 +2,11 @@ "profiles": { "http": { "commandName": "Project", - "launchBrowser": true, "launchUrl": "swagger", + "launchBrowser": true, "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" + "ASPNETCORE_ENVIRONMENT": "Development", + "ASPNETCORE_HTTP_PORT": "5000" }, "dotnetRunMessages": true, "applicationUrl": "http://localhost:5000" @@ -15,7 +16,8 @@ "launchBrowser": true, "launchUrl": "swagger", "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" + "ASPNETCORE_ENVIRONMENT": "Development", + "ASPNETCORE_HTTPS_PORT": "5001" }, "dotnetRunMessages": true, "applicationUrl": "https://localhost:5001;http://localhost:5000" diff --git a/src/Web.Api/appsettings.json b/src/Web.Api/appsettings.json index a5fd774..9405d9d 100644 --- a/src/Web.Api/appsettings.json +++ b/src/Web.Api/appsettings.json @@ -1,15 +1,12 @@ { "AllowedHosts": "*", "ConnectionStrings": { - "Database": "Host=localhost;Port=5432;Database=clean-architecture;Username=postgres;Password=12345;Include Error Detail=true;Pooling=true;Timeout=30;" + "Database": "Host=localhost;Port=5432;Database=clean-architecture;Username=postgres;Password=22345;Include Error Detail=true;Pooling=true;Timeout=30;" }, "FrontendLoginUrl": "https://localhost:4200/login", "IssuerUrl": "https://localhost:5001", - "Jwt": { - "Secret": "super-duper-secret-value-that-should-be-in-user-secrets", - "Issuer": "clean-architecture", - "Audience": "developers", - "ExpirationInMinutes": 60 + "AuthServer": { + "AlwaysHTTPS": true }, "Cors": { "AllowedOrigins": [ @@ -23,6 +20,9 @@ "http://localhost:53882" ] }, + "KnownProxies": [ + "172.18.240.206" + ], "EmailSettings": { "SmtpServer": "smtp.gmail.com", "SmtpPort": 587,