diff --git a/.gitea/workflows/cms-stage.yml b/.gitea/workflows/cms-stage.yml new file mode 100644 index 0000000..856768b --- /dev/null +++ b/.gitea/workflows/cms-stage.yml @@ -0,0 +1,47 @@ + +name: Push nuget and docker image Actions Workflow + +on: + push: + branches: + - stage +jobs: + Deploy: + runs-on: windows + steps: + - name: Checkout + uses: https://git.afrino.co/actions/checkout@v3 + - name: Setup dotnet + uses: https://git.afrino.co/actions/setup-dotnet@v3 + with: + dotnet-version: 7.0.x + + - name: Remove Package Source + run: dotnet nuget remove source MegaBizdEx + continue-on-error: true + - name: Add Package Source + run: dotnet nuget add source --name MegaBizdEx --username systemuser --password BHMkDaU3uXP6euR http://88.198.47.16:7000/api/packages/MegaBizdEx/nuget/index.json --store-password-in-clear-text + - name: Install dependencies + run: dotnet restore ".\src\CMSMicroservice.Protobuf\CMSMicroservice.Protobuf.csproj" + - name: Build + run: dotnet build ".\src\CMSMicroservice.Protobuf\CMSMicroservice.Protobuf.csproj" --configuration Release --no-restore + - name: Test + run: dotnet test ".\src\CMSMicroservice.Protobuf\CMSMicroservice.Protobuf.csproj" --no-restore --verbosity normal + - name: Pack + run: dotnet pack ".\src\CMSMicroservice.Protobuf\CMSMicroservice.Protobuf.csproj" --no-build --configuration Release + - name: Push To Gitea Packages + run: dotnet nuget push **/*.nupkg --source http://88.198.47.16:7000/api/packages/megabizdex/nuget/index.json --api-key 49c6424b31442f3aaad8d5ce73401143264f8471 --skip-duplicate + + - name: Build Docker Image + run: docker build ./src -t cmsapi:latest -f src/CMSMicroservice.WebApi/Dockerfile + - name: Log Out From Registry + run: docker logout git.afrino.co + - name: Log In To Registry + run: docker login git.afrino.co -u systemuser -p sZSA7PTiv3pUSQZ + - name: Tag Docker Image + run: docker image tag cmsapi:latest git.afrino.co/megabizdex/cmsapi:latest + - name: Push Docker Image + run: docker image push git.afrino.co/megabizdex/cmsapi:latest + + - name: Deploy (Up) Services + run: docker-compose up -d diff --git a/src/.dockerignore b/src/.dockerignore new file mode 100644 index 0000000..25f68c7 --- /dev/null +++ b/src/.dockerignore @@ -0,0 +1,26 @@ + +**/.classpath +**/.dockerignore +**/.env +**/.git +**/.gitignore +**/.project +**/.settings +**/.toolstarget +**/.vs +**/.vscode +**/*.*proj.user +**/*.dbmdl +**/*.jfm +**/azds.yaml +**/bin +**/charts +**/docker-compose* +**/Dockerfile* +**/node_modules +**/npm-debug.log +**/obj +**/secrets.dev.yaml +**/values.dev.yaml +LICENSE +README.md diff --git a/src/CMS.sln b/src/CMS.sln new file mode 100644 index 0000000..0b74488 --- /dev/null +++ b/src/CMS.sln @@ -0,0 +1,45 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.31903.59 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{43A1942F-306D-4937-8907-B9888A5449CF}") = "CMSMicroservice.Domain", "CMSMicroservice.Domain\CMSMicroservice.Domain.csproj", "{426E097F-8C77-44B2-BF9D-4280B295B366}" +EndProject +Project("{43A1942F-306D-4937-8907-B9888A5449CF}") = "CMSMicroservice.Application", "CMSMicroservice.Application\CMSMicroservice.Application.csproj", "{5A05B9B0-D6BB-46EB-BE8C-EEAB6F0EAC55}" +EndProject +Project("{43A1942F-306D-4937-8907-B9888A5449CF}") = "CMSMicroservice.Infrastructure", "CMSMicroservice.Infrastructure\CMSMicroservice.Infrastructure.csproj", "{A583B3B2-EAFB-45B7-BAA3-C17662714713}" +EndProject +Project("{43A1942F-306D-4937-8907-B9888A5449CF}") = "CMSMicroservice.WebApi", "CMSMicroservice.WebApi\CMSMicroservice.WebApi.csproj", "{0A56701B-A4EA-441F-A5A6-7EDD89572F9D}" +EndProject +Project("{43A1942F-306D-4937-8907-B9888A5449CF}") = "CMSMicroservice.Protobuf", "CMSMicroservice.Protobuf\CMSMicroservice.Protobuf.csproj", "{AC4961A7-941F-4E42-9208-B48CB352361C}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {426E097F-8C77-44B2-BF9D-4280B295B366}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {426E097F-8C77-44B2-BF9D-4280B295B366}.Debug|Any CPU.Build.0 = Debug|Any CPU + {426E097F-8C77-44B2-BF9D-4280B295B366}.Release|Any CPU.ActiveCfg = Release|Any CPU + {426E097F-8C77-44B2-BF9D-4280B295B366}.Release|Any CPU.Build.0 = Release|Any CPU + {5A05B9B0-D6BB-46EB-BE8C-EEAB6F0EAC55}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5A05B9B0-D6BB-46EB-BE8C-EEAB6F0EAC55}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5A05B9B0-D6BB-46EB-BE8C-EEAB6F0EAC55}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5A05B9B0-D6BB-46EB-BE8C-EEAB6F0EAC55}.Release|Any CPU.Build.0 = Release|Any CPU + {A583B3B2-EAFB-45B7-BAA3-C17662714713}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A583B3B2-EAFB-45B7-BAA3-C17662714713}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A583B3B2-EAFB-45B7-BAA3-C17662714713}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A583B3B2-EAFB-45B7-BAA3-C17662714713}.Release|Any CPU.Build.0 = Release|Any CPU + {0A56701B-A4EA-441F-A5A6-7EDD89572F9D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0A56701B-A4EA-441F-A5A6-7EDD89572F9D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0A56701B-A4EA-441F-A5A6-7EDD89572F9D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0A56701B-A4EA-441F-A5A6-7EDD89572F9D}.Release|Any CPU.Build.0 = Release|Any CPU + {AC4961A7-941F-4E42-9208-B48CB352361C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AC4961A7-941F-4E42-9208-B48CB352361C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AC4961A7-941F-4E42-9208-B48CB352361C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AC4961A7-941F-4E42-9208-B48CB352361C}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/src/CMSMicroservice.Application/CMSMicroservice.Application.csproj b/src/CMSMicroservice.Application/CMSMicroservice.Application.csproj new file mode 100644 index 0000000..f292b0e --- /dev/null +++ b/src/CMSMicroservice.Application/CMSMicroservice.Application.csproj @@ -0,0 +1,19 @@ + + + + net7.0 + enable + + + + + + + + + + + + + + diff --git a/src/CMSMicroservice.Application/Common/Behaviours/LoggingBehaviour.cs b/src/CMSMicroservice.Application/Common/Behaviours/LoggingBehaviour.cs new file mode 100644 index 0000000..951bc51 --- /dev/null +++ b/src/CMSMicroservice.Application/Common/Behaviours/LoggingBehaviour.cs @@ -0,0 +1,24 @@ +using MediatR.Pipeline; +using Microsoft.Extensions.Logging; + +namespace CMSMicroservice.Application.Common.Behaviours; + +public class LoggingBehaviour : IRequestPreProcessor where TRequest : notnull +{ + private readonly ILogger _logger; + private readonly ICurrentUserService _currentUserService; + + public LoggingBehaviour(ILogger logger, ICurrentUserService currentUserService) + { + _logger = logger; + _currentUserService = currentUserService; + } + + public async Task Process(TRequest request, CancellationToken cancellationToken) + { + var requestName = typeof(TRequest).Name; + var userId = _currentUserService.UserId ?? string.Empty; + _logger.LogInformation("Request: {Name} {@UserId} {@Request}", + requestName, userId, request); + } +} diff --git a/src/CMSMicroservice.Application/Common/Behaviours/PerformanceBehaviour.cs b/src/CMSMicroservice.Application/Common/Behaviours/PerformanceBehaviour.cs new file mode 100644 index 0000000..45cd4e9 --- /dev/null +++ b/src/CMSMicroservice.Application/Common/Behaviours/PerformanceBehaviour.cs @@ -0,0 +1,43 @@ +using System.Diagnostics; +using MediatR; +using Microsoft.Extensions.Logging; + +namespace CMSMicroservice.Application.Common.Behaviours; + +public class PerformanceBehaviour : IPipelineBehavior + where TRequest : IRequest +{ + private readonly Stopwatch _timer; + private readonly ILogger _logger; + private readonly ICurrentUserService _currentUserService; + + public PerformanceBehaviour(ILogger logger, ICurrentUserService currentUserService) + { + _timer = new Stopwatch(); + _logger = logger; + _currentUserService = currentUserService; + } + + public async Task Handle(TRequest request, RequestHandlerDelegate next, + CancellationToken cancellationToken) + { + _timer.Start(); + + var response = await next(); + + _timer.Stop(); + + var elapsedMilliseconds = _timer.ElapsedMilliseconds; + + if (elapsedMilliseconds > 500) + { + var requestName = typeof(TRequest).Name; + var userId = _currentUserService.UserId ?? string.Empty; + + _logger.LogWarning("Long Running Request: {Name} ({ElapsedMilliseconds} milliseconds) {@UserId} {@Request}", + requestName, elapsedMilliseconds, userId, request); + } + + return response; + } +} diff --git a/src/CMSMicroservice.Application/Common/Behaviours/UnhandledExceptionBehaviour.cs b/src/CMSMicroservice.Application/Common/Behaviours/UnhandledExceptionBehaviour.cs new file mode 100644 index 0000000..12648ad --- /dev/null +++ b/src/CMSMicroservice.Application/Common/Behaviours/UnhandledExceptionBehaviour.cs @@ -0,0 +1,31 @@ +using Microsoft.Extensions.Logging; + +namespace CMSMicroservice.Application.Common.Behaviours; + +public class UnhandledExceptionBehaviour : IPipelineBehavior + where TRequest : IRequest +{ + private readonly ILogger _logger; + + public UnhandledExceptionBehaviour(ILogger logger) + { + _logger = logger; + } + + public async Task Handle(TRequest request, RequestHandlerDelegate next, + CancellationToken cancellationToken) + { + try + { + return await next(); + } + catch (Exception ex) + { + var requestName = typeof(TRequest).Name; + + _logger.LogError(ex, "Request: Unhandled Exception for Request {Name} {@Request}", requestName, request); + + throw; + } + } +} diff --git a/src/CMSMicroservice.Application/Common/Behaviours/ValidationBehaviour.cs b/src/CMSMicroservice.Application/Common/Behaviours/ValidationBehaviour.cs new file mode 100644 index 0000000..a13c783 --- /dev/null +++ b/src/CMSMicroservice.Application/Common/Behaviours/ValidationBehaviour.cs @@ -0,0 +1,37 @@ +using ValidationException = CMSMicroservice.Application.Common.Exceptions.ValidationException; + +namespace CMSMicroservice.Application.Common.Behaviours; + +public class ValidationBehaviour : IPipelineBehavior + where TRequest : IRequest +{ + private readonly IEnumerable> _validators; + + public ValidationBehaviour(IEnumerable> validators) + { + _validators = validators; + } + + public async Task Handle(TRequest request, RequestHandlerDelegate next, + CancellationToken cancellationToken) + { + if (_validators.Any()) + { + var context = new ValidationContext(request); + + var validationResults = await Task.WhenAll( + _validators.Select(v => + v.ValidateAsync(context, cancellationToken))); + + var failures = validationResults + .Where(r => r.Errors.Any()) + .SelectMany(r => r.Errors) + .ToList(); + + if (failures.Any()) + throw new ValidationException(failures); + } + + return await next(); + } +} diff --git a/src/CMSMicroservice.Application/Common/Exceptions/DuplicateException.cs b/src/CMSMicroservice.Application/Common/Exceptions/DuplicateException.cs new file mode 100644 index 0000000..5ccf2a1 --- /dev/null +++ b/src/CMSMicroservice.Application/Common/Exceptions/DuplicateException.cs @@ -0,0 +1,29 @@ +namespace CMSMicroservice.Application.Common.Exceptions; + +public class DuplicateException : Exception +{ + public DuplicateException() + : base() + { + } + + public DuplicateException(string message) + : base(message) + { + } + + public DuplicateException(string message, Exception innerException) + : base(message, innerException) + { + } + + public DuplicateException(string name, object key) + : base($"Entity \"{name}\" ({key}) already exists.") + { + } + + public DuplicateException(string name, string field, object? key) + : base($"Entity \"{name}\" field \"{field}\" ({key}) already exists.") + { + } +} diff --git a/src/CMSMicroservice.Application/Common/Exceptions/ForbiddenAccessException.cs b/src/CMSMicroservice.Application/Common/Exceptions/ForbiddenAccessException.cs new file mode 100644 index 0000000..5809be8 --- /dev/null +++ b/src/CMSMicroservice.Application/Common/Exceptions/ForbiddenAccessException.cs @@ -0,0 +1,8 @@ +namespace CMSMicroservice.Application.Common.Exceptions; + +public class ForbiddenAccessException : Exception +{ + public ForbiddenAccessException() : base() + { + } +} diff --git a/src/CMSMicroservice.Application/Common/Exceptions/NotFoundException.cs b/src/CMSMicroservice.Application/Common/Exceptions/NotFoundException.cs new file mode 100644 index 0000000..a92a29f --- /dev/null +++ b/src/CMSMicroservice.Application/Common/Exceptions/NotFoundException.cs @@ -0,0 +1,24 @@ +namespace CMSMicroservice.Application.Common.Exceptions; + +public class NotFoundException : Exception +{ + public NotFoundException() + : base() + { + } + + public NotFoundException(string message) + : base(message) + { + } + + public NotFoundException(string message, Exception innerException) + : base(message, innerException) + { + } + + public NotFoundException(string name, object key) + : base($"Entity \"{name}\" ({key}) was not found.") + { + } +} diff --git a/src/CMSMicroservice.Application/Common/Exceptions/ValidationException.cs b/src/CMSMicroservice.Application/Common/Exceptions/ValidationException.cs new file mode 100644 index 0000000..77d2d7d --- /dev/null +++ b/src/CMSMicroservice.Application/Common/Exceptions/ValidationException.cs @@ -0,0 +1,22 @@ +using FluentValidation.Results; + +namespace CMSMicroservice.Application.Common.Exceptions; + +public class ValidationException : Exception +{ + public ValidationException() + : base("One or more validation failures have occurred.") + { + Errors = new Dictionary(); + } + + public ValidationException(IEnumerable failures) + : this() + { + Errors = failures + .GroupBy(e => e.PropertyName, e => e.ErrorMessage) + .ToDictionary(failureGroup => failureGroup.Key, failureGroup => failureGroup.ToArray()); + } + + public IDictionary Errors { get; } +} diff --git a/src/CMSMicroservice.Application/Common/Extensions/MetaDataExtensions.cs b/src/CMSMicroservice.Application/Common/Extensions/MetaDataExtensions.cs new file mode 100644 index 0000000..3c8ce88 --- /dev/null +++ b/src/CMSMicroservice.Application/Common/Extensions/MetaDataExtensions.cs @@ -0,0 +1,30 @@ +namespace CMSMicroservice.Application.Common.Extensions; + +public static class MetaDataExtensions +{ + public static async Task GetMetaData(this IQueryable source, PaginationState? paginationState, + CancellationToken cancellationToken) + { + if (paginationState is null) + return new MetaData + { + TotalCount = await source.CountAsync(cancellationToken) + }; + + var pageSize = paginationState.PageSize > 0 ? paginationState.PageSize : PaginationDefaults.PageSize; + var pageNumber = paginationState.PageNumber > 0 ? paginationState.PageNumber : PaginationDefaults.PageNumber; + var totalCount = await source.CountAsync(cancellationToken); + var totalPageCount = (int)Math.Ceiling(totalCount / (double)pageSize); + + var metaData = new MetaData + { + CurrentPage = pageNumber, + HasNext = pageNumber < totalPageCount, + HasPrevious = pageNumber > 1, + PageSize = pageSize, + TotalCount = totalCount, + TotalPage = totalPageCount + }; + return metaData; + } +} diff --git a/src/CMSMicroservice.Application/Common/Extensions/PaginationStateExtensions.cs b/src/CMSMicroservice.Application/Common/Extensions/PaginationStateExtensions.cs new file mode 100644 index 0000000..794a3d0 --- /dev/null +++ b/src/CMSMicroservice.Application/Common/Extensions/PaginationStateExtensions.cs @@ -0,0 +1,25 @@ +namespace CMSMicroservice.Application.Common.Extensions; + +public static class PaginationStateExtensions +{ + public static IQueryable PaginatedListAsync(this IQueryable source, + PaginationState? paginationState) + { + if (paginationState is null) + return source; + + var pageSize = paginationState.PageSize > 0 ? paginationState.PageSize : PaginationDefaults.PageSize; + var pageNumber = paginationState.PageNumber > 0 ? paginationState.PageNumber : PaginationDefaults.PageNumber; + var paginationSkip = pageSize * (pageNumber - 1); + + return source.Skip(paginationSkip).Take(pageSize); + } +} + +public static class PaginationDefaults +{ + public const int PageSize = 10; + public const int PageNumber = 1; + public const int Skip = 0; + public const int Take = PageSize; +} diff --git a/src/CMSMicroservice.Application/Common/Extensions/SortByExtensions.cs b/src/CMSMicroservice.Application/Common/Extensions/SortByExtensions.cs new file mode 100644 index 0000000..3f0d9c8 --- /dev/null +++ b/src/CMSMicroservice.Application/Common/Extensions/SortByExtensions.cs @@ -0,0 +1,23 @@ +using System.Linq.Dynamic.Core; +using CMSMicroservice.Domain.Common; + +namespace CMSMicroservice.Application.Common.Extensions; + +public static class SortByExtensions +{ + public static IQueryable ApplyOrder(this IQueryable source, + string? sortBy) where TSource : BaseAuditableEntity + { + // default sort approach + if (sortBy is null or "") + { + source = source.OrderByDescending(p => p.Created); + return source; + } + + // sort using dynamic linq + source = source.OrderBy(sortBy); + + return source; + } +} diff --git a/src/CMSMicroservice.Application/Common/Interfaces/IApplicationDbContext.cs b/src/CMSMicroservice.Application/Common/Interfaces/IApplicationDbContext.cs new file mode 100644 index 0000000..3d0f94a --- /dev/null +++ b/src/CMSMicroservice.Application/Common/Interfaces/IApplicationDbContext.cs @@ -0,0 +1,12 @@ +namespace CMSMicroservice.Application.Common.Interfaces; + +public interface IApplicationDbContext +{ + DbSet Users { get; } + DbSet UserAddresss { get; } + DbSet Packages { get; } + DbSet UserOrders { get; } + DbSet Roles { get; } + DbSet UserRoles { get; } + Task SaveChangesAsync(CancellationToken cancellationToken = default); +} \ No newline at end of file diff --git a/src/CMSMicroservice.Application/Common/Interfaces/ICurrentUserService.cs b/src/CMSMicroservice.Application/Common/Interfaces/ICurrentUserService.cs new file mode 100644 index 0000000..c8f2752 --- /dev/null +++ b/src/CMSMicroservice.Application/Common/Interfaces/ICurrentUserService.cs @@ -0,0 +1,6 @@ +namespace CMSMicroservice.Application.Common.Interfaces; + +public interface ICurrentUserService +{ + string? UserId { get; } +} diff --git a/src/CMSMicroservice.Application/Common/Mappings/PackageProfile.cs b/src/CMSMicroservice.Application/Common/Mappings/PackageProfile.cs new file mode 100644 index 0000000..0f077cb --- /dev/null +++ b/src/CMSMicroservice.Application/Common/Mappings/PackageProfile.cs @@ -0,0 +1,10 @@ +namespace CMSMicroservice.Application.Common.Mappings; + +public class PackageProfile : IRegister +{ + void IRegister.Register(TypeAdapterConfig config) + { + //config.NewConfig() + // .Map(dest => dest.FullName, src => $"{src.Firstname} {src.Lastname}"); + } +} diff --git a/src/CMSMicroservice.Application/Common/Mappings/RoleProfile.cs b/src/CMSMicroservice.Application/Common/Mappings/RoleProfile.cs new file mode 100644 index 0000000..a061f62 --- /dev/null +++ b/src/CMSMicroservice.Application/Common/Mappings/RoleProfile.cs @@ -0,0 +1,10 @@ +namespace CMSMicroservice.Application.Common.Mappings; + +public class RoleProfile : IRegister +{ + void IRegister.Register(TypeAdapterConfig config) + { + //config.NewConfig() + // .Map(dest => dest.FullName, src => $"{src.Firstname} {src.Lastname}"); + } +} diff --git a/src/CMSMicroservice.Application/Common/Mappings/UserAddressProfile.cs b/src/CMSMicroservice.Application/Common/Mappings/UserAddressProfile.cs new file mode 100644 index 0000000..4347c46 --- /dev/null +++ b/src/CMSMicroservice.Application/Common/Mappings/UserAddressProfile.cs @@ -0,0 +1,10 @@ +namespace CMSMicroservice.Application.Common.Mappings; + +public class UserAddressProfile : IRegister +{ + void IRegister.Register(TypeAdapterConfig config) + { + //config.NewConfig() + // .Map(dest => dest.FullName, src => $"{src.Firstname} {src.Lastname}"); + } +} diff --git a/src/CMSMicroservice.Application/Common/Mappings/UserOrderProfile.cs b/src/CMSMicroservice.Application/Common/Mappings/UserOrderProfile.cs new file mode 100644 index 0000000..f9d2e63 --- /dev/null +++ b/src/CMSMicroservice.Application/Common/Mappings/UserOrderProfile.cs @@ -0,0 +1,10 @@ +namespace CMSMicroservice.Application.Common.Mappings; + +public class UserOrderProfile : IRegister +{ + void IRegister.Register(TypeAdapterConfig config) + { + //config.NewConfig() + // .Map(dest => dest.FullName, src => $"{src.Firstname} {src.Lastname}"); + } +} diff --git a/src/CMSMicroservice.Application/Common/Mappings/UserProfile.cs b/src/CMSMicroservice.Application/Common/Mappings/UserProfile.cs new file mode 100644 index 0000000..12f9563 --- /dev/null +++ b/src/CMSMicroservice.Application/Common/Mappings/UserProfile.cs @@ -0,0 +1,10 @@ +namespace CMSMicroservice.Application.Common.Mappings; + +public class UserProfile : IRegister +{ + void IRegister.Register(TypeAdapterConfig config) + { + //config.NewConfig() + // .Map(dest => dest.FullName, src => $"{src.Firstname} {src.Lastname}"); + } +} diff --git a/src/CMSMicroservice.Application/Common/Mappings/UserRoleProfile.cs b/src/CMSMicroservice.Application/Common/Mappings/UserRoleProfile.cs new file mode 100644 index 0000000..59b221d --- /dev/null +++ b/src/CMSMicroservice.Application/Common/Mappings/UserRoleProfile.cs @@ -0,0 +1,10 @@ +namespace CMSMicroservice.Application.Common.Mappings; + +public class UserRoleProfile : IRegister +{ + void IRegister.Register(TypeAdapterConfig config) + { + //config.NewConfig() + // .Map(dest => dest.FullName, src => $"{src.Firstname} {src.Lastname}"); + } +} diff --git a/src/CMSMicroservice.Application/Common/Models/MetaData.cs b/src/CMSMicroservice.Application/Common/Models/MetaData.cs new file mode 100644 index 0000000..ce1184c --- /dev/null +++ b/src/CMSMicroservice.Application/Common/Models/MetaData.cs @@ -0,0 +1,22 @@ +namespace CMSMicroservice.Application.Common.Models; + +public class MetaData +{ + //صفحه جاری + public long CurrentPage { get; set; } + + //تعداد کل صفحات + public long TotalPage { get; set; } + + //تعداد در هر صفحه + public long PageSize { get; set; } + + //تعداد کل آیتم‌ها + public long TotalCount { get; set; } + + //قبلی دارد؟ + public bool HasPrevious { get; set; } + + //بعدی دارد؟ + public bool HasNext { get; set; } +} diff --git a/src/CMSMicroservice.Application/Common/Models/PaginationState.cs b/src/CMSMicroservice.Application/Common/Models/PaginationState.cs new file mode 100644 index 0000000..3985c71 --- /dev/null +++ b/src/CMSMicroservice.Application/Common/Models/PaginationState.cs @@ -0,0 +1,10 @@ +namespace CMSMicroservice.Application.Common.Models; + +public class PaginationState +{ + //شماره صفحه + public int PageNumber { get; set; } + + //اندازه صفحه + public int PageSize { get; set; } +} diff --git a/src/CMSMicroservice.Application/ConfigureServices.cs b/src/CMSMicroservice.Application/ConfigureServices.cs new file mode 100644 index 0000000..2e33de9 --- /dev/null +++ b/src/CMSMicroservice.Application/ConfigureServices.cs @@ -0,0 +1,31 @@ +using System.Reflection; +using CMSMicroservice.Application.Common.Behaviours; +using MapsterMapper; + +namespace Microsoft.Extensions.DependencyInjection; + +public static class ConfigureServices +{ + public static IServiceCollection AddApplicationServices(this IServiceCollection services) + { + services.AddMapping(); + services.AddValidatorsFromAssembly(Assembly.GetExecutingAssembly()); + services.AddMediatR(AppDomain.CurrentDomain.GetAssemblies()); + services.AddTransient(typeof(IPipelineBehavior<,>), typeof(UnhandledExceptionBehaviour<,>)); + services.AddTransient(typeof(IPipelineBehavior<,>), typeof(ValidationBehaviour<,>)); + services.AddTransient(typeof(IPipelineBehavior<,>), typeof(PerformanceBehaviour<,>)); + + return services; + } + + private static IServiceCollection AddMapping(this IServiceCollection services) + { + var typeAdapterConfig = TypeAdapterConfig.GlobalSettings; + // scans the assembly and gets the IRegister, adding the registration to the TypeAdapterConfig + typeAdapterConfig.Scan(Assembly.GetExecutingAssembly()); + // register the mapper as Singleton service for my application + var mapperConfig = new Mapper(typeAdapterConfig); + services.AddSingleton(mapperConfig); + return services; + } +} diff --git a/src/CMSMicroservice.Application/GlobalUsings.cs b/src/CMSMicroservice.Application/GlobalUsings.cs new file mode 100644 index 0000000..da6b801 --- /dev/null +++ b/src/CMSMicroservice.Application/GlobalUsings.cs @@ -0,0 +1,15 @@ +global using MediatR; +global using FluentValidation; +global using Mapster; + +global using CMSMicroservice.Domain.Entities; +global using CMSMicroservice.Application.Common.Interfaces; +global using System.Threading; +global using System.Threading.Tasks; +global using System; +global using System.Collections.Generic; +global using System.Linq; +global using Microsoft.EntityFrameworkCore; +global using CMSMicroservice.Application.Common.Exceptions; +global using CMSMicroservice.Application.Common.Extensions; +global using CMSMicroservice.Application.Common.Models; diff --git a/src/CMSMicroservice.Application/PackageCQ/Commands/CreateNewPackage/CreateNewPackageCommand.cs b/src/CMSMicroservice.Application/PackageCQ/Commands/CreateNewPackage/CreateNewPackageCommand.cs new file mode 100644 index 0000000..5d8b6e6 --- /dev/null +++ b/src/CMSMicroservice.Application/PackageCQ/Commands/CreateNewPackage/CreateNewPackageCommand.cs @@ -0,0 +1,13 @@ +namespace CMSMicroservice.Application.PackageCQ.Commands.CreateNewPackage; +public record CreateNewPackageCommand : IRequest +{ + //عنوان + public string Title { get; init; } + //توضیحات + public string Description { get; init; } + //آدرس تصویر + public string ImagePath { get; init; } + //قیمت + public long Price { get; init; } + +} \ No newline at end of file diff --git a/src/CMSMicroservice.Application/PackageCQ/Commands/CreateNewPackage/CreateNewPackageCommandHandler.cs b/src/CMSMicroservice.Application/PackageCQ/Commands/CreateNewPackage/CreateNewPackageCommandHandler.cs new file mode 100644 index 0000000..6ac4da7 --- /dev/null +++ b/src/CMSMicroservice.Application/PackageCQ/Commands/CreateNewPackage/CreateNewPackageCommandHandler.cs @@ -0,0 +1,21 @@ +using CMSMicroservice.Domain.Events; +namespace CMSMicroservice.Application.PackageCQ.Commands.CreateNewPackage; +public class CreateNewPackageCommandHandler : IRequestHandler +{ + private readonly IApplicationDbContext _context; + + public CreateNewPackageCommandHandler(IApplicationDbContext context) + { + _context = context; + } + + public async Task Handle(CreateNewPackageCommand request, + CancellationToken cancellationToken) + { + var entity = request.Adapt(); + await _context.Packages.AddAsync(entity, cancellationToken); + entity.AddDomainEvent(new CreateNewPackageEvent(entity)); + await _context.SaveChangesAsync(cancellationToken); + return entity.Adapt(); + } +} diff --git a/src/CMSMicroservice.Application/PackageCQ/Commands/CreateNewPackage/CreateNewPackageCommandValidator.cs b/src/CMSMicroservice.Application/PackageCQ/Commands/CreateNewPackage/CreateNewPackageCommandValidator.cs new file mode 100644 index 0000000..c2fb657 --- /dev/null +++ b/src/CMSMicroservice.Application/PackageCQ/Commands/CreateNewPackage/CreateNewPackageCommandValidator.cs @@ -0,0 +1,22 @@ +namespace CMSMicroservice.Application.PackageCQ.Commands.CreateNewPackage; +public class CreateNewPackageCommandValidator : AbstractValidator +{ + public CreateNewPackageCommandValidator() + { + RuleFor(model => model.Title) + .NotEmpty(); + RuleFor(model => model.Description) + .NotEmpty(); + RuleFor(model => model.ImagePath) + .NotEmpty(); + RuleFor(model => model.Price) + .NotNull(); + } + public Func>> ValidateValue => async (model, propertyName) => + { + var result = await ValidateAsync(ValidationContext.CreateWithOptions((CreateNewPackageCommand)model, x => x.IncludeProperties(propertyName))); + if (result.IsValid) + return Array.Empty(); + return result.Errors.Select(e => e.ErrorMessage); + }; +} diff --git a/src/CMSMicroservice.Application/PackageCQ/Commands/CreateNewPackage/CreateNewPackageResponseDto.cs b/src/CMSMicroservice.Application/PackageCQ/Commands/CreateNewPackage/CreateNewPackageResponseDto.cs new file mode 100644 index 0000000..b1f920a --- /dev/null +++ b/src/CMSMicroservice.Application/PackageCQ/Commands/CreateNewPackage/CreateNewPackageResponseDto.cs @@ -0,0 +1,7 @@ +namespace CMSMicroservice.Application.PackageCQ.Commands.CreateNewPackage; +public class CreateNewPackageResponseDto +{ + //شناسه + public long Id { get; set; } + +} \ No newline at end of file diff --git a/src/CMSMicroservice.Application/PackageCQ/Commands/DeletePackage/DeletePackageCommand.cs b/src/CMSMicroservice.Application/PackageCQ/Commands/DeletePackage/DeletePackageCommand.cs new file mode 100644 index 0000000..530779c --- /dev/null +++ b/src/CMSMicroservice.Application/PackageCQ/Commands/DeletePackage/DeletePackageCommand.cs @@ -0,0 +1,7 @@ +namespace CMSMicroservice.Application.PackageCQ.Commands.DeletePackage; +public record DeletePackageCommand : IRequest +{ + //شناسه + public long Id { get; init; } + +} \ No newline at end of file diff --git a/src/CMSMicroservice.Application/PackageCQ/Commands/DeletePackage/DeletePackageCommandHandler.cs b/src/CMSMicroservice.Application/PackageCQ/Commands/DeletePackage/DeletePackageCommandHandler.cs new file mode 100644 index 0000000..c3f586c --- /dev/null +++ b/src/CMSMicroservice.Application/PackageCQ/Commands/DeletePackage/DeletePackageCommandHandler.cs @@ -0,0 +1,22 @@ +using CMSMicroservice.Domain.Events; +namespace CMSMicroservice.Application.PackageCQ.Commands.DeletePackage; +public class DeletePackageCommandHandler : IRequestHandler +{ + private readonly IApplicationDbContext _context; + + public DeletePackageCommandHandler(IApplicationDbContext context) + { + _context = context; + } + + public async Task Handle(DeletePackageCommand request, CancellationToken cancellationToken) + { + var entity = await _context.Packages + .FirstOrDefaultAsync(x => x.Id == request.Id, cancellationToken) ?? throw new NotFoundException(nameof(Package), request.Id); + entity.IsDeleted = true; + _context.Packages.Update(entity); + entity.AddDomainEvent(new DeletePackageEvent(entity)); + await _context.SaveChangesAsync(cancellationToken); + return Unit.Value; + } +} diff --git a/src/CMSMicroservice.Application/PackageCQ/Commands/DeletePackage/DeletePackageCommandValidator.cs b/src/CMSMicroservice.Application/PackageCQ/Commands/DeletePackage/DeletePackageCommandValidator.cs new file mode 100644 index 0000000..ba2f19f --- /dev/null +++ b/src/CMSMicroservice.Application/PackageCQ/Commands/DeletePackage/DeletePackageCommandValidator.cs @@ -0,0 +1,16 @@ +namespace CMSMicroservice.Application.PackageCQ.Commands.DeletePackage; +public class DeletePackageCommandValidator : AbstractValidator +{ + public DeletePackageCommandValidator() + { + RuleFor(model => model.Id) + .NotNull(); + } + public Func>> ValidateValue => async (model, propertyName) => + { + var result = await ValidateAsync(ValidationContext.CreateWithOptions((DeletePackageCommand)model, x => x.IncludeProperties(propertyName))); + if (result.IsValid) + return Array.Empty(); + return result.Errors.Select(e => e.ErrorMessage); + }; +} diff --git a/src/CMSMicroservice.Application/PackageCQ/Commands/UpdatePackage/UpdatePackageCommand.cs b/src/CMSMicroservice.Application/PackageCQ/Commands/UpdatePackage/UpdatePackageCommand.cs new file mode 100644 index 0000000..caf5896 --- /dev/null +++ b/src/CMSMicroservice.Application/PackageCQ/Commands/UpdatePackage/UpdatePackageCommand.cs @@ -0,0 +1,15 @@ +namespace CMSMicroservice.Application.PackageCQ.Commands.UpdatePackage; +public record UpdatePackageCommand : IRequest +{ + //شناسه + public long Id { get; init; } + //عنوان + public string Title { get; init; } + //توضیحات + public string Description { get; init; } + //آدرس تصویر + public string ImagePath { get; init; } + //قیمت + public long Price { get; init; } + +} \ No newline at end of file diff --git a/src/CMSMicroservice.Application/PackageCQ/Commands/UpdatePackage/UpdatePackageCommandHandler.cs b/src/CMSMicroservice.Application/PackageCQ/Commands/UpdatePackage/UpdatePackageCommandHandler.cs new file mode 100644 index 0000000..417f29b --- /dev/null +++ b/src/CMSMicroservice.Application/PackageCQ/Commands/UpdatePackage/UpdatePackageCommandHandler.cs @@ -0,0 +1,22 @@ +using CMSMicroservice.Domain.Events; +namespace CMSMicroservice.Application.PackageCQ.Commands.UpdatePackage; +public class UpdatePackageCommandHandler : IRequestHandler +{ + private readonly IApplicationDbContext _context; + + public UpdatePackageCommandHandler(IApplicationDbContext context) + { + _context = context; + } + + public async Task Handle(UpdatePackageCommand request, CancellationToken cancellationToken) + { + var entity = await _context.Packages + .FirstOrDefaultAsync(x => x.Id == request.Id, cancellationToken) ?? throw new NotFoundException(nameof(Package), request.Id); + request.Adapt(entity); + _context.Packages.Update(entity); + entity.AddDomainEvent(new UpdatePackageEvent(entity)); + await _context.SaveChangesAsync(cancellationToken); + return Unit.Value; + } +} diff --git a/src/CMSMicroservice.Application/PackageCQ/Commands/UpdatePackage/UpdatePackageCommandValidator.cs b/src/CMSMicroservice.Application/PackageCQ/Commands/UpdatePackage/UpdatePackageCommandValidator.cs new file mode 100644 index 0000000..e197dd3 --- /dev/null +++ b/src/CMSMicroservice.Application/PackageCQ/Commands/UpdatePackage/UpdatePackageCommandValidator.cs @@ -0,0 +1,24 @@ +namespace CMSMicroservice.Application.PackageCQ.Commands.UpdatePackage; +public class UpdatePackageCommandValidator : AbstractValidator +{ + public UpdatePackageCommandValidator() + { + RuleFor(model => model.Id) + .NotNull(); + RuleFor(model => model.Title) + .NotEmpty(); + RuleFor(model => model.Description) + .NotEmpty(); + RuleFor(model => model.ImagePath) + .NotEmpty(); + RuleFor(model => model.Price) + .NotNull(); + } + public Func>> ValidateValue => async (model, propertyName) => + { + var result = await ValidateAsync(ValidationContext.CreateWithOptions((UpdatePackageCommand)model, x => x.IncludeProperties(propertyName))); + if (result.IsValid) + return Array.Empty(); + return result.Errors.Select(e => e.ErrorMessage); + }; +} diff --git a/src/CMSMicroservice.Application/PackageCQ/EventHandlers/CreateNewPackageEventHandlers/CreateNewPackageEventHandler.cs b/src/CMSMicroservice.Application/PackageCQ/EventHandlers/CreateNewPackageEventHandlers/CreateNewPackageEventHandler.cs new file mode 100644 index 0000000..af19590 --- /dev/null +++ b/src/CMSMicroservice.Application/PackageCQ/EventHandlers/CreateNewPackageEventHandlers/CreateNewPackageEventHandler.cs @@ -0,0 +1,21 @@ +using CMSMicroservice.Domain.Events; +using Microsoft.Extensions.Logging; + +namespace CMSMicroservice.Application.PackageCQ.EventHandlers; + +public class CreateNewPackageEventHandler : INotificationHandler +{ + private readonly ILogger _logger; + + public CreateNewPackageEventHandler(ILogger logger) + { + _logger = logger; + } + + public Task Handle(CreateNewPackageEvent notification, CancellationToken cancellationToken) + { + _logger.LogInformation("Domain Event: {DomainEvent}", notification.GetType().Name); + + return Task.CompletedTask; + } +} diff --git a/src/CMSMicroservice.Application/PackageCQ/EventHandlers/DeletePackageEventHandlers/DeletePackageEventHandler.cs b/src/CMSMicroservice.Application/PackageCQ/EventHandlers/DeletePackageEventHandlers/DeletePackageEventHandler.cs new file mode 100644 index 0000000..e80e3f7 --- /dev/null +++ b/src/CMSMicroservice.Application/PackageCQ/EventHandlers/DeletePackageEventHandlers/DeletePackageEventHandler.cs @@ -0,0 +1,21 @@ +using CMSMicroservice.Domain.Events; +using Microsoft.Extensions.Logging; + +namespace CMSMicroservice.Application.PackageCQ.EventHandlers; + +public class DeletePackageEventHandler : INotificationHandler +{ + private readonly ILogger _logger; + + public DeletePackageEventHandler(ILogger logger) + { + _logger = logger; + } + + public Task Handle(DeletePackageEvent notification, CancellationToken cancellationToken) + { + _logger.LogInformation("Domain Event: {DomainEvent}", notification.GetType().Name); + + return Task.CompletedTask; + } +} diff --git a/src/CMSMicroservice.Application/PackageCQ/EventHandlers/UpdatePackageEventHandlers/UpdatePackageEventHandler.cs b/src/CMSMicroservice.Application/PackageCQ/EventHandlers/UpdatePackageEventHandlers/UpdatePackageEventHandler.cs new file mode 100644 index 0000000..23a0913 --- /dev/null +++ b/src/CMSMicroservice.Application/PackageCQ/EventHandlers/UpdatePackageEventHandlers/UpdatePackageEventHandler.cs @@ -0,0 +1,21 @@ +using CMSMicroservice.Domain.Events; +using Microsoft.Extensions.Logging; + +namespace CMSMicroservice.Application.PackageCQ.EventHandlers; + +public class UpdatePackageEventHandler : INotificationHandler +{ + private readonly ILogger _logger; + + public UpdatePackageEventHandler(ILogger logger) + { + _logger = logger; + } + + public Task Handle(UpdatePackageEvent notification, CancellationToken cancellationToken) + { + _logger.LogInformation("Domain Event: {DomainEvent}", notification.GetType().Name); + + return Task.CompletedTask; + } +} diff --git a/src/CMSMicroservice.Application/PackageCQ/Queries/GetAllPackageByFilter/GetAllPackageByFilterQuery.cs b/src/CMSMicroservice.Application/PackageCQ/Queries/GetAllPackageByFilter/GetAllPackageByFilterQuery.cs new file mode 100644 index 0000000..103b12b --- /dev/null +++ b/src/CMSMicroservice.Application/PackageCQ/Queries/GetAllPackageByFilter/GetAllPackageByFilterQuery.cs @@ -0,0 +1,23 @@ +namespace CMSMicroservice.Application.PackageCQ.Queries.GetAllPackageByFilter; +public record GetAllPackageByFilterQuery : IRequest +{ + //موقعیت صفحه بندی + public PaginationState? PaginationState { get; init; } + //مرتب سازی بر اساس + public string? SortBy { get; init; } + //فیلتر + public GetAllPackageByFilterFilter? Filter { get; init; } + +}public class GetAllPackageByFilterFilter +{ + //شناسه + public long? Id { get; set; } + //عنوان + public string? Title { get; set; } + //توضیحات + public string? Description { get; set; } + //آدرس تصویر + public string? ImagePath { get; set; } + //قیمت + public long? Price { get; set; } +} diff --git a/src/CMSMicroservice.Application/PackageCQ/Queries/GetAllPackageByFilter/GetAllPackageByFilterQueryHandler.cs b/src/CMSMicroservice.Application/PackageCQ/Queries/GetAllPackageByFilter/GetAllPackageByFilterQueryHandler.cs new file mode 100644 index 0000000..68ef055 --- /dev/null +++ b/src/CMSMicroservice.Application/PackageCQ/Queries/GetAllPackageByFilter/GetAllPackageByFilterQueryHandler.cs @@ -0,0 +1,34 @@ +namespace CMSMicroservice.Application.PackageCQ.Queries.GetAllPackageByFilter; +public class GetAllPackageByFilterQueryHandler : IRequestHandler +{ + private readonly IApplicationDbContext _context; + + public GetAllPackageByFilterQueryHandler(IApplicationDbContext context) + { + _context = context; + } + + public async Task Handle(GetAllPackageByFilterQuery request, CancellationToken cancellationToken) + { + var query = _context.Packages + .ApplyOrder(sortBy: request.SortBy) + .AsNoTracking() + .AsQueryable(); + if (request.Filter is not null) + { + query = query + .Where(x => request.Filter.Id == null || x.Id == request.Filter.Id) + .Where(x => request.Filter.Title == null || x.Title.Contains(request.Filter.Title)) + .Where(x => request.Filter.Description == null || x.Description.Contains(request.Filter.Description)) + .Where(x => request.Filter.ImagePath == null || x.ImagePath.Contains(request.Filter.ImagePath)) + .Where(x => request.Filter.Price == null || x.Price == request.Filter.Price) +; + } + return new GetAllPackageByFilterResponseDto + { + MetaData = await query.GetMetaData(request.PaginationState, cancellationToken), + Models = await query.PaginatedListAsync(paginationState: request.PaginationState) + .ProjectToType().ToListAsync(cancellationToken) + }; + } +} diff --git a/src/CMSMicroservice.Application/PackageCQ/Queries/GetAllPackageByFilter/GetAllPackageByFilterQueryValidator.cs b/src/CMSMicroservice.Application/PackageCQ/Queries/GetAllPackageByFilter/GetAllPackageByFilterQueryValidator.cs new file mode 100644 index 0000000..6421da4 --- /dev/null +++ b/src/CMSMicroservice.Application/PackageCQ/Queries/GetAllPackageByFilter/GetAllPackageByFilterQueryValidator.cs @@ -0,0 +1,14 @@ +namespace CMSMicroservice.Application.PackageCQ.Queries.GetAllPackageByFilter; +public class GetAllPackageByFilterQueryValidator : AbstractValidator +{ + public GetAllPackageByFilterQueryValidator() + { + } + public Func>> ValidateValue => async (model, propertyName) => + { + var result = await ValidateAsync(ValidationContext.CreateWithOptions((GetAllPackageByFilterQuery)model, x => x.IncludeProperties(propertyName))); + if (result.IsValid) + return Array.Empty(); + return result.Errors.Select(e => e.ErrorMessage); + }; +} diff --git a/src/CMSMicroservice.Application/PackageCQ/Queries/GetAllPackageByFilter/GetAllPackageByFilterResponseDto.cs b/src/CMSMicroservice.Application/PackageCQ/Queries/GetAllPackageByFilter/GetAllPackageByFilterResponseDto.cs new file mode 100644 index 0000000..f8d3b39 --- /dev/null +++ b/src/CMSMicroservice.Application/PackageCQ/Queries/GetAllPackageByFilter/GetAllPackageByFilterResponseDto.cs @@ -0,0 +1,21 @@ +namespace CMSMicroservice.Application.PackageCQ.Queries.GetAllPackageByFilter; +public class GetAllPackageByFilterResponseDto +{ + //متادیتا + public MetaData MetaData { get; set; } + //مدل خروجی + public List? Models { get; set; } + +}public class GetAllPackageByFilterResponseModel +{ + //شناسه + public long Id { get; set; } + //عنوان + public string Title { get; set; } + //توضیحات + public string Description { get; set; } + //آدرس تصویر + public string ImagePath { get; set; } + //قیمت + public long Price { get; set; } +} diff --git a/src/CMSMicroservice.Application/PackageCQ/Queries/GetPackage/GetPackageQuery.cs b/src/CMSMicroservice.Application/PackageCQ/Queries/GetPackage/GetPackageQuery.cs new file mode 100644 index 0000000..f7fb792 --- /dev/null +++ b/src/CMSMicroservice.Application/PackageCQ/Queries/GetPackage/GetPackageQuery.cs @@ -0,0 +1,7 @@ +namespace CMSMicroservice.Application.PackageCQ.Queries.GetPackage; +public record GetPackageQuery : IRequest +{ + //شناسه + public long Id { get; init; } + +} \ No newline at end of file diff --git a/src/CMSMicroservice.Application/PackageCQ/Queries/GetPackage/GetPackageQueryHandler.cs b/src/CMSMicroservice.Application/PackageCQ/Queries/GetPackage/GetPackageQueryHandler.cs new file mode 100644 index 0000000..0a86195 --- /dev/null +++ b/src/CMSMicroservice.Application/PackageCQ/Queries/GetPackage/GetPackageQueryHandler.cs @@ -0,0 +1,22 @@ +namespace CMSMicroservice.Application.PackageCQ.Queries.GetPackage; +public class GetPackageQueryHandler : IRequestHandler +{ + private readonly IApplicationDbContext _context; + + public GetPackageQueryHandler(IApplicationDbContext context) + { + _context = context; + } + + public async Task Handle(GetPackageQuery request, + CancellationToken cancellationToken) + { + var response = await _context.Packages + .AsNoTracking() + .Where(x => x.Id == request.Id) + .ProjectToType() + .FirstOrDefaultAsync(cancellationToken); + + return response ?? throw new NotFoundException(nameof(Package), request.Id); + } +} diff --git a/src/CMSMicroservice.Application/PackageCQ/Queries/GetPackage/GetPackageQueryValidator.cs b/src/CMSMicroservice.Application/PackageCQ/Queries/GetPackage/GetPackageQueryValidator.cs new file mode 100644 index 0000000..7f86346 --- /dev/null +++ b/src/CMSMicroservice.Application/PackageCQ/Queries/GetPackage/GetPackageQueryValidator.cs @@ -0,0 +1,16 @@ +namespace CMSMicroservice.Application.PackageCQ.Queries.GetPackage; +public class GetPackageQueryValidator : AbstractValidator +{ + public GetPackageQueryValidator() + { + RuleFor(model => model.Id) + .NotNull(); + } + public Func>> ValidateValue => async (model, propertyName) => + { + var result = await ValidateAsync(ValidationContext.CreateWithOptions((GetPackageQuery)model, x => x.IncludeProperties(propertyName))); + if (result.IsValid) + return Array.Empty(); + return result.Errors.Select(e => e.ErrorMessage); + }; +} diff --git a/src/CMSMicroservice.Application/PackageCQ/Queries/GetPackage/GetPackageResponseDto.cs b/src/CMSMicroservice.Application/PackageCQ/Queries/GetPackage/GetPackageResponseDto.cs new file mode 100644 index 0000000..04c3252 --- /dev/null +++ b/src/CMSMicroservice.Application/PackageCQ/Queries/GetPackage/GetPackageResponseDto.cs @@ -0,0 +1,15 @@ +namespace CMSMicroservice.Application.PackageCQ.Queries.GetPackage; +public class GetPackageResponseDto +{ + //شناسه + public long Id { get; set; } + //عنوان + public string Title { get; set; } + //توضیحات + public string Description { get; set; } + //آدرس تصویر + public string ImagePath { get; set; } + //قیمت + public long Price { get; set; } + +} \ No newline at end of file diff --git a/src/CMSMicroservice.Application/RoleCQ/Commands/CreateNewRole/CreateNewRoleCommand.cs b/src/CMSMicroservice.Application/RoleCQ/Commands/CreateNewRole/CreateNewRoleCommand.cs new file mode 100644 index 0000000..45225b2 --- /dev/null +++ b/src/CMSMicroservice.Application/RoleCQ/Commands/CreateNewRole/CreateNewRoleCommand.cs @@ -0,0 +1,9 @@ +namespace CMSMicroservice.Application.RoleCQ.Commands.CreateNewRole; +public record CreateNewRoleCommand : IRequest +{ + //نام لاتین + public string Name { get; init; } + //عنوان + public string Title { get; init; } + +} \ No newline at end of file diff --git a/src/CMSMicroservice.Application/RoleCQ/Commands/CreateNewRole/CreateNewRoleCommandHandler.cs b/src/CMSMicroservice.Application/RoleCQ/Commands/CreateNewRole/CreateNewRoleCommandHandler.cs new file mode 100644 index 0000000..98bdb47 --- /dev/null +++ b/src/CMSMicroservice.Application/RoleCQ/Commands/CreateNewRole/CreateNewRoleCommandHandler.cs @@ -0,0 +1,21 @@ +using CMSMicroservice.Domain.Events; +namespace CMSMicroservice.Application.RoleCQ.Commands.CreateNewRole; +public class CreateNewRoleCommandHandler : IRequestHandler +{ + private readonly IApplicationDbContext _context; + + public CreateNewRoleCommandHandler(IApplicationDbContext context) + { + _context = context; + } + + public async Task Handle(CreateNewRoleCommand request, + CancellationToken cancellationToken) + { + var entity = request.Adapt(); + await _context.Roles.AddAsync(entity, cancellationToken); + entity.AddDomainEvent(new CreateNewRoleEvent(entity)); + await _context.SaveChangesAsync(cancellationToken); + return entity.Adapt(); + } +} diff --git a/src/CMSMicroservice.Application/RoleCQ/Commands/CreateNewRole/CreateNewRoleCommandValidator.cs b/src/CMSMicroservice.Application/RoleCQ/Commands/CreateNewRole/CreateNewRoleCommandValidator.cs new file mode 100644 index 0000000..e365c3b --- /dev/null +++ b/src/CMSMicroservice.Application/RoleCQ/Commands/CreateNewRole/CreateNewRoleCommandValidator.cs @@ -0,0 +1,18 @@ +namespace CMSMicroservice.Application.RoleCQ.Commands.CreateNewRole; +public class CreateNewRoleCommandValidator : AbstractValidator +{ + public CreateNewRoleCommandValidator() + { + RuleFor(model => model.Name) + .NotEmpty(); + RuleFor(model => model.Title) + .NotEmpty(); + } + public Func>> ValidateValue => async (model, propertyName) => + { + var result = await ValidateAsync(ValidationContext.CreateWithOptions((CreateNewRoleCommand)model, x => x.IncludeProperties(propertyName))); + if (result.IsValid) + return Array.Empty(); + return result.Errors.Select(e => e.ErrorMessage); + }; +} diff --git a/src/CMSMicroservice.Application/RoleCQ/Commands/CreateNewRole/CreateNewRoleResponseDto.cs b/src/CMSMicroservice.Application/RoleCQ/Commands/CreateNewRole/CreateNewRoleResponseDto.cs new file mode 100644 index 0000000..21e6cbc --- /dev/null +++ b/src/CMSMicroservice.Application/RoleCQ/Commands/CreateNewRole/CreateNewRoleResponseDto.cs @@ -0,0 +1,7 @@ +namespace CMSMicroservice.Application.RoleCQ.Commands.CreateNewRole; +public class CreateNewRoleResponseDto +{ + //شناسه + public long Id { get; set; } + +} \ No newline at end of file diff --git a/src/CMSMicroservice.Application/RoleCQ/Commands/DeleteRole/DeleteRoleCommand.cs b/src/CMSMicroservice.Application/RoleCQ/Commands/DeleteRole/DeleteRoleCommand.cs new file mode 100644 index 0000000..1929466 --- /dev/null +++ b/src/CMSMicroservice.Application/RoleCQ/Commands/DeleteRole/DeleteRoleCommand.cs @@ -0,0 +1,7 @@ +namespace CMSMicroservice.Application.RoleCQ.Commands.DeleteRole; +public record DeleteRoleCommand : IRequest +{ + //شناسه + public long Id { get; init; } + +} \ No newline at end of file diff --git a/src/CMSMicroservice.Application/RoleCQ/Commands/DeleteRole/DeleteRoleCommandHandler.cs b/src/CMSMicroservice.Application/RoleCQ/Commands/DeleteRole/DeleteRoleCommandHandler.cs new file mode 100644 index 0000000..6a2bc0e --- /dev/null +++ b/src/CMSMicroservice.Application/RoleCQ/Commands/DeleteRole/DeleteRoleCommandHandler.cs @@ -0,0 +1,22 @@ +using CMSMicroservice.Domain.Events; +namespace CMSMicroservice.Application.RoleCQ.Commands.DeleteRole; +public class DeleteRoleCommandHandler : IRequestHandler +{ + private readonly IApplicationDbContext _context; + + public DeleteRoleCommandHandler(IApplicationDbContext context) + { + _context = context; + } + + public async Task Handle(DeleteRoleCommand request, CancellationToken cancellationToken) + { + var entity = await _context.Roles + .FirstOrDefaultAsync(x => x.Id == request.Id, cancellationToken) ?? throw new NotFoundException(nameof(Role), request.Id); + entity.IsDeleted = true; + _context.Roles.Update(entity); + entity.AddDomainEvent(new DeleteRoleEvent(entity)); + await _context.SaveChangesAsync(cancellationToken); + return Unit.Value; + } +} diff --git a/src/CMSMicroservice.Application/RoleCQ/Commands/DeleteRole/DeleteRoleCommandValidator.cs b/src/CMSMicroservice.Application/RoleCQ/Commands/DeleteRole/DeleteRoleCommandValidator.cs new file mode 100644 index 0000000..c349fef --- /dev/null +++ b/src/CMSMicroservice.Application/RoleCQ/Commands/DeleteRole/DeleteRoleCommandValidator.cs @@ -0,0 +1,16 @@ +namespace CMSMicroservice.Application.RoleCQ.Commands.DeleteRole; +public class DeleteRoleCommandValidator : AbstractValidator +{ + public DeleteRoleCommandValidator() + { + RuleFor(model => model.Id) + .NotNull(); + } + public Func>> ValidateValue => async (model, propertyName) => + { + var result = await ValidateAsync(ValidationContext.CreateWithOptions((DeleteRoleCommand)model, x => x.IncludeProperties(propertyName))); + if (result.IsValid) + return Array.Empty(); + return result.Errors.Select(e => e.ErrorMessage); + }; +} diff --git a/src/CMSMicroservice.Application/RoleCQ/Commands/UpdateRole/UpdateRoleCommand.cs b/src/CMSMicroservice.Application/RoleCQ/Commands/UpdateRole/UpdateRoleCommand.cs new file mode 100644 index 0000000..a0199d9 --- /dev/null +++ b/src/CMSMicroservice.Application/RoleCQ/Commands/UpdateRole/UpdateRoleCommand.cs @@ -0,0 +1,11 @@ +namespace CMSMicroservice.Application.RoleCQ.Commands.UpdateRole; +public record UpdateRoleCommand : IRequest +{ + //شناسه + public long Id { get; init; } + //نام لاتین + public string Name { get; init; } + //عنوان + public string Title { get; init; } + +} \ No newline at end of file diff --git a/src/CMSMicroservice.Application/RoleCQ/Commands/UpdateRole/UpdateRoleCommandHandler.cs b/src/CMSMicroservice.Application/RoleCQ/Commands/UpdateRole/UpdateRoleCommandHandler.cs new file mode 100644 index 0000000..ecd1e30 --- /dev/null +++ b/src/CMSMicroservice.Application/RoleCQ/Commands/UpdateRole/UpdateRoleCommandHandler.cs @@ -0,0 +1,22 @@ +using CMSMicroservice.Domain.Events; +namespace CMSMicroservice.Application.RoleCQ.Commands.UpdateRole; +public class UpdateRoleCommandHandler : IRequestHandler +{ + private readonly IApplicationDbContext _context; + + public UpdateRoleCommandHandler(IApplicationDbContext context) + { + _context = context; + } + + public async Task Handle(UpdateRoleCommand request, CancellationToken cancellationToken) + { + var entity = await _context.Roles + .FirstOrDefaultAsync(x => x.Id == request.Id, cancellationToken) ?? throw new NotFoundException(nameof(Role), request.Id); + request.Adapt(entity); + _context.Roles.Update(entity); + entity.AddDomainEvent(new UpdateRoleEvent(entity)); + await _context.SaveChangesAsync(cancellationToken); + return Unit.Value; + } +} diff --git a/src/CMSMicroservice.Application/RoleCQ/Commands/UpdateRole/UpdateRoleCommandValidator.cs b/src/CMSMicroservice.Application/RoleCQ/Commands/UpdateRole/UpdateRoleCommandValidator.cs new file mode 100644 index 0000000..8892075 --- /dev/null +++ b/src/CMSMicroservice.Application/RoleCQ/Commands/UpdateRole/UpdateRoleCommandValidator.cs @@ -0,0 +1,20 @@ +namespace CMSMicroservice.Application.RoleCQ.Commands.UpdateRole; +public class UpdateRoleCommandValidator : AbstractValidator +{ + public UpdateRoleCommandValidator() + { + RuleFor(model => model.Id) + .NotNull(); + RuleFor(model => model.Name) + .NotEmpty(); + RuleFor(model => model.Title) + .NotEmpty(); + } + public Func>> ValidateValue => async (model, propertyName) => + { + var result = await ValidateAsync(ValidationContext.CreateWithOptions((UpdateRoleCommand)model, x => x.IncludeProperties(propertyName))); + if (result.IsValid) + return Array.Empty(); + return result.Errors.Select(e => e.ErrorMessage); + }; +} diff --git a/src/CMSMicroservice.Application/RoleCQ/EventHandlers/CreateNewRoleEventHandlers/CreateNewRoleEventHandler.cs b/src/CMSMicroservice.Application/RoleCQ/EventHandlers/CreateNewRoleEventHandlers/CreateNewRoleEventHandler.cs new file mode 100644 index 0000000..ed4892c --- /dev/null +++ b/src/CMSMicroservice.Application/RoleCQ/EventHandlers/CreateNewRoleEventHandlers/CreateNewRoleEventHandler.cs @@ -0,0 +1,21 @@ +using CMSMicroservice.Domain.Events; +using Microsoft.Extensions.Logging; + +namespace CMSMicroservice.Application.RoleCQ.EventHandlers; + +public class CreateNewRoleEventHandler : INotificationHandler +{ + private readonly ILogger _logger; + + public CreateNewRoleEventHandler(ILogger logger) + { + _logger = logger; + } + + public Task Handle(CreateNewRoleEvent notification, CancellationToken cancellationToken) + { + _logger.LogInformation("Domain Event: {DomainEvent}", notification.GetType().Name); + + return Task.CompletedTask; + } +} diff --git a/src/CMSMicroservice.Application/RoleCQ/EventHandlers/DeleteRoleEventHandlers/DeleteRoleEventHandler.cs b/src/CMSMicroservice.Application/RoleCQ/EventHandlers/DeleteRoleEventHandlers/DeleteRoleEventHandler.cs new file mode 100644 index 0000000..7fb16c4 --- /dev/null +++ b/src/CMSMicroservice.Application/RoleCQ/EventHandlers/DeleteRoleEventHandlers/DeleteRoleEventHandler.cs @@ -0,0 +1,21 @@ +using CMSMicroservice.Domain.Events; +using Microsoft.Extensions.Logging; + +namespace CMSMicroservice.Application.RoleCQ.EventHandlers; + +public class DeleteRoleEventHandler : INotificationHandler +{ + private readonly ILogger _logger; + + public DeleteRoleEventHandler(ILogger logger) + { + _logger = logger; + } + + public Task Handle(DeleteRoleEvent notification, CancellationToken cancellationToken) + { + _logger.LogInformation("Domain Event: {DomainEvent}", notification.GetType().Name); + + return Task.CompletedTask; + } +} diff --git a/src/CMSMicroservice.Application/RoleCQ/EventHandlers/UpdateRoleEventHandlers/UpdateRoleEventHandler.cs b/src/CMSMicroservice.Application/RoleCQ/EventHandlers/UpdateRoleEventHandlers/UpdateRoleEventHandler.cs new file mode 100644 index 0000000..d8113bc --- /dev/null +++ b/src/CMSMicroservice.Application/RoleCQ/EventHandlers/UpdateRoleEventHandlers/UpdateRoleEventHandler.cs @@ -0,0 +1,21 @@ +using CMSMicroservice.Domain.Events; +using Microsoft.Extensions.Logging; + +namespace CMSMicroservice.Application.RoleCQ.EventHandlers; + +public class UpdateRoleEventHandler : INotificationHandler +{ + private readonly ILogger _logger; + + public UpdateRoleEventHandler(ILogger logger) + { + _logger = logger; + } + + public Task Handle(UpdateRoleEvent notification, CancellationToken cancellationToken) + { + _logger.LogInformation("Domain Event: {DomainEvent}", notification.GetType().Name); + + return Task.CompletedTask; + } +} diff --git a/src/CMSMicroservice.Application/RoleCQ/Queries/GetAllRoleByFilter/GetAllRoleByFilterQuery.cs b/src/CMSMicroservice.Application/RoleCQ/Queries/GetAllRoleByFilter/GetAllRoleByFilterQuery.cs new file mode 100644 index 0000000..9ecacdb --- /dev/null +++ b/src/CMSMicroservice.Application/RoleCQ/Queries/GetAllRoleByFilter/GetAllRoleByFilterQuery.cs @@ -0,0 +1,19 @@ +namespace CMSMicroservice.Application.RoleCQ.Queries.GetAllRoleByFilter; +public record GetAllRoleByFilterQuery : IRequest +{ + //موقعیت صفحه بندی + public PaginationState? PaginationState { get; init; } + //مرتب سازی بر اساس + public string? SortBy { get; init; } + //فیلتر + public GetAllRoleByFilterFilter? Filter { get; init; } + +}public class GetAllRoleByFilterFilter +{ + //شناسه + public long? Id { get; set; } + //نام لاتین + public string? Name { get; set; } + //عنوان + public string? Title { get; set; } +} diff --git a/src/CMSMicroservice.Application/RoleCQ/Queries/GetAllRoleByFilter/GetAllRoleByFilterQueryHandler.cs b/src/CMSMicroservice.Application/RoleCQ/Queries/GetAllRoleByFilter/GetAllRoleByFilterQueryHandler.cs new file mode 100644 index 0000000..5529378 --- /dev/null +++ b/src/CMSMicroservice.Application/RoleCQ/Queries/GetAllRoleByFilter/GetAllRoleByFilterQueryHandler.cs @@ -0,0 +1,32 @@ +namespace CMSMicroservice.Application.RoleCQ.Queries.GetAllRoleByFilter; +public class GetAllRoleByFilterQueryHandler : IRequestHandler +{ + private readonly IApplicationDbContext _context; + + public GetAllRoleByFilterQueryHandler(IApplicationDbContext context) + { + _context = context; + } + + public async Task Handle(GetAllRoleByFilterQuery request, CancellationToken cancellationToken) + { + var query = _context.Roles + .ApplyOrder(sortBy: request.SortBy) + .AsNoTracking() + .AsQueryable(); + if (request.Filter is not null) + { + query = query + .Where(x => request.Filter.Id == null || x.Id == request.Filter.Id) + .Where(x => request.Filter.Name == null || x.Name.Contains(request.Filter.Name)) + .Where(x => request.Filter.Title == null || x.Title.Contains(request.Filter.Title)) +; + } + return new GetAllRoleByFilterResponseDto + { + MetaData = await query.GetMetaData(request.PaginationState, cancellationToken), + Models = await query.PaginatedListAsync(paginationState: request.PaginationState) + .ProjectToType().ToListAsync(cancellationToken) + }; + } +} diff --git a/src/CMSMicroservice.Application/RoleCQ/Queries/GetAllRoleByFilter/GetAllRoleByFilterQueryValidator.cs b/src/CMSMicroservice.Application/RoleCQ/Queries/GetAllRoleByFilter/GetAllRoleByFilterQueryValidator.cs new file mode 100644 index 0000000..7428528 --- /dev/null +++ b/src/CMSMicroservice.Application/RoleCQ/Queries/GetAllRoleByFilter/GetAllRoleByFilterQueryValidator.cs @@ -0,0 +1,14 @@ +namespace CMSMicroservice.Application.RoleCQ.Queries.GetAllRoleByFilter; +public class GetAllRoleByFilterQueryValidator : AbstractValidator +{ + public GetAllRoleByFilterQueryValidator() + { + } + public Func>> ValidateValue => async (model, propertyName) => + { + var result = await ValidateAsync(ValidationContext.CreateWithOptions((GetAllRoleByFilterQuery)model, x => x.IncludeProperties(propertyName))); + if (result.IsValid) + return Array.Empty(); + return result.Errors.Select(e => e.ErrorMessage); + }; +} diff --git a/src/CMSMicroservice.Application/RoleCQ/Queries/GetAllRoleByFilter/GetAllRoleByFilterResponseDto.cs b/src/CMSMicroservice.Application/RoleCQ/Queries/GetAllRoleByFilter/GetAllRoleByFilterResponseDto.cs new file mode 100644 index 0000000..f8d6de1 --- /dev/null +++ b/src/CMSMicroservice.Application/RoleCQ/Queries/GetAllRoleByFilter/GetAllRoleByFilterResponseDto.cs @@ -0,0 +1,17 @@ +namespace CMSMicroservice.Application.RoleCQ.Queries.GetAllRoleByFilter; +public class GetAllRoleByFilterResponseDto +{ + //متادیتا + public MetaData MetaData { get; set; } + //مدل خروجی + public List? Models { get; set; } + +}public class GetAllRoleByFilterResponseModel +{ + //شناسه + public long Id { get; set; } + //نام لاتین + public string Name { get; set; } + //عنوان + public string Title { get; set; } +} diff --git a/src/CMSMicroservice.Application/RoleCQ/Queries/GetRole/GetRoleQuery.cs b/src/CMSMicroservice.Application/RoleCQ/Queries/GetRole/GetRoleQuery.cs new file mode 100644 index 0000000..94505a4 --- /dev/null +++ b/src/CMSMicroservice.Application/RoleCQ/Queries/GetRole/GetRoleQuery.cs @@ -0,0 +1,7 @@ +namespace CMSMicroservice.Application.RoleCQ.Queries.GetRole; +public record GetRoleQuery : IRequest +{ + //شناسه + public long Id { get; init; } + +} \ No newline at end of file diff --git a/src/CMSMicroservice.Application/RoleCQ/Queries/GetRole/GetRoleQueryHandler.cs b/src/CMSMicroservice.Application/RoleCQ/Queries/GetRole/GetRoleQueryHandler.cs new file mode 100644 index 0000000..8074457 --- /dev/null +++ b/src/CMSMicroservice.Application/RoleCQ/Queries/GetRole/GetRoleQueryHandler.cs @@ -0,0 +1,22 @@ +namespace CMSMicroservice.Application.RoleCQ.Queries.GetRole; +public class GetRoleQueryHandler : IRequestHandler +{ + private readonly IApplicationDbContext _context; + + public GetRoleQueryHandler(IApplicationDbContext context) + { + _context = context; + } + + public async Task Handle(GetRoleQuery request, + CancellationToken cancellationToken) + { + var response = await _context.Roles + .AsNoTracking() + .Where(x => x.Id == request.Id) + .ProjectToType() + .FirstOrDefaultAsync(cancellationToken); + + return response ?? throw new NotFoundException(nameof(Role), request.Id); + } +} diff --git a/src/CMSMicroservice.Application/RoleCQ/Queries/GetRole/GetRoleQueryValidator.cs b/src/CMSMicroservice.Application/RoleCQ/Queries/GetRole/GetRoleQueryValidator.cs new file mode 100644 index 0000000..df6b02e --- /dev/null +++ b/src/CMSMicroservice.Application/RoleCQ/Queries/GetRole/GetRoleQueryValidator.cs @@ -0,0 +1,16 @@ +namespace CMSMicroservice.Application.RoleCQ.Queries.GetRole; +public class GetRoleQueryValidator : AbstractValidator +{ + public GetRoleQueryValidator() + { + RuleFor(model => model.Id) + .NotNull(); + } + public Func>> ValidateValue => async (model, propertyName) => + { + var result = await ValidateAsync(ValidationContext.CreateWithOptions((GetRoleQuery)model, x => x.IncludeProperties(propertyName))); + if (result.IsValid) + return Array.Empty(); + return result.Errors.Select(e => e.ErrorMessage); + }; +} diff --git a/src/CMSMicroservice.Application/RoleCQ/Queries/GetRole/GetRoleResponseDto.cs b/src/CMSMicroservice.Application/RoleCQ/Queries/GetRole/GetRoleResponseDto.cs new file mode 100644 index 0000000..485674d --- /dev/null +++ b/src/CMSMicroservice.Application/RoleCQ/Queries/GetRole/GetRoleResponseDto.cs @@ -0,0 +1,11 @@ +namespace CMSMicroservice.Application.RoleCQ.Queries.GetRole; +public class GetRoleResponseDto +{ + //شناسه + public long Id { get; set; } + //نام لاتین + public string Name { get; set; } + //عنوان + public string Title { get; set; } + +} \ No newline at end of file diff --git a/src/CMSMicroservice.Application/UserAddressCQ/Commands/CreateNewUserAddress/CreateNewUserAddressCommand.cs b/src/CMSMicroservice.Application/UserAddressCQ/Commands/CreateNewUserAddress/CreateNewUserAddressCommand.cs new file mode 100644 index 0000000..9cb57e9 --- /dev/null +++ b/src/CMSMicroservice.Application/UserAddressCQ/Commands/CreateNewUserAddress/CreateNewUserAddressCommand.cs @@ -0,0 +1,17 @@ +namespace CMSMicroservice.Application.UserAddressCQ.Commands.CreateNewUserAddress; +public record CreateNewUserAddressCommand : IRequest +{ + //شناسه کاربر + public long UserId { get; init; } + //عنوان + public string Title { get; init; } + //آدرس + public string Address { get; init; } + //کدپستی + public string PostalCode { get; init; } + //پیشفرض؟ + public bool IsDefault { get; init; } + //شناسه شهر + public long CityId { get; init; } + +} \ No newline at end of file diff --git a/src/CMSMicroservice.Application/UserAddressCQ/Commands/CreateNewUserAddress/CreateNewUserAddressCommandHandler.cs b/src/CMSMicroservice.Application/UserAddressCQ/Commands/CreateNewUserAddress/CreateNewUserAddressCommandHandler.cs new file mode 100644 index 0000000..4d5e99d --- /dev/null +++ b/src/CMSMicroservice.Application/UserAddressCQ/Commands/CreateNewUserAddress/CreateNewUserAddressCommandHandler.cs @@ -0,0 +1,21 @@ +using CMSMicroservice.Domain.Events; +namespace CMSMicroservice.Application.UserAddressCQ.Commands.CreateNewUserAddress; +public class CreateNewUserAddressCommandHandler : IRequestHandler +{ + private readonly IApplicationDbContext _context; + + public CreateNewUserAddressCommandHandler(IApplicationDbContext context) + { + _context = context; + } + + public async Task Handle(CreateNewUserAddressCommand request, + CancellationToken cancellationToken) + { + var entity = request.Adapt(); + await _context.UserAddresss.AddAsync(entity, cancellationToken); + entity.AddDomainEvent(new CreateNewUserAddressEvent(entity)); + await _context.SaveChangesAsync(cancellationToken); + return entity.Adapt(); + } +} diff --git a/src/CMSMicroservice.Application/UserAddressCQ/Commands/CreateNewUserAddress/CreateNewUserAddressCommandValidator.cs b/src/CMSMicroservice.Application/UserAddressCQ/Commands/CreateNewUserAddress/CreateNewUserAddressCommandValidator.cs new file mode 100644 index 0000000..ef307ab --- /dev/null +++ b/src/CMSMicroservice.Application/UserAddressCQ/Commands/CreateNewUserAddress/CreateNewUserAddressCommandValidator.cs @@ -0,0 +1,26 @@ +namespace CMSMicroservice.Application.UserAddressCQ.Commands.CreateNewUserAddress; +public class CreateNewUserAddressCommandValidator : AbstractValidator +{ + public CreateNewUserAddressCommandValidator() + { + RuleFor(model => model.UserId) + .NotNull(); + RuleFor(model => model.Title) + .NotEmpty(); + RuleFor(model => model.Address) + .NotEmpty(); + RuleFor(model => model.PostalCode) + .NotEmpty(); + RuleFor(model => model.IsDefault) + .NotNull(); + RuleFor(model => model.CityId) + .NotNull(); + } + public Func>> ValidateValue => async (model, propertyName) => + { + var result = await ValidateAsync(ValidationContext.CreateWithOptions((CreateNewUserAddressCommand)model, x => x.IncludeProperties(propertyName))); + if (result.IsValid) + return Array.Empty(); + return result.Errors.Select(e => e.ErrorMessage); + }; +} diff --git a/src/CMSMicroservice.Application/UserAddressCQ/Commands/CreateNewUserAddress/CreateNewUserAddressResponseDto.cs b/src/CMSMicroservice.Application/UserAddressCQ/Commands/CreateNewUserAddress/CreateNewUserAddressResponseDto.cs new file mode 100644 index 0000000..095f516 --- /dev/null +++ b/src/CMSMicroservice.Application/UserAddressCQ/Commands/CreateNewUserAddress/CreateNewUserAddressResponseDto.cs @@ -0,0 +1,7 @@ +namespace CMSMicroservice.Application.UserAddressCQ.Commands.CreateNewUserAddress; +public class CreateNewUserAddressResponseDto +{ + //شناسه + public long Id { get; set; } + +} \ No newline at end of file diff --git a/src/CMSMicroservice.Application/UserAddressCQ/Commands/DeleteUserAddress/DeleteUserAddressCommand.cs b/src/CMSMicroservice.Application/UserAddressCQ/Commands/DeleteUserAddress/DeleteUserAddressCommand.cs new file mode 100644 index 0000000..2790477 --- /dev/null +++ b/src/CMSMicroservice.Application/UserAddressCQ/Commands/DeleteUserAddress/DeleteUserAddressCommand.cs @@ -0,0 +1,7 @@ +namespace CMSMicroservice.Application.UserAddressCQ.Commands.DeleteUserAddress; +public record DeleteUserAddressCommand : IRequest +{ + //شناسه + public long Id { get; init; } + +} \ No newline at end of file diff --git a/src/CMSMicroservice.Application/UserAddressCQ/Commands/DeleteUserAddress/DeleteUserAddressCommandHandler.cs b/src/CMSMicroservice.Application/UserAddressCQ/Commands/DeleteUserAddress/DeleteUserAddressCommandHandler.cs new file mode 100644 index 0000000..b691a95 --- /dev/null +++ b/src/CMSMicroservice.Application/UserAddressCQ/Commands/DeleteUserAddress/DeleteUserAddressCommandHandler.cs @@ -0,0 +1,22 @@ +using CMSMicroservice.Domain.Events; +namespace CMSMicroservice.Application.UserAddressCQ.Commands.DeleteUserAddress; +public class DeleteUserAddressCommandHandler : IRequestHandler +{ + private readonly IApplicationDbContext _context; + + public DeleteUserAddressCommandHandler(IApplicationDbContext context) + { + _context = context; + } + + public async Task Handle(DeleteUserAddressCommand request, CancellationToken cancellationToken) + { + var entity = await _context.UserAddresss + .FirstOrDefaultAsync(x => x.Id == request.Id, cancellationToken) ?? throw new NotFoundException(nameof(UserAddress), request.Id); + entity.IsDeleted = true; + _context.UserAddresss.Update(entity); + entity.AddDomainEvent(new DeleteUserAddressEvent(entity)); + await _context.SaveChangesAsync(cancellationToken); + return Unit.Value; + } +} diff --git a/src/CMSMicroservice.Application/UserAddressCQ/Commands/DeleteUserAddress/DeleteUserAddressCommandValidator.cs b/src/CMSMicroservice.Application/UserAddressCQ/Commands/DeleteUserAddress/DeleteUserAddressCommandValidator.cs new file mode 100644 index 0000000..bbeab87 --- /dev/null +++ b/src/CMSMicroservice.Application/UserAddressCQ/Commands/DeleteUserAddress/DeleteUserAddressCommandValidator.cs @@ -0,0 +1,16 @@ +namespace CMSMicroservice.Application.UserAddressCQ.Commands.DeleteUserAddress; +public class DeleteUserAddressCommandValidator : AbstractValidator +{ + public DeleteUserAddressCommandValidator() + { + RuleFor(model => model.Id) + .NotNull(); + } + public Func>> ValidateValue => async (model, propertyName) => + { + var result = await ValidateAsync(ValidationContext.CreateWithOptions((DeleteUserAddressCommand)model, x => x.IncludeProperties(propertyName))); + if (result.IsValid) + return Array.Empty(); + return result.Errors.Select(e => e.ErrorMessage); + }; +} diff --git a/src/CMSMicroservice.Application/UserAddressCQ/Commands/UpdateUserAddress/UpdateUserAddressCommand.cs b/src/CMSMicroservice.Application/UserAddressCQ/Commands/UpdateUserAddress/UpdateUserAddressCommand.cs new file mode 100644 index 0000000..b8999dc --- /dev/null +++ b/src/CMSMicroservice.Application/UserAddressCQ/Commands/UpdateUserAddress/UpdateUserAddressCommand.cs @@ -0,0 +1,19 @@ +namespace CMSMicroservice.Application.UserAddressCQ.Commands.UpdateUserAddress; +public record UpdateUserAddressCommand : IRequest +{ + //شناسه + public long Id { get; init; } + //شناسه کاربر + public long UserId { get; init; } + //عنوان + public string Title { get; init; } + //آدرس + public string Address { get; init; } + //کدپستی + public string PostalCode { get; init; } + //پیشفرض؟ + public bool IsDefault { get; init; } + //شناسه شهر + public long CityId { get; init; } + +} \ No newline at end of file diff --git a/src/CMSMicroservice.Application/UserAddressCQ/Commands/UpdateUserAddress/UpdateUserAddressCommandHandler.cs b/src/CMSMicroservice.Application/UserAddressCQ/Commands/UpdateUserAddress/UpdateUserAddressCommandHandler.cs new file mode 100644 index 0000000..e8b8ec1 --- /dev/null +++ b/src/CMSMicroservice.Application/UserAddressCQ/Commands/UpdateUserAddress/UpdateUserAddressCommandHandler.cs @@ -0,0 +1,22 @@ +using CMSMicroservice.Domain.Events; +namespace CMSMicroservice.Application.UserAddressCQ.Commands.UpdateUserAddress; +public class UpdateUserAddressCommandHandler : IRequestHandler +{ + private readonly IApplicationDbContext _context; + + public UpdateUserAddressCommandHandler(IApplicationDbContext context) + { + _context = context; + } + + public async Task Handle(UpdateUserAddressCommand request, CancellationToken cancellationToken) + { + var entity = await _context.UserAddresss + .FirstOrDefaultAsync(x => x.Id == request.Id, cancellationToken) ?? throw new NotFoundException(nameof(UserAddress), request.Id); + request.Adapt(entity); + _context.UserAddresss.Update(entity); + entity.AddDomainEvent(new UpdateUserAddressEvent(entity)); + await _context.SaveChangesAsync(cancellationToken); + return Unit.Value; + } +} diff --git a/src/CMSMicroservice.Application/UserAddressCQ/Commands/UpdateUserAddress/UpdateUserAddressCommandValidator.cs b/src/CMSMicroservice.Application/UserAddressCQ/Commands/UpdateUserAddress/UpdateUserAddressCommandValidator.cs new file mode 100644 index 0000000..7b99f50 --- /dev/null +++ b/src/CMSMicroservice.Application/UserAddressCQ/Commands/UpdateUserAddress/UpdateUserAddressCommandValidator.cs @@ -0,0 +1,28 @@ +namespace CMSMicroservice.Application.UserAddressCQ.Commands.UpdateUserAddress; +public class UpdateUserAddressCommandValidator : AbstractValidator +{ + public UpdateUserAddressCommandValidator() + { + RuleFor(model => model.Id) + .NotNull(); + RuleFor(model => model.UserId) + .NotNull(); + RuleFor(model => model.Title) + .NotEmpty(); + RuleFor(model => model.Address) + .NotEmpty(); + RuleFor(model => model.PostalCode) + .NotEmpty(); + RuleFor(model => model.IsDefault) + .NotNull(); + RuleFor(model => model.CityId) + .NotNull(); + } + public Func>> ValidateValue => async (model, propertyName) => + { + var result = await ValidateAsync(ValidationContext.CreateWithOptions((UpdateUserAddressCommand)model, x => x.IncludeProperties(propertyName))); + if (result.IsValid) + return Array.Empty(); + return result.Errors.Select(e => e.ErrorMessage); + }; +} diff --git a/src/CMSMicroservice.Application/UserAddressCQ/EventHandlers/CreateNewUserAddressEventHandlers/CreateNewUserAddressEventHandler.cs b/src/CMSMicroservice.Application/UserAddressCQ/EventHandlers/CreateNewUserAddressEventHandlers/CreateNewUserAddressEventHandler.cs new file mode 100644 index 0000000..36d78cd --- /dev/null +++ b/src/CMSMicroservice.Application/UserAddressCQ/EventHandlers/CreateNewUserAddressEventHandlers/CreateNewUserAddressEventHandler.cs @@ -0,0 +1,21 @@ +using CMSMicroservice.Domain.Events; +using Microsoft.Extensions.Logging; + +namespace CMSMicroservice.Application.UserAddressCQ.EventHandlers; + +public class CreateNewUserAddressEventHandler : INotificationHandler +{ + private readonly ILogger _logger; + + public CreateNewUserAddressEventHandler(ILogger logger) + { + _logger = logger; + } + + public Task Handle(CreateNewUserAddressEvent notification, CancellationToken cancellationToken) + { + _logger.LogInformation("Domain Event: {DomainEvent}", notification.GetType().Name); + + return Task.CompletedTask; + } +} diff --git a/src/CMSMicroservice.Application/UserAddressCQ/EventHandlers/DeleteUserAddressEventHandlers/DeleteUserAddressEventHandler.cs b/src/CMSMicroservice.Application/UserAddressCQ/EventHandlers/DeleteUserAddressEventHandlers/DeleteUserAddressEventHandler.cs new file mode 100644 index 0000000..4cff41c --- /dev/null +++ b/src/CMSMicroservice.Application/UserAddressCQ/EventHandlers/DeleteUserAddressEventHandlers/DeleteUserAddressEventHandler.cs @@ -0,0 +1,21 @@ +using CMSMicroservice.Domain.Events; +using Microsoft.Extensions.Logging; + +namespace CMSMicroservice.Application.UserAddressCQ.EventHandlers; + +public class DeleteUserAddressEventHandler : INotificationHandler +{ + private readonly ILogger _logger; + + public DeleteUserAddressEventHandler(ILogger logger) + { + _logger = logger; + } + + public Task Handle(DeleteUserAddressEvent notification, CancellationToken cancellationToken) + { + _logger.LogInformation("Domain Event: {DomainEvent}", notification.GetType().Name); + + return Task.CompletedTask; + } +} diff --git a/src/CMSMicroservice.Application/UserAddressCQ/EventHandlers/UpdateUserAddressEventHandlers/UpdateUserAddressEventHandler.cs b/src/CMSMicroservice.Application/UserAddressCQ/EventHandlers/UpdateUserAddressEventHandlers/UpdateUserAddressEventHandler.cs new file mode 100644 index 0000000..589bc35 --- /dev/null +++ b/src/CMSMicroservice.Application/UserAddressCQ/EventHandlers/UpdateUserAddressEventHandlers/UpdateUserAddressEventHandler.cs @@ -0,0 +1,21 @@ +using CMSMicroservice.Domain.Events; +using Microsoft.Extensions.Logging; + +namespace CMSMicroservice.Application.UserAddressCQ.EventHandlers; + +public class UpdateUserAddressEventHandler : INotificationHandler +{ + private readonly ILogger _logger; + + public UpdateUserAddressEventHandler(ILogger logger) + { + _logger = logger; + } + + public Task Handle(UpdateUserAddressEvent notification, CancellationToken cancellationToken) + { + _logger.LogInformation("Domain Event: {DomainEvent}", notification.GetType().Name); + + return Task.CompletedTask; + } +} diff --git a/src/CMSMicroservice.Application/UserAddressCQ/Queries/GetAllUserAddressByFilter/GetAllUserAddressByFilterQuery.cs b/src/CMSMicroservice.Application/UserAddressCQ/Queries/GetAllUserAddressByFilter/GetAllUserAddressByFilterQuery.cs new file mode 100644 index 0000000..fee4437 --- /dev/null +++ b/src/CMSMicroservice.Application/UserAddressCQ/Queries/GetAllUserAddressByFilter/GetAllUserAddressByFilterQuery.cs @@ -0,0 +1,27 @@ +namespace CMSMicroservice.Application.UserAddressCQ.Queries.GetAllUserAddressByFilter; +public record GetAllUserAddressByFilterQuery : IRequest +{ + //موقعیت صفحه بندی + public PaginationState? PaginationState { get; init; } + //مرتب سازی بر اساس + public string? SortBy { get; init; } + //فیلتر + public GetAllUserAddressByFilterFilter? Filter { get; init; } + +}public class GetAllUserAddressByFilterFilter +{ + //شناسه + public long? Id { get; set; } + //شناسه کاربر + public long? UserId { get; set; } + //عنوان + public string? Title { get; set; } + //آدرس + public string? Address { get; set; } + //کدپستی + public string? PostalCode { get; set; } + //پیشفرض؟ + public bool? IsDefault { get; set; } + //شناسه شهر + public long? CityId { get; set; } +} diff --git a/src/CMSMicroservice.Application/UserAddressCQ/Queries/GetAllUserAddressByFilter/GetAllUserAddressByFilterQueryHandler.cs b/src/CMSMicroservice.Application/UserAddressCQ/Queries/GetAllUserAddressByFilter/GetAllUserAddressByFilterQueryHandler.cs new file mode 100644 index 0000000..a304c8c --- /dev/null +++ b/src/CMSMicroservice.Application/UserAddressCQ/Queries/GetAllUserAddressByFilter/GetAllUserAddressByFilterQueryHandler.cs @@ -0,0 +1,36 @@ +namespace CMSMicroservice.Application.UserAddressCQ.Queries.GetAllUserAddressByFilter; +public class GetAllUserAddressByFilterQueryHandler : IRequestHandler +{ + private readonly IApplicationDbContext _context; + + public GetAllUserAddressByFilterQueryHandler(IApplicationDbContext context) + { + _context = context; + } + + public async Task Handle(GetAllUserAddressByFilterQuery request, CancellationToken cancellationToken) + { + var query = _context.UserAddresss + .ApplyOrder(sortBy: request.SortBy) + .AsNoTracking() + .AsQueryable(); + if (request.Filter is not null) + { + query = query + .Where(x => request.Filter.Id == null || x.Id == request.Filter.Id) + .Where(x => request.Filter.UserId == null || x.UserId == request.Filter.UserId) + .Where(x => request.Filter.Title == null || x.Title.Contains(request.Filter.Title)) + .Where(x => request.Filter.Address == null || x.Address.Contains(request.Filter.Address)) + .Where(x => request.Filter.PostalCode == null || x.PostalCode.Contains(request.Filter.PostalCode)) + .Where(x => request.Filter.IsDefault == null || x.IsDefault == request.Filter.IsDefault) + .Where(x => request.Filter.CityId == null || x.CityId == request.Filter.CityId) +; + } + return new GetAllUserAddressByFilterResponseDto + { + MetaData = await query.GetMetaData(request.PaginationState, cancellationToken), + Models = await query.PaginatedListAsync(paginationState: request.PaginationState) + .ProjectToType().ToListAsync(cancellationToken) + }; + } +} diff --git a/src/CMSMicroservice.Application/UserAddressCQ/Queries/GetAllUserAddressByFilter/GetAllUserAddressByFilterQueryValidator.cs b/src/CMSMicroservice.Application/UserAddressCQ/Queries/GetAllUserAddressByFilter/GetAllUserAddressByFilterQueryValidator.cs new file mode 100644 index 0000000..3cc70fa --- /dev/null +++ b/src/CMSMicroservice.Application/UserAddressCQ/Queries/GetAllUserAddressByFilter/GetAllUserAddressByFilterQueryValidator.cs @@ -0,0 +1,14 @@ +namespace CMSMicroservice.Application.UserAddressCQ.Queries.GetAllUserAddressByFilter; +public class GetAllUserAddressByFilterQueryValidator : AbstractValidator +{ + public GetAllUserAddressByFilterQueryValidator() + { + } + public Func>> ValidateValue => async (model, propertyName) => + { + var result = await ValidateAsync(ValidationContext.CreateWithOptions((GetAllUserAddressByFilterQuery)model, x => x.IncludeProperties(propertyName))); + if (result.IsValid) + return Array.Empty(); + return result.Errors.Select(e => e.ErrorMessage); + }; +} diff --git a/src/CMSMicroservice.Application/UserAddressCQ/Queries/GetAllUserAddressByFilter/GetAllUserAddressByFilterResponseDto.cs b/src/CMSMicroservice.Application/UserAddressCQ/Queries/GetAllUserAddressByFilter/GetAllUserAddressByFilterResponseDto.cs new file mode 100644 index 0000000..2f4653e --- /dev/null +++ b/src/CMSMicroservice.Application/UserAddressCQ/Queries/GetAllUserAddressByFilter/GetAllUserAddressByFilterResponseDto.cs @@ -0,0 +1,25 @@ +namespace CMSMicroservice.Application.UserAddressCQ.Queries.GetAllUserAddressByFilter; +public class GetAllUserAddressByFilterResponseDto +{ + //متادیتا + public MetaData MetaData { get; set; } + //مدل خروجی + public List? Models { get; set; } + +}public class GetAllUserAddressByFilterResponseModel +{ + //شناسه + public long Id { get; set; } + //شناسه کاربر + public long UserId { get; set; } + //عنوان + public string Title { get; set; } + //آدرس + public string Address { get; set; } + //کدپستی + public string PostalCode { get; set; } + //پیشفرض؟ + public bool IsDefault { get; set; } + //شناسه شهر + public long CityId { get; set; } +} diff --git a/src/CMSMicroservice.Application/UserAddressCQ/Queries/GetUserAddress/GetUserAddressQuery.cs b/src/CMSMicroservice.Application/UserAddressCQ/Queries/GetUserAddress/GetUserAddressQuery.cs new file mode 100644 index 0000000..194cd5b --- /dev/null +++ b/src/CMSMicroservice.Application/UserAddressCQ/Queries/GetUserAddress/GetUserAddressQuery.cs @@ -0,0 +1,7 @@ +namespace CMSMicroservice.Application.UserAddressCQ.Queries.GetUserAddress; +public record GetUserAddressQuery : IRequest +{ + //شناسه + public long Id { get; init; } + +} \ No newline at end of file diff --git a/src/CMSMicroservice.Application/UserAddressCQ/Queries/GetUserAddress/GetUserAddressQueryHandler.cs b/src/CMSMicroservice.Application/UserAddressCQ/Queries/GetUserAddress/GetUserAddressQueryHandler.cs new file mode 100644 index 0000000..4147345 --- /dev/null +++ b/src/CMSMicroservice.Application/UserAddressCQ/Queries/GetUserAddress/GetUserAddressQueryHandler.cs @@ -0,0 +1,22 @@ +namespace CMSMicroservice.Application.UserAddressCQ.Queries.GetUserAddress; +public class GetUserAddressQueryHandler : IRequestHandler +{ + private readonly IApplicationDbContext _context; + + public GetUserAddressQueryHandler(IApplicationDbContext context) + { + _context = context; + } + + public async Task Handle(GetUserAddressQuery request, + CancellationToken cancellationToken) + { + var response = await _context.UserAddresss + .AsNoTracking() + .Where(x => x.Id == request.Id) + .ProjectToType() + .FirstOrDefaultAsync(cancellationToken); + + return response ?? throw new NotFoundException(nameof(UserAddress), request.Id); + } +} diff --git a/src/CMSMicroservice.Application/UserAddressCQ/Queries/GetUserAddress/GetUserAddressQueryValidator.cs b/src/CMSMicroservice.Application/UserAddressCQ/Queries/GetUserAddress/GetUserAddressQueryValidator.cs new file mode 100644 index 0000000..70cfa3d --- /dev/null +++ b/src/CMSMicroservice.Application/UserAddressCQ/Queries/GetUserAddress/GetUserAddressQueryValidator.cs @@ -0,0 +1,16 @@ +namespace CMSMicroservice.Application.UserAddressCQ.Queries.GetUserAddress; +public class GetUserAddressQueryValidator : AbstractValidator +{ + public GetUserAddressQueryValidator() + { + RuleFor(model => model.Id) + .NotNull(); + } + public Func>> ValidateValue => async (model, propertyName) => + { + var result = await ValidateAsync(ValidationContext.CreateWithOptions((GetUserAddressQuery)model, x => x.IncludeProperties(propertyName))); + if (result.IsValid) + return Array.Empty(); + return result.Errors.Select(e => e.ErrorMessage); + }; +} diff --git a/src/CMSMicroservice.Application/UserAddressCQ/Queries/GetUserAddress/GetUserAddressResponseDto.cs b/src/CMSMicroservice.Application/UserAddressCQ/Queries/GetUserAddress/GetUserAddressResponseDto.cs new file mode 100644 index 0000000..b05fce2 --- /dev/null +++ b/src/CMSMicroservice.Application/UserAddressCQ/Queries/GetUserAddress/GetUserAddressResponseDto.cs @@ -0,0 +1,19 @@ +namespace CMSMicroservice.Application.UserAddressCQ.Queries.GetUserAddress; +public class GetUserAddressResponseDto +{ + //شناسه + public long Id { get; set; } + //شناسه کاربر + public long UserId { get; set; } + //عنوان + public string Title { get; set; } + //آدرس + public string Address { get; set; } + //کدپستی + public string PostalCode { get; set; } + //پیشفرض؟ + public bool IsDefault { get; set; } + //شناسه شهر + public long CityId { get; set; } + +} \ No newline at end of file diff --git a/src/CMSMicroservice.Application/UserCQ/Commands/CreateNewUser/CreateNewUserCommand.cs b/src/CMSMicroservice.Application/UserCQ/Commands/CreateNewUser/CreateNewUserCommand.cs new file mode 100644 index 0000000..ec02065 --- /dev/null +++ b/src/CMSMicroservice.Application/UserCQ/Commands/CreateNewUser/CreateNewUserCommand.cs @@ -0,0 +1,17 @@ +namespace CMSMicroservice.Application.UserCQ.Commands.CreateNewUser; +public record CreateNewUserCommand : IRequest +{ + //نام + public string? FirstName { get; init; } + //نام خانوادگی + public string? LastName { get; init; } + //شماره موبایل + public string Mobile { get; init; } + //کد ملی + public string? NationalCode { get; init; } + //آدرس آواتار + public string? AvatarPath { get; init; } + //شناسه والد + public long? ParentId { get; init; } + +} \ No newline at end of file diff --git a/src/CMSMicroservice.Application/UserCQ/Commands/CreateNewUser/CreateNewUserCommandHandler.cs b/src/CMSMicroservice.Application/UserCQ/Commands/CreateNewUser/CreateNewUserCommandHandler.cs new file mode 100644 index 0000000..12d2301 --- /dev/null +++ b/src/CMSMicroservice.Application/UserCQ/Commands/CreateNewUser/CreateNewUserCommandHandler.cs @@ -0,0 +1,21 @@ +using CMSMicroservice.Domain.Events; +namespace CMSMicroservice.Application.UserCQ.Commands.CreateNewUser; +public class CreateNewUserCommandHandler : IRequestHandler +{ + private readonly IApplicationDbContext _context; + + public CreateNewUserCommandHandler(IApplicationDbContext context) + { + _context = context; + } + + public async Task Handle(CreateNewUserCommand request, + CancellationToken cancellationToken) + { + var entity = request.Adapt(); + await _context.Users.AddAsync(entity, cancellationToken); + entity.AddDomainEvent(new CreateNewUserEvent(entity)); + await _context.SaveChangesAsync(cancellationToken); + return entity.Adapt(); + } +} diff --git a/src/CMSMicroservice.Application/UserCQ/Commands/CreateNewUser/CreateNewUserCommandValidator.cs b/src/CMSMicroservice.Application/UserCQ/Commands/CreateNewUser/CreateNewUserCommandValidator.cs new file mode 100644 index 0000000..1e42bfd --- /dev/null +++ b/src/CMSMicroservice.Application/UserCQ/Commands/CreateNewUser/CreateNewUserCommandValidator.cs @@ -0,0 +1,16 @@ +namespace CMSMicroservice.Application.UserCQ.Commands.CreateNewUser; +public class CreateNewUserCommandValidator : AbstractValidator +{ + public CreateNewUserCommandValidator() + { + RuleFor(model => model.Mobile) + .NotEmpty(); + } + public Func>> ValidateValue => async (model, propertyName) => + { + var result = await ValidateAsync(ValidationContext.CreateWithOptions((CreateNewUserCommand)model, x => x.IncludeProperties(propertyName))); + if (result.IsValid) + return Array.Empty(); + return result.Errors.Select(e => e.ErrorMessage); + }; +} diff --git a/src/CMSMicroservice.Application/UserCQ/Commands/CreateNewUser/CreateNewUserResponseDto.cs b/src/CMSMicroservice.Application/UserCQ/Commands/CreateNewUser/CreateNewUserResponseDto.cs new file mode 100644 index 0000000..c17dbb5 --- /dev/null +++ b/src/CMSMicroservice.Application/UserCQ/Commands/CreateNewUser/CreateNewUserResponseDto.cs @@ -0,0 +1,7 @@ +namespace CMSMicroservice.Application.UserCQ.Commands.CreateNewUser; +public class CreateNewUserResponseDto +{ + //شناسه + public long Id { get; set; } + +} \ No newline at end of file diff --git a/src/CMSMicroservice.Application/UserCQ/Commands/DeleteUser/DeleteUserCommand.cs b/src/CMSMicroservice.Application/UserCQ/Commands/DeleteUser/DeleteUserCommand.cs new file mode 100644 index 0000000..18a77ff --- /dev/null +++ b/src/CMSMicroservice.Application/UserCQ/Commands/DeleteUser/DeleteUserCommand.cs @@ -0,0 +1,7 @@ +namespace CMSMicroservice.Application.UserCQ.Commands.DeleteUser; +public record DeleteUserCommand : IRequest +{ + //شناسه + public long Id { get; init; } + +} \ No newline at end of file diff --git a/src/CMSMicroservice.Application/UserCQ/Commands/DeleteUser/DeleteUserCommandHandler.cs b/src/CMSMicroservice.Application/UserCQ/Commands/DeleteUser/DeleteUserCommandHandler.cs new file mode 100644 index 0000000..34d7873 --- /dev/null +++ b/src/CMSMicroservice.Application/UserCQ/Commands/DeleteUser/DeleteUserCommandHandler.cs @@ -0,0 +1,22 @@ +using CMSMicroservice.Domain.Events; +namespace CMSMicroservice.Application.UserCQ.Commands.DeleteUser; +public class DeleteUserCommandHandler : IRequestHandler +{ + private readonly IApplicationDbContext _context; + + public DeleteUserCommandHandler(IApplicationDbContext context) + { + _context = context; + } + + public async Task Handle(DeleteUserCommand request, CancellationToken cancellationToken) + { + var entity = await _context.Users + .FirstOrDefaultAsync(x => x.Id == request.Id, cancellationToken) ?? throw new NotFoundException(nameof(User), request.Id); + entity.IsDeleted = true; + _context.Users.Update(entity); + entity.AddDomainEvent(new DeleteUserEvent(entity)); + await _context.SaveChangesAsync(cancellationToken); + return Unit.Value; + } +} diff --git a/src/CMSMicroservice.Application/UserCQ/Commands/DeleteUser/DeleteUserCommandValidator.cs b/src/CMSMicroservice.Application/UserCQ/Commands/DeleteUser/DeleteUserCommandValidator.cs new file mode 100644 index 0000000..8b104cb --- /dev/null +++ b/src/CMSMicroservice.Application/UserCQ/Commands/DeleteUser/DeleteUserCommandValidator.cs @@ -0,0 +1,16 @@ +namespace CMSMicroservice.Application.UserCQ.Commands.DeleteUser; +public class DeleteUserCommandValidator : AbstractValidator +{ + public DeleteUserCommandValidator() + { + RuleFor(model => model.Id) + .NotNull(); + } + public Func>> ValidateValue => async (model, propertyName) => + { + var result = await ValidateAsync(ValidationContext.CreateWithOptions((DeleteUserCommand)model, x => x.IncludeProperties(propertyName))); + if (result.IsValid) + return Array.Empty(); + return result.Errors.Select(e => e.ErrorMessage); + }; +} diff --git a/src/CMSMicroservice.Application/UserCQ/Commands/UpdateUser/UpdateUserCommand.cs b/src/CMSMicroservice.Application/UserCQ/Commands/UpdateUser/UpdateUserCommand.cs new file mode 100644 index 0000000..fa10886 --- /dev/null +++ b/src/CMSMicroservice.Application/UserCQ/Commands/UpdateUser/UpdateUserCommand.cs @@ -0,0 +1,19 @@ +namespace CMSMicroservice.Application.UserCQ.Commands.UpdateUser; +public record UpdateUserCommand : IRequest +{ + //شناسه + public long Id { get; init; } + //نام + public string? FirstName { get; init; } + //نام خانوادگی + public string? LastName { get; init; } + //شماره موبایل + public string Mobile { get; init; } + //کد ملی + public string? NationalCode { get; init; } + //آدرس آواتار + public string? AvatarPath { get; init; } + //شناسه والد + public long? ParentId { get; init; } + +} \ No newline at end of file diff --git a/src/CMSMicroservice.Application/UserCQ/Commands/UpdateUser/UpdateUserCommandHandler.cs b/src/CMSMicroservice.Application/UserCQ/Commands/UpdateUser/UpdateUserCommandHandler.cs new file mode 100644 index 0000000..93be70a --- /dev/null +++ b/src/CMSMicroservice.Application/UserCQ/Commands/UpdateUser/UpdateUserCommandHandler.cs @@ -0,0 +1,22 @@ +using CMSMicroservice.Domain.Events; +namespace CMSMicroservice.Application.UserCQ.Commands.UpdateUser; +public class UpdateUserCommandHandler : IRequestHandler +{ + private readonly IApplicationDbContext _context; + + public UpdateUserCommandHandler(IApplicationDbContext context) + { + _context = context; + } + + public async Task Handle(UpdateUserCommand request, CancellationToken cancellationToken) + { + var entity = await _context.Users + .FirstOrDefaultAsync(x => x.Id == request.Id, cancellationToken) ?? throw new NotFoundException(nameof(User), request.Id); + request.Adapt(entity); + _context.Users.Update(entity); + entity.AddDomainEvent(new UpdateUserEvent(entity)); + await _context.SaveChangesAsync(cancellationToken); + return Unit.Value; + } +} diff --git a/src/CMSMicroservice.Application/UserCQ/Commands/UpdateUser/UpdateUserCommandValidator.cs b/src/CMSMicroservice.Application/UserCQ/Commands/UpdateUser/UpdateUserCommandValidator.cs new file mode 100644 index 0000000..bc37700 --- /dev/null +++ b/src/CMSMicroservice.Application/UserCQ/Commands/UpdateUser/UpdateUserCommandValidator.cs @@ -0,0 +1,18 @@ +namespace CMSMicroservice.Application.UserCQ.Commands.UpdateUser; +public class UpdateUserCommandValidator : AbstractValidator +{ + public UpdateUserCommandValidator() + { + RuleFor(model => model.Id) + .NotNull(); + RuleFor(model => model.Mobile) + .NotEmpty(); + } + public Func>> ValidateValue => async (model, propertyName) => + { + var result = await ValidateAsync(ValidationContext.CreateWithOptions((UpdateUserCommand)model, x => x.IncludeProperties(propertyName))); + if (result.IsValid) + return Array.Empty(); + return result.Errors.Select(e => e.ErrorMessage); + }; +} diff --git a/src/CMSMicroservice.Application/UserCQ/EventHandlers/CreateNewUserEventHandlers/CreateNewUserEventHandler.cs b/src/CMSMicroservice.Application/UserCQ/EventHandlers/CreateNewUserEventHandlers/CreateNewUserEventHandler.cs new file mode 100644 index 0000000..a027413 --- /dev/null +++ b/src/CMSMicroservice.Application/UserCQ/EventHandlers/CreateNewUserEventHandlers/CreateNewUserEventHandler.cs @@ -0,0 +1,21 @@ +using CMSMicroservice.Domain.Events; +using Microsoft.Extensions.Logging; + +namespace CMSMicroservice.Application.UserCQ.EventHandlers; + +public class CreateNewUserEventHandler : INotificationHandler +{ + private readonly ILogger _logger; + + public CreateNewUserEventHandler(ILogger logger) + { + _logger = logger; + } + + public Task Handle(CreateNewUserEvent notification, CancellationToken cancellationToken) + { + _logger.LogInformation("Domain Event: {DomainEvent}", notification.GetType().Name); + + return Task.CompletedTask; + } +} diff --git a/src/CMSMicroservice.Application/UserCQ/EventHandlers/DeleteUserEventHandlers/DeleteUserEventHandler.cs b/src/CMSMicroservice.Application/UserCQ/EventHandlers/DeleteUserEventHandlers/DeleteUserEventHandler.cs new file mode 100644 index 0000000..f604f93 --- /dev/null +++ b/src/CMSMicroservice.Application/UserCQ/EventHandlers/DeleteUserEventHandlers/DeleteUserEventHandler.cs @@ -0,0 +1,21 @@ +using CMSMicroservice.Domain.Events; +using Microsoft.Extensions.Logging; + +namespace CMSMicroservice.Application.UserCQ.EventHandlers; + +public class DeleteUserEventHandler : INotificationHandler +{ + private readonly ILogger _logger; + + public DeleteUserEventHandler(ILogger logger) + { + _logger = logger; + } + + public Task Handle(DeleteUserEvent notification, CancellationToken cancellationToken) + { + _logger.LogInformation("Domain Event: {DomainEvent}", notification.GetType().Name); + + return Task.CompletedTask; + } +} diff --git a/src/CMSMicroservice.Application/UserCQ/EventHandlers/UpdateUserEventHandlers/UpdateUserEventHandler.cs b/src/CMSMicroservice.Application/UserCQ/EventHandlers/UpdateUserEventHandlers/UpdateUserEventHandler.cs new file mode 100644 index 0000000..45714ae --- /dev/null +++ b/src/CMSMicroservice.Application/UserCQ/EventHandlers/UpdateUserEventHandlers/UpdateUserEventHandler.cs @@ -0,0 +1,21 @@ +using CMSMicroservice.Domain.Events; +using Microsoft.Extensions.Logging; + +namespace CMSMicroservice.Application.UserCQ.EventHandlers; + +public class UpdateUserEventHandler : INotificationHandler +{ + private readonly ILogger _logger; + + public UpdateUserEventHandler(ILogger logger) + { + _logger = logger; + } + + public Task Handle(UpdateUserEvent notification, CancellationToken cancellationToken) + { + _logger.LogInformation("Domain Event: {DomainEvent}", notification.GetType().Name); + + return Task.CompletedTask; + } +} diff --git a/src/CMSMicroservice.Application/UserCQ/Queries/GetAllUserByFilter/GetAllUserByFilterQuery.cs b/src/CMSMicroservice.Application/UserCQ/Queries/GetAllUserByFilter/GetAllUserByFilterQuery.cs new file mode 100644 index 0000000..12e601c --- /dev/null +++ b/src/CMSMicroservice.Application/UserCQ/Queries/GetAllUserByFilter/GetAllUserByFilterQuery.cs @@ -0,0 +1,27 @@ +namespace CMSMicroservice.Application.UserCQ.Queries.GetAllUserByFilter; +public record GetAllUserByFilterQuery : IRequest +{ + //موقعیت صفحه بندی + public PaginationState? PaginationState { get; init; } + //مرتب سازی بر اساس + public string? SortBy { get; init; } + //فیلتر + public GetAllUserByFilterFilter? Filter { get; init; } + +}public class GetAllUserByFilterFilter +{ + //شناسه + public long? Id { get; set; } + //نام + public string? FirstName { get; set; } + //نام خانوادگی + public string? LastName { get; set; } + //شماره موبایل + public string? Mobile { get; set; } + //کد ملی + public string? NationalCode { get; set; } + //آدرس آواتار + public string? AvatarPath { get; set; } + //شناسه والد + public long? ParentId { get; set; } +} diff --git a/src/CMSMicroservice.Application/UserCQ/Queries/GetAllUserByFilter/GetAllUserByFilterQueryHandler.cs b/src/CMSMicroservice.Application/UserCQ/Queries/GetAllUserByFilter/GetAllUserByFilterQueryHandler.cs new file mode 100644 index 0000000..6e96911 --- /dev/null +++ b/src/CMSMicroservice.Application/UserCQ/Queries/GetAllUserByFilter/GetAllUserByFilterQueryHandler.cs @@ -0,0 +1,36 @@ +namespace CMSMicroservice.Application.UserCQ.Queries.GetAllUserByFilter; +public class GetAllUserByFilterQueryHandler : IRequestHandler +{ + private readonly IApplicationDbContext _context; + + public GetAllUserByFilterQueryHandler(IApplicationDbContext context) + { + _context = context; + } + + public async Task Handle(GetAllUserByFilterQuery request, CancellationToken cancellationToken) + { + var query = _context.Users + .ApplyOrder(sortBy: request.SortBy) + .AsNoTracking() + .AsQueryable(); + if (request.Filter is not null) + { + query = query + .Where(x => request.Filter.Id == null || x.Id == request.Filter.Id) + .Where(x => request.Filter.FirstName == null || x.FirstName.Contains(request.Filter.FirstName)) + .Where(x => request.Filter.LastName == null || x.LastName.Contains(request.Filter.LastName)) + .Where(x => request.Filter.Mobile == null || x.Mobile.Contains(request.Filter.Mobile)) + .Where(x => request.Filter.NationalCode == null || x.NationalCode.Contains(request.Filter.NationalCode)) + .Where(x => request.Filter.AvatarPath == null || x.AvatarPath.Contains(request.Filter.AvatarPath)) + .Where(x => request.Filter.ParentId == null || x.ParentId == request.Filter.ParentId) +; + } + return new GetAllUserByFilterResponseDto + { + MetaData = await query.GetMetaData(request.PaginationState, cancellationToken), + Models = await query.PaginatedListAsync(paginationState: request.PaginationState) + .ProjectToType().ToListAsync(cancellationToken) + }; + } +} diff --git a/src/CMSMicroservice.Application/UserCQ/Queries/GetAllUserByFilter/GetAllUserByFilterQueryValidator.cs b/src/CMSMicroservice.Application/UserCQ/Queries/GetAllUserByFilter/GetAllUserByFilterQueryValidator.cs new file mode 100644 index 0000000..153a639 --- /dev/null +++ b/src/CMSMicroservice.Application/UserCQ/Queries/GetAllUserByFilter/GetAllUserByFilterQueryValidator.cs @@ -0,0 +1,14 @@ +namespace CMSMicroservice.Application.UserCQ.Queries.GetAllUserByFilter; +public class GetAllUserByFilterQueryValidator : AbstractValidator +{ + public GetAllUserByFilterQueryValidator() + { + } + public Func>> ValidateValue => async (model, propertyName) => + { + var result = await ValidateAsync(ValidationContext.CreateWithOptions((GetAllUserByFilterQuery)model, x => x.IncludeProperties(propertyName))); + if (result.IsValid) + return Array.Empty(); + return result.Errors.Select(e => e.ErrorMessage); + }; +} diff --git a/src/CMSMicroservice.Application/UserCQ/Queries/GetAllUserByFilter/GetAllUserByFilterResponseDto.cs b/src/CMSMicroservice.Application/UserCQ/Queries/GetAllUserByFilter/GetAllUserByFilterResponseDto.cs new file mode 100644 index 0000000..1ae3fd3 --- /dev/null +++ b/src/CMSMicroservice.Application/UserCQ/Queries/GetAllUserByFilter/GetAllUserByFilterResponseDto.cs @@ -0,0 +1,25 @@ +namespace CMSMicroservice.Application.UserCQ.Queries.GetAllUserByFilter; +public class GetAllUserByFilterResponseDto +{ + //متادیتا + public MetaData MetaData { get; set; } + //مدل خروجی + public List? Models { get; set; } + +}public class GetAllUserByFilterResponseModel +{ + //شناسه + public long Id { get; set; } + //نام + public string? FirstName { get; set; } + //نام خانوادگی + public string? LastName { get; set; } + //شماره موبایل + public string Mobile { get; set; } + //کد ملی + public string? NationalCode { get; set; } + //آدرس آواتار + public string? AvatarPath { get; set; } + //شناسه والد + public long? ParentId { get; set; } +} diff --git a/src/CMSMicroservice.Application/UserCQ/Queries/GetUser/GetUserQuery.cs b/src/CMSMicroservice.Application/UserCQ/Queries/GetUser/GetUserQuery.cs new file mode 100644 index 0000000..5b202a6 --- /dev/null +++ b/src/CMSMicroservice.Application/UserCQ/Queries/GetUser/GetUserQuery.cs @@ -0,0 +1,7 @@ +namespace CMSMicroservice.Application.UserCQ.Queries.GetUser; +public record GetUserQuery : IRequest +{ + //شناسه + public long Id { get; init; } + +} \ No newline at end of file diff --git a/src/CMSMicroservice.Application/UserCQ/Queries/GetUser/GetUserQueryHandler.cs b/src/CMSMicroservice.Application/UserCQ/Queries/GetUser/GetUserQueryHandler.cs new file mode 100644 index 0000000..2e895b6 --- /dev/null +++ b/src/CMSMicroservice.Application/UserCQ/Queries/GetUser/GetUserQueryHandler.cs @@ -0,0 +1,22 @@ +namespace CMSMicroservice.Application.UserCQ.Queries.GetUser; +public class GetUserQueryHandler : IRequestHandler +{ + private readonly IApplicationDbContext _context; + + public GetUserQueryHandler(IApplicationDbContext context) + { + _context = context; + } + + public async Task Handle(GetUserQuery request, + CancellationToken cancellationToken) + { + var response = await _context.Users + .AsNoTracking() + .Where(x => x.Id == request.Id) + .ProjectToType() + .FirstOrDefaultAsync(cancellationToken); + + return response ?? throw new NotFoundException(nameof(User), request.Id); + } +} diff --git a/src/CMSMicroservice.Application/UserCQ/Queries/GetUser/GetUserQueryValidator.cs b/src/CMSMicroservice.Application/UserCQ/Queries/GetUser/GetUserQueryValidator.cs new file mode 100644 index 0000000..0d9cd77 --- /dev/null +++ b/src/CMSMicroservice.Application/UserCQ/Queries/GetUser/GetUserQueryValidator.cs @@ -0,0 +1,16 @@ +namespace CMSMicroservice.Application.UserCQ.Queries.GetUser; +public class GetUserQueryValidator : AbstractValidator +{ + public GetUserQueryValidator() + { + RuleFor(model => model.Id) + .NotNull(); + } + public Func>> ValidateValue => async (model, propertyName) => + { + var result = await ValidateAsync(ValidationContext.CreateWithOptions((GetUserQuery)model, x => x.IncludeProperties(propertyName))); + if (result.IsValid) + return Array.Empty(); + return result.Errors.Select(e => e.ErrorMessage); + }; +} diff --git a/src/CMSMicroservice.Application/UserCQ/Queries/GetUser/GetUserResponseDto.cs b/src/CMSMicroservice.Application/UserCQ/Queries/GetUser/GetUserResponseDto.cs new file mode 100644 index 0000000..df3f6c0 --- /dev/null +++ b/src/CMSMicroservice.Application/UserCQ/Queries/GetUser/GetUserResponseDto.cs @@ -0,0 +1,19 @@ +namespace CMSMicroservice.Application.UserCQ.Queries.GetUser; +public class GetUserResponseDto +{ + //شناسه + public long Id { get; set; } + //نام + public string? FirstName { get; set; } + //نام خانوادگی + public string? LastName { get; set; } + //شماره موبایل + public string Mobile { get; set; } + //کد ملی + public string? NationalCode { get; set; } + //آدرس آواتار + public string? AvatarPath { get; set; } + //شناسه والد + public long? ParentId { get; set; } + +} \ No newline at end of file diff --git a/src/CMSMicroservice.Application/UserOrderCQ/Commands/CreateNewUserOrder/CreateNewUserOrderCommand.cs b/src/CMSMicroservice.Application/UserOrderCQ/Commands/CreateNewUserOrder/CreateNewUserOrderCommand.cs new file mode 100644 index 0000000..7d96144 --- /dev/null +++ b/src/CMSMicroservice.Application/UserOrderCQ/Commands/CreateNewUserOrder/CreateNewUserOrderCommand.cs @@ -0,0 +1,17 @@ +namespace CMSMicroservice.Application.UserOrderCQ.Commands.CreateNewUserOrder; +public record CreateNewUserOrderCommand : IRequest +{ + //قیمت + public long Price { get; init; } + //شناسه پکیج + public long PackageId { get; init; } + //شناسه تراکنش + public long? TransactionId { get; init; } + //وضعیت پرداخت + public bool PaymentStatus { get; init; } + //تاریخ پرداخت + public DateTime? PaymentDate { get; init; } + //شناسه کاربر + public long UserId { get; init; } + +} \ No newline at end of file diff --git a/src/CMSMicroservice.Application/UserOrderCQ/Commands/CreateNewUserOrder/CreateNewUserOrderCommandHandler.cs b/src/CMSMicroservice.Application/UserOrderCQ/Commands/CreateNewUserOrder/CreateNewUserOrderCommandHandler.cs new file mode 100644 index 0000000..3289faf --- /dev/null +++ b/src/CMSMicroservice.Application/UserOrderCQ/Commands/CreateNewUserOrder/CreateNewUserOrderCommandHandler.cs @@ -0,0 +1,21 @@ +using CMSMicroservice.Domain.Events; +namespace CMSMicroservice.Application.UserOrderCQ.Commands.CreateNewUserOrder; +public class CreateNewUserOrderCommandHandler : IRequestHandler +{ + private readonly IApplicationDbContext _context; + + public CreateNewUserOrderCommandHandler(IApplicationDbContext context) + { + _context = context; + } + + public async Task Handle(CreateNewUserOrderCommand request, + CancellationToken cancellationToken) + { + var entity = request.Adapt(); + await _context.UserOrders.AddAsync(entity, cancellationToken); + entity.AddDomainEvent(new CreateNewUserOrderEvent(entity)); + await _context.SaveChangesAsync(cancellationToken); + return entity.Adapt(); + } +} diff --git a/src/CMSMicroservice.Application/UserOrderCQ/Commands/CreateNewUserOrder/CreateNewUserOrderCommandValidator.cs b/src/CMSMicroservice.Application/UserOrderCQ/Commands/CreateNewUserOrder/CreateNewUserOrderCommandValidator.cs new file mode 100644 index 0000000..27103b9 --- /dev/null +++ b/src/CMSMicroservice.Application/UserOrderCQ/Commands/CreateNewUserOrder/CreateNewUserOrderCommandValidator.cs @@ -0,0 +1,22 @@ +namespace CMSMicroservice.Application.UserOrderCQ.Commands.CreateNewUserOrder; +public class CreateNewUserOrderCommandValidator : AbstractValidator +{ + public CreateNewUserOrderCommandValidator() + { + RuleFor(model => model.Price) + .NotNull(); + RuleFor(model => model.PackageId) + .NotNull(); + RuleFor(model => model.PaymentStatus) + .NotNull(); + RuleFor(model => model.UserId) + .NotNull(); + } + public Func>> ValidateValue => async (model, propertyName) => + { + var result = await ValidateAsync(ValidationContext.CreateWithOptions((CreateNewUserOrderCommand)model, x => x.IncludeProperties(propertyName))); + if (result.IsValid) + return Array.Empty(); + return result.Errors.Select(e => e.ErrorMessage); + }; +} diff --git a/src/CMSMicroservice.Application/UserOrderCQ/Commands/CreateNewUserOrder/CreateNewUserOrderResponseDto.cs b/src/CMSMicroservice.Application/UserOrderCQ/Commands/CreateNewUserOrder/CreateNewUserOrderResponseDto.cs new file mode 100644 index 0000000..997db65 --- /dev/null +++ b/src/CMSMicroservice.Application/UserOrderCQ/Commands/CreateNewUserOrder/CreateNewUserOrderResponseDto.cs @@ -0,0 +1,7 @@ +namespace CMSMicroservice.Application.UserOrderCQ.Commands.CreateNewUserOrder; +public class CreateNewUserOrderResponseDto +{ + //شناسه + public long Id { get; set; } + +} \ No newline at end of file diff --git a/src/CMSMicroservice.Application/UserOrderCQ/Commands/DeleteUserOrder/DeleteUserOrderCommand.cs b/src/CMSMicroservice.Application/UserOrderCQ/Commands/DeleteUserOrder/DeleteUserOrderCommand.cs new file mode 100644 index 0000000..eea3fa2 --- /dev/null +++ b/src/CMSMicroservice.Application/UserOrderCQ/Commands/DeleteUserOrder/DeleteUserOrderCommand.cs @@ -0,0 +1,7 @@ +namespace CMSMicroservice.Application.UserOrderCQ.Commands.DeleteUserOrder; +public record DeleteUserOrderCommand : IRequest +{ + //شناسه + public long Id { get; init; } + +} \ No newline at end of file diff --git a/src/CMSMicroservice.Application/UserOrderCQ/Commands/DeleteUserOrder/DeleteUserOrderCommandHandler.cs b/src/CMSMicroservice.Application/UserOrderCQ/Commands/DeleteUserOrder/DeleteUserOrderCommandHandler.cs new file mode 100644 index 0000000..d07061b --- /dev/null +++ b/src/CMSMicroservice.Application/UserOrderCQ/Commands/DeleteUserOrder/DeleteUserOrderCommandHandler.cs @@ -0,0 +1,22 @@ +using CMSMicroservice.Domain.Events; +namespace CMSMicroservice.Application.UserOrderCQ.Commands.DeleteUserOrder; +public class DeleteUserOrderCommandHandler : IRequestHandler +{ + private readonly IApplicationDbContext _context; + + public DeleteUserOrderCommandHandler(IApplicationDbContext context) + { + _context = context; + } + + public async Task Handle(DeleteUserOrderCommand request, CancellationToken cancellationToken) + { + var entity = await _context.UserOrders + .FirstOrDefaultAsync(x => x.Id == request.Id, cancellationToken) ?? throw new NotFoundException(nameof(UserOrder), request.Id); + entity.IsDeleted = true; + _context.UserOrders.Update(entity); + entity.AddDomainEvent(new DeleteUserOrderEvent(entity)); + await _context.SaveChangesAsync(cancellationToken); + return Unit.Value; + } +} diff --git a/src/CMSMicroservice.Application/UserOrderCQ/Commands/DeleteUserOrder/DeleteUserOrderCommandValidator.cs b/src/CMSMicroservice.Application/UserOrderCQ/Commands/DeleteUserOrder/DeleteUserOrderCommandValidator.cs new file mode 100644 index 0000000..0942569 --- /dev/null +++ b/src/CMSMicroservice.Application/UserOrderCQ/Commands/DeleteUserOrder/DeleteUserOrderCommandValidator.cs @@ -0,0 +1,16 @@ +namespace CMSMicroservice.Application.UserOrderCQ.Commands.DeleteUserOrder; +public class DeleteUserOrderCommandValidator : AbstractValidator +{ + public DeleteUserOrderCommandValidator() + { + RuleFor(model => model.Id) + .NotNull(); + } + public Func>> ValidateValue => async (model, propertyName) => + { + var result = await ValidateAsync(ValidationContext.CreateWithOptions((DeleteUserOrderCommand)model, x => x.IncludeProperties(propertyName))); + if (result.IsValid) + return Array.Empty(); + return result.Errors.Select(e => e.ErrorMessage); + }; +} diff --git a/src/CMSMicroservice.Application/UserOrderCQ/Commands/UpdateUserOrder/UpdateUserOrderCommand.cs b/src/CMSMicroservice.Application/UserOrderCQ/Commands/UpdateUserOrder/UpdateUserOrderCommand.cs new file mode 100644 index 0000000..c73120d --- /dev/null +++ b/src/CMSMicroservice.Application/UserOrderCQ/Commands/UpdateUserOrder/UpdateUserOrderCommand.cs @@ -0,0 +1,19 @@ +namespace CMSMicroservice.Application.UserOrderCQ.Commands.UpdateUserOrder; +public record UpdateUserOrderCommand : IRequest +{ + //شناسه + public long Id { get; init; } + //قیمت + public long Price { get; init; } + //شناسه پکیج + public long PackageId { get; init; } + //شناسه تراکنش + public long? TransactionId { get; init; } + //وضعیت پرداخت + public bool PaymentStatus { get; init; } + //تاریخ پرداخت + public DateTime? PaymentDate { get; init; } + //شناسه کاربر + public long UserId { get; init; } + +} \ No newline at end of file diff --git a/src/CMSMicroservice.Application/UserOrderCQ/Commands/UpdateUserOrder/UpdateUserOrderCommandHandler.cs b/src/CMSMicroservice.Application/UserOrderCQ/Commands/UpdateUserOrder/UpdateUserOrderCommandHandler.cs new file mode 100644 index 0000000..35407d3 --- /dev/null +++ b/src/CMSMicroservice.Application/UserOrderCQ/Commands/UpdateUserOrder/UpdateUserOrderCommandHandler.cs @@ -0,0 +1,22 @@ +using CMSMicroservice.Domain.Events; +namespace CMSMicroservice.Application.UserOrderCQ.Commands.UpdateUserOrder; +public class UpdateUserOrderCommandHandler : IRequestHandler +{ + private readonly IApplicationDbContext _context; + + public UpdateUserOrderCommandHandler(IApplicationDbContext context) + { + _context = context; + } + + public async Task Handle(UpdateUserOrderCommand request, CancellationToken cancellationToken) + { + var entity = await _context.UserOrders + .FirstOrDefaultAsync(x => x.Id == request.Id, cancellationToken) ?? throw new NotFoundException(nameof(UserOrder), request.Id); + request.Adapt(entity); + _context.UserOrders.Update(entity); + entity.AddDomainEvent(new UpdateUserOrderEvent(entity)); + await _context.SaveChangesAsync(cancellationToken); + return Unit.Value; + } +} diff --git a/src/CMSMicroservice.Application/UserOrderCQ/Commands/UpdateUserOrder/UpdateUserOrderCommandValidator.cs b/src/CMSMicroservice.Application/UserOrderCQ/Commands/UpdateUserOrder/UpdateUserOrderCommandValidator.cs new file mode 100644 index 0000000..1ae70e7 --- /dev/null +++ b/src/CMSMicroservice.Application/UserOrderCQ/Commands/UpdateUserOrder/UpdateUserOrderCommandValidator.cs @@ -0,0 +1,24 @@ +namespace CMSMicroservice.Application.UserOrderCQ.Commands.UpdateUserOrder; +public class UpdateUserOrderCommandValidator : AbstractValidator +{ + public UpdateUserOrderCommandValidator() + { + RuleFor(model => model.Id) + .NotNull(); + RuleFor(model => model.Price) + .NotNull(); + RuleFor(model => model.PackageId) + .NotNull(); + RuleFor(model => model.PaymentStatus) + .NotNull(); + RuleFor(model => model.UserId) + .NotNull(); + } + public Func>> ValidateValue => async (model, propertyName) => + { + var result = await ValidateAsync(ValidationContext.CreateWithOptions((UpdateUserOrderCommand)model, x => x.IncludeProperties(propertyName))); + if (result.IsValid) + return Array.Empty(); + return result.Errors.Select(e => e.ErrorMessage); + }; +} diff --git a/src/CMSMicroservice.Application/UserOrderCQ/EventHandlers/CreateNewUserOrderEventHandlers/CreateNewUserOrderEventHandler.cs b/src/CMSMicroservice.Application/UserOrderCQ/EventHandlers/CreateNewUserOrderEventHandlers/CreateNewUserOrderEventHandler.cs new file mode 100644 index 0000000..0c7d157 --- /dev/null +++ b/src/CMSMicroservice.Application/UserOrderCQ/EventHandlers/CreateNewUserOrderEventHandlers/CreateNewUserOrderEventHandler.cs @@ -0,0 +1,21 @@ +using CMSMicroservice.Domain.Events; +using Microsoft.Extensions.Logging; + +namespace CMSMicroservice.Application.UserOrderCQ.EventHandlers; + +public class CreateNewUserOrderEventHandler : INotificationHandler +{ + private readonly ILogger _logger; + + public CreateNewUserOrderEventHandler(ILogger logger) + { + _logger = logger; + } + + public Task Handle(CreateNewUserOrderEvent notification, CancellationToken cancellationToken) + { + _logger.LogInformation("Domain Event: {DomainEvent}", notification.GetType().Name); + + return Task.CompletedTask; + } +} diff --git a/src/CMSMicroservice.Application/UserOrderCQ/EventHandlers/DeleteUserOrderEventHandlers/DeleteUserOrderEventHandler.cs b/src/CMSMicroservice.Application/UserOrderCQ/EventHandlers/DeleteUserOrderEventHandlers/DeleteUserOrderEventHandler.cs new file mode 100644 index 0000000..1e204cb --- /dev/null +++ b/src/CMSMicroservice.Application/UserOrderCQ/EventHandlers/DeleteUserOrderEventHandlers/DeleteUserOrderEventHandler.cs @@ -0,0 +1,21 @@ +using CMSMicroservice.Domain.Events; +using Microsoft.Extensions.Logging; + +namespace CMSMicroservice.Application.UserOrderCQ.EventHandlers; + +public class DeleteUserOrderEventHandler : INotificationHandler +{ + private readonly ILogger _logger; + + public DeleteUserOrderEventHandler(ILogger logger) + { + _logger = logger; + } + + public Task Handle(DeleteUserOrderEvent notification, CancellationToken cancellationToken) + { + _logger.LogInformation("Domain Event: {DomainEvent}", notification.GetType().Name); + + return Task.CompletedTask; + } +} diff --git a/src/CMSMicroservice.Application/UserOrderCQ/EventHandlers/UpdateUserOrderEventHandlers/UpdateUserOrderEventHandler.cs b/src/CMSMicroservice.Application/UserOrderCQ/EventHandlers/UpdateUserOrderEventHandlers/UpdateUserOrderEventHandler.cs new file mode 100644 index 0000000..f965c31 --- /dev/null +++ b/src/CMSMicroservice.Application/UserOrderCQ/EventHandlers/UpdateUserOrderEventHandlers/UpdateUserOrderEventHandler.cs @@ -0,0 +1,21 @@ +using CMSMicroservice.Domain.Events; +using Microsoft.Extensions.Logging; + +namespace CMSMicroservice.Application.UserOrderCQ.EventHandlers; + +public class UpdateUserOrderEventHandler : INotificationHandler +{ + private readonly ILogger _logger; + + public UpdateUserOrderEventHandler(ILogger logger) + { + _logger = logger; + } + + public Task Handle(UpdateUserOrderEvent notification, CancellationToken cancellationToken) + { + _logger.LogInformation("Domain Event: {DomainEvent}", notification.GetType().Name); + + return Task.CompletedTask; + } +} diff --git a/src/CMSMicroservice.Application/UserOrderCQ/Queries/GetAllUserOrderByFilter/GetAllUserOrderByFilterQuery.cs b/src/CMSMicroservice.Application/UserOrderCQ/Queries/GetAllUserOrderByFilter/GetAllUserOrderByFilterQuery.cs new file mode 100644 index 0000000..f3372b0 --- /dev/null +++ b/src/CMSMicroservice.Application/UserOrderCQ/Queries/GetAllUserOrderByFilter/GetAllUserOrderByFilterQuery.cs @@ -0,0 +1,27 @@ +namespace CMSMicroservice.Application.UserOrderCQ.Queries.GetAllUserOrderByFilter; +public record GetAllUserOrderByFilterQuery : IRequest +{ + //موقعیت صفحه بندی + public PaginationState? PaginationState { get; init; } + //مرتب سازی بر اساس + public string? SortBy { get; init; } + //فیلتر + public GetAllUserOrderByFilterFilter? Filter { get; init; } + +}public class GetAllUserOrderByFilterFilter +{ + //شناسه + public long? Id { get; set; } + //قیمت + public long? Price { get; set; } + //شناسه پکیج + public long? PackageId { get; set; } + //شناسه تراکنش + public long? TransactionId { get; set; } + //وضعیت پرداخت + public bool? PaymentStatus { get; set; } + //تاریخ پرداخت + public DateTime? PaymentDate { get; set; } + //شناسه کاربر + public long? UserId { get; set; } +} diff --git a/src/CMSMicroservice.Application/UserOrderCQ/Queries/GetAllUserOrderByFilter/GetAllUserOrderByFilterQueryHandler.cs b/src/CMSMicroservice.Application/UserOrderCQ/Queries/GetAllUserOrderByFilter/GetAllUserOrderByFilterQueryHandler.cs new file mode 100644 index 0000000..cefb0d3 --- /dev/null +++ b/src/CMSMicroservice.Application/UserOrderCQ/Queries/GetAllUserOrderByFilter/GetAllUserOrderByFilterQueryHandler.cs @@ -0,0 +1,36 @@ +namespace CMSMicroservice.Application.UserOrderCQ.Queries.GetAllUserOrderByFilter; +public class GetAllUserOrderByFilterQueryHandler : IRequestHandler +{ + private readonly IApplicationDbContext _context; + + public GetAllUserOrderByFilterQueryHandler(IApplicationDbContext context) + { + _context = context; + } + + public async Task Handle(GetAllUserOrderByFilterQuery request, CancellationToken cancellationToken) + { + var query = _context.UserOrders + .ApplyOrder(sortBy: request.SortBy) + .AsNoTracking() + .AsQueryable(); + if (request.Filter is not null) + { + query = query + .Where(x => request.Filter.Id == null || x.Id == request.Filter.Id) + .Where(x => request.Filter.Price == null || x.Price == request.Filter.Price) + .Where(x => request.Filter.PackageId == null || x.PackageId == request.Filter.PackageId) + .Where(x => request.Filter.TransactionId == null || x.TransactionId == request.Filter.TransactionId) + .Where(x => request.Filter.PaymentStatus == null || x.PaymentStatus == request.Filter.PaymentStatus) + .Where(x => request.Filter.PaymentDate == null || x.PaymentDate == request.Filter.PaymentDate) + .Where(x => request.Filter.UserId == null || x.UserId == request.Filter.UserId) +; + } + return new GetAllUserOrderByFilterResponseDto + { + MetaData = await query.GetMetaData(request.PaginationState, cancellationToken), + Models = await query.PaginatedListAsync(paginationState: request.PaginationState) + .ProjectToType().ToListAsync(cancellationToken) + }; + } +} diff --git a/src/CMSMicroservice.Application/UserOrderCQ/Queries/GetAllUserOrderByFilter/GetAllUserOrderByFilterQueryValidator.cs b/src/CMSMicroservice.Application/UserOrderCQ/Queries/GetAllUserOrderByFilter/GetAllUserOrderByFilterQueryValidator.cs new file mode 100644 index 0000000..e25cf25 --- /dev/null +++ b/src/CMSMicroservice.Application/UserOrderCQ/Queries/GetAllUserOrderByFilter/GetAllUserOrderByFilterQueryValidator.cs @@ -0,0 +1,14 @@ +namespace CMSMicroservice.Application.UserOrderCQ.Queries.GetAllUserOrderByFilter; +public class GetAllUserOrderByFilterQueryValidator : AbstractValidator +{ + public GetAllUserOrderByFilterQueryValidator() + { + } + public Func>> ValidateValue => async (model, propertyName) => + { + var result = await ValidateAsync(ValidationContext.CreateWithOptions((GetAllUserOrderByFilterQuery)model, x => x.IncludeProperties(propertyName))); + if (result.IsValid) + return Array.Empty(); + return result.Errors.Select(e => e.ErrorMessage); + }; +} diff --git a/src/CMSMicroservice.Application/UserOrderCQ/Queries/GetAllUserOrderByFilter/GetAllUserOrderByFilterResponseDto.cs b/src/CMSMicroservice.Application/UserOrderCQ/Queries/GetAllUserOrderByFilter/GetAllUserOrderByFilterResponseDto.cs new file mode 100644 index 0000000..fa7f9f4 --- /dev/null +++ b/src/CMSMicroservice.Application/UserOrderCQ/Queries/GetAllUserOrderByFilter/GetAllUserOrderByFilterResponseDto.cs @@ -0,0 +1,25 @@ +namespace CMSMicroservice.Application.UserOrderCQ.Queries.GetAllUserOrderByFilter; +public class GetAllUserOrderByFilterResponseDto +{ + //متادیتا + public MetaData MetaData { get; set; } + //مدل خروجی + public List? Models { get; set; } + +}public class GetAllUserOrderByFilterResponseModel +{ + //شناسه + public long Id { get; set; } + //قیمت + public long Price { get; set; } + //شناسه پکیج + public long PackageId { get; set; } + //شناسه تراکنش + public long? TransactionId { get; set; } + //وضعیت پرداخت + public bool PaymentStatus { get; set; } + //تاریخ پرداخت + public DateTime? PaymentDate { get; set; } + //شناسه کاربر + public long UserId { get; set; } +} diff --git a/src/CMSMicroservice.Application/UserOrderCQ/Queries/GetUserOrder/GetUserOrderQuery.cs b/src/CMSMicroservice.Application/UserOrderCQ/Queries/GetUserOrder/GetUserOrderQuery.cs new file mode 100644 index 0000000..e605e34 --- /dev/null +++ b/src/CMSMicroservice.Application/UserOrderCQ/Queries/GetUserOrder/GetUserOrderQuery.cs @@ -0,0 +1,7 @@ +namespace CMSMicroservice.Application.UserOrderCQ.Queries.GetUserOrder; +public record GetUserOrderQuery : IRequest +{ + //شناسه + public long Id { get; init; } + +} \ No newline at end of file diff --git a/src/CMSMicroservice.Application/UserOrderCQ/Queries/GetUserOrder/GetUserOrderQueryHandler.cs b/src/CMSMicroservice.Application/UserOrderCQ/Queries/GetUserOrder/GetUserOrderQueryHandler.cs new file mode 100644 index 0000000..ef029d9 --- /dev/null +++ b/src/CMSMicroservice.Application/UserOrderCQ/Queries/GetUserOrder/GetUserOrderQueryHandler.cs @@ -0,0 +1,22 @@ +namespace CMSMicroservice.Application.UserOrderCQ.Queries.GetUserOrder; +public class GetUserOrderQueryHandler : IRequestHandler +{ + private readonly IApplicationDbContext _context; + + public GetUserOrderQueryHandler(IApplicationDbContext context) + { + _context = context; + } + + public async Task Handle(GetUserOrderQuery request, + CancellationToken cancellationToken) + { + var response = await _context.UserOrders + .AsNoTracking() + .Where(x => x.Id == request.Id) + .ProjectToType() + .FirstOrDefaultAsync(cancellationToken); + + return response ?? throw new NotFoundException(nameof(UserOrder), request.Id); + } +} diff --git a/src/CMSMicroservice.Application/UserOrderCQ/Queries/GetUserOrder/GetUserOrderQueryValidator.cs b/src/CMSMicroservice.Application/UserOrderCQ/Queries/GetUserOrder/GetUserOrderQueryValidator.cs new file mode 100644 index 0000000..4f6d6f2 --- /dev/null +++ b/src/CMSMicroservice.Application/UserOrderCQ/Queries/GetUserOrder/GetUserOrderQueryValidator.cs @@ -0,0 +1,16 @@ +namespace CMSMicroservice.Application.UserOrderCQ.Queries.GetUserOrder; +public class GetUserOrderQueryValidator : AbstractValidator +{ + public GetUserOrderQueryValidator() + { + RuleFor(model => model.Id) + .NotNull(); + } + public Func>> ValidateValue => async (model, propertyName) => + { + var result = await ValidateAsync(ValidationContext.CreateWithOptions((GetUserOrderQuery)model, x => x.IncludeProperties(propertyName))); + if (result.IsValid) + return Array.Empty(); + return result.Errors.Select(e => e.ErrorMessage); + }; +} diff --git a/src/CMSMicroservice.Application/UserOrderCQ/Queries/GetUserOrder/GetUserOrderResponseDto.cs b/src/CMSMicroservice.Application/UserOrderCQ/Queries/GetUserOrder/GetUserOrderResponseDto.cs new file mode 100644 index 0000000..ac05f8e --- /dev/null +++ b/src/CMSMicroservice.Application/UserOrderCQ/Queries/GetUserOrder/GetUserOrderResponseDto.cs @@ -0,0 +1,19 @@ +namespace CMSMicroservice.Application.UserOrderCQ.Queries.GetUserOrder; +public class GetUserOrderResponseDto +{ + //شناسه + public long Id { get; set; } + //قیمت + public long Price { get; set; } + //شناسه پکیج + public long PackageId { get; set; } + //شناسه تراکنش + public long? TransactionId { get; set; } + //وضعیت پرداخت + public bool PaymentStatus { get; set; } + //تاریخ پرداخت + public DateTime? PaymentDate { get; set; } + //شناسه کاربر + public long UserId { get; set; } + +} \ No newline at end of file diff --git a/src/CMSMicroservice.Application/UserRoleCQ/Commands/CreateNewUserRole/CreateNewUserRoleCommand.cs b/src/CMSMicroservice.Application/UserRoleCQ/Commands/CreateNewUserRole/CreateNewUserRoleCommand.cs new file mode 100644 index 0000000..4f326bd --- /dev/null +++ b/src/CMSMicroservice.Application/UserRoleCQ/Commands/CreateNewUserRole/CreateNewUserRoleCommand.cs @@ -0,0 +1,9 @@ +namespace CMSMicroservice.Application.UserRoleCQ.Commands.CreateNewUserRole; +public record CreateNewUserRoleCommand : IRequest +{ + //شناسه نقش + public long RoleId { get; init; } + //شناسه کاربر + public long UserId { get; init; } + +} \ No newline at end of file diff --git a/src/CMSMicroservice.Application/UserRoleCQ/Commands/CreateNewUserRole/CreateNewUserRoleCommandHandler.cs b/src/CMSMicroservice.Application/UserRoleCQ/Commands/CreateNewUserRole/CreateNewUserRoleCommandHandler.cs new file mode 100644 index 0000000..c37012e --- /dev/null +++ b/src/CMSMicroservice.Application/UserRoleCQ/Commands/CreateNewUserRole/CreateNewUserRoleCommandHandler.cs @@ -0,0 +1,21 @@ +using CMSMicroservice.Domain.Events; +namespace CMSMicroservice.Application.UserRoleCQ.Commands.CreateNewUserRole; +public class CreateNewUserRoleCommandHandler : IRequestHandler +{ + private readonly IApplicationDbContext _context; + + public CreateNewUserRoleCommandHandler(IApplicationDbContext context) + { + _context = context; + } + + public async Task Handle(CreateNewUserRoleCommand request, + CancellationToken cancellationToken) + { + var entity = request.Adapt(); + await _context.UserRoles.AddAsync(entity, cancellationToken); + entity.AddDomainEvent(new CreateNewUserRoleEvent(entity)); + await _context.SaveChangesAsync(cancellationToken); + return entity.Adapt(); + } +} diff --git a/src/CMSMicroservice.Application/UserRoleCQ/Commands/CreateNewUserRole/CreateNewUserRoleCommandValidator.cs b/src/CMSMicroservice.Application/UserRoleCQ/Commands/CreateNewUserRole/CreateNewUserRoleCommandValidator.cs new file mode 100644 index 0000000..700c25e --- /dev/null +++ b/src/CMSMicroservice.Application/UserRoleCQ/Commands/CreateNewUserRole/CreateNewUserRoleCommandValidator.cs @@ -0,0 +1,18 @@ +namespace CMSMicroservice.Application.UserRoleCQ.Commands.CreateNewUserRole; +public class CreateNewUserRoleCommandValidator : AbstractValidator +{ + public CreateNewUserRoleCommandValidator() + { + RuleFor(model => model.RoleId) + .NotNull(); + RuleFor(model => model.UserId) + .NotNull(); + } + public Func>> ValidateValue => async (model, propertyName) => + { + var result = await ValidateAsync(ValidationContext.CreateWithOptions((CreateNewUserRoleCommand)model, x => x.IncludeProperties(propertyName))); + if (result.IsValid) + return Array.Empty(); + return result.Errors.Select(e => e.ErrorMessage); + }; +} diff --git a/src/CMSMicroservice.Application/UserRoleCQ/Commands/CreateNewUserRole/CreateNewUserRoleResponseDto.cs b/src/CMSMicroservice.Application/UserRoleCQ/Commands/CreateNewUserRole/CreateNewUserRoleResponseDto.cs new file mode 100644 index 0000000..17af214 --- /dev/null +++ b/src/CMSMicroservice.Application/UserRoleCQ/Commands/CreateNewUserRole/CreateNewUserRoleResponseDto.cs @@ -0,0 +1,7 @@ +namespace CMSMicroservice.Application.UserRoleCQ.Commands.CreateNewUserRole; +public class CreateNewUserRoleResponseDto +{ + //شناسه + public long Id { get; set; } + +} \ No newline at end of file diff --git a/src/CMSMicroservice.Application/UserRoleCQ/Commands/DeleteUserRole/DeleteUserRoleCommand.cs b/src/CMSMicroservice.Application/UserRoleCQ/Commands/DeleteUserRole/DeleteUserRoleCommand.cs new file mode 100644 index 0000000..37363f0 --- /dev/null +++ b/src/CMSMicroservice.Application/UserRoleCQ/Commands/DeleteUserRole/DeleteUserRoleCommand.cs @@ -0,0 +1,7 @@ +namespace CMSMicroservice.Application.UserRoleCQ.Commands.DeleteUserRole; +public record DeleteUserRoleCommand : IRequest +{ + //شناسه + public long Id { get; init; } + +} \ No newline at end of file diff --git a/src/CMSMicroservice.Application/UserRoleCQ/Commands/DeleteUserRole/DeleteUserRoleCommandHandler.cs b/src/CMSMicroservice.Application/UserRoleCQ/Commands/DeleteUserRole/DeleteUserRoleCommandHandler.cs new file mode 100644 index 0000000..1783b29 --- /dev/null +++ b/src/CMSMicroservice.Application/UserRoleCQ/Commands/DeleteUserRole/DeleteUserRoleCommandHandler.cs @@ -0,0 +1,22 @@ +using CMSMicroservice.Domain.Events; +namespace CMSMicroservice.Application.UserRoleCQ.Commands.DeleteUserRole; +public class DeleteUserRoleCommandHandler : IRequestHandler +{ + private readonly IApplicationDbContext _context; + + public DeleteUserRoleCommandHandler(IApplicationDbContext context) + { + _context = context; + } + + public async Task Handle(DeleteUserRoleCommand request, CancellationToken cancellationToken) + { + var entity = await _context.UserRoles + .FirstOrDefaultAsync(x => x.Id == request.Id, cancellationToken) ?? throw new NotFoundException(nameof(UserRole), request.Id); + entity.IsDeleted = true; + _context.UserRoles.Update(entity); + entity.AddDomainEvent(new DeleteUserRoleEvent(entity)); + await _context.SaveChangesAsync(cancellationToken); + return Unit.Value; + } +} diff --git a/src/CMSMicroservice.Application/UserRoleCQ/Commands/DeleteUserRole/DeleteUserRoleCommandValidator.cs b/src/CMSMicroservice.Application/UserRoleCQ/Commands/DeleteUserRole/DeleteUserRoleCommandValidator.cs new file mode 100644 index 0000000..2784bcf --- /dev/null +++ b/src/CMSMicroservice.Application/UserRoleCQ/Commands/DeleteUserRole/DeleteUserRoleCommandValidator.cs @@ -0,0 +1,16 @@ +namespace CMSMicroservice.Application.UserRoleCQ.Commands.DeleteUserRole; +public class DeleteUserRoleCommandValidator : AbstractValidator +{ + public DeleteUserRoleCommandValidator() + { + RuleFor(model => model.Id) + .NotNull(); + } + public Func>> ValidateValue => async (model, propertyName) => + { + var result = await ValidateAsync(ValidationContext.CreateWithOptions((DeleteUserRoleCommand)model, x => x.IncludeProperties(propertyName))); + if (result.IsValid) + return Array.Empty(); + return result.Errors.Select(e => e.ErrorMessage); + }; +} diff --git a/src/CMSMicroservice.Application/UserRoleCQ/Commands/UpdateUserRole/UpdateUserRoleCommand.cs b/src/CMSMicroservice.Application/UserRoleCQ/Commands/UpdateUserRole/UpdateUserRoleCommand.cs new file mode 100644 index 0000000..b89c1c4 --- /dev/null +++ b/src/CMSMicroservice.Application/UserRoleCQ/Commands/UpdateUserRole/UpdateUserRoleCommand.cs @@ -0,0 +1,11 @@ +namespace CMSMicroservice.Application.UserRoleCQ.Commands.UpdateUserRole; +public record UpdateUserRoleCommand : IRequest +{ + //شناسه + public long Id { get; init; } + //شناسه نقش + public long RoleId { get; init; } + //شناسه کاربر + public long UserId { get; init; } + +} \ No newline at end of file diff --git a/src/CMSMicroservice.Application/UserRoleCQ/Commands/UpdateUserRole/UpdateUserRoleCommandHandler.cs b/src/CMSMicroservice.Application/UserRoleCQ/Commands/UpdateUserRole/UpdateUserRoleCommandHandler.cs new file mode 100644 index 0000000..6f16e3e --- /dev/null +++ b/src/CMSMicroservice.Application/UserRoleCQ/Commands/UpdateUserRole/UpdateUserRoleCommandHandler.cs @@ -0,0 +1,22 @@ +using CMSMicroservice.Domain.Events; +namespace CMSMicroservice.Application.UserRoleCQ.Commands.UpdateUserRole; +public class UpdateUserRoleCommandHandler : IRequestHandler +{ + private readonly IApplicationDbContext _context; + + public UpdateUserRoleCommandHandler(IApplicationDbContext context) + { + _context = context; + } + + public async Task Handle(UpdateUserRoleCommand request, CancellationToken cancellationToken) + { + var entity = await _context.UserRoles + .FirstOrDefaultAsync(x => x.Id == request.Id, cancellationToken) ?? throw new NotFoundException(nameof(UserRole), request.Id); + request.Adapt(entity); + _context.UserRoles.Update(entity); + entity.AddDomainEvent(new UpdateUserRoleEvent(entity)); + await _context.SaveChangesAsync(cancellationToken); + return Unit.Value; + } +} diff --git a/src/CMSMicroservice.Application/UserRoleCQ/Commands/UpdateUserRole/UpdateUserRoleCommandValidator.cs b/src/CMSMicroservice.Application/UserRoleCQ/Commands/UpdateUserRole/UpdateUserRoleCommandValidator.cs new file mode 100644 index 0000000..b969519 --- /dev/null +++ b/src/CMSMicroservice.Application/UserRoleCQ/Commands/UpdateUserRole/UpdateUserRoleCommandValidator.cs @@ -0,0 +1,20 @@ +namespace CMSMicroservice.Application.UserRoleCQ.Commands.UpdateUserRole; +public class UpdateUserRoleCommandValidator : AbstractValidator +{ + public UpdateUserRoleCommandValidator() + { + RuleFor(model => model.Id) + .NotNull(); + RuleFor(model => model.RoleId) + .NotNull(); + RuleFor(model => model.UserId) + .NotNull(); + } + public Func>> ValidateValue => async (model, propertyName) => + { + var result = await ValidateAsync(ValidationContext.CreateWithOptions((UpdateUserRoleCommand)model, x => x.IncludeProperties(propertyName))); + if (result.IsValid) + return Array.Empty(); + return result.Errors.Select(e => e.ErrorMessage); + }; +} diff --git a/src/CMSMicroservice.Application/UserRoleCQ/EventHandlers/CreateNewUserRoleEventHandlers/CreateNewUserRoleEventHandler.cs b/src/CMSMicroservice.Application/UserRoleCQ/EventHandlers/CreateNewUserRoleEventHandlers/CreateNewUserRoleEventHandler.cs new file mode 100644 index 0000000..5a17661 --- /dev/null +++ b/src/CMSMicroservice.Application/UserRoleCQ/EventHandlers/CreateNewUserRoleEventHandlers/CreateNewUserRoleEventHandler.cs @@ -0,0 +1,21 @@ +using CMSMicroservice.Domain.Events; +using Microsoft.Extensions.Logging; + +namespace CMSMicroservice.Application.UserRoleCQ.EventHandlers; + +public class CreateNewUserRoleEventHandler : INotificationHandler +{ + private readonly ILogger _logger; + + public CreateNewUserRoleEventHandler(ILogger logger) + { + _logger = logger; + } + + public Task Handle(CreateNewUserRoleEvent notification, CancellationToken cancellationToken) + { + _logger.LogInformation("Domain Event: {DomainEvent}", notification.GetType().Name); + + return Task.CompletedTask; + } +} diff --git a/src/CMSMicroservice.Application/UserRoleCQ/EventHandlers/DeleteUserRoleEventHandlers/DeleteUserRoleEventHandler.cs b/src/CMSMicroservice.Application/UserRoleCQ/EventHandlers/DeleteUserRoleEventHandlers/DeleteUserRoleEventHandler.cs new file mode 100644 index 0000000..84f8717 --- /dev/null +++ b/src/CMSMicroservice.Application/UserRoleCQ/EventHandlers/DeleteUserRoleEventHandlers/DeleteUserRoleEventHandler.cs @@ -0,0 +1,21 @@ +using CMSMicroservice.Domain.Events; +using Microsoft.Extensions.Logging; + +namespace CMSMicroservice.Application.UserRoleCQ.EventHandlers; + +public class DeleteUserRoleEventHandler : INotificationHandler +{ + private readonly ILogger _logger; + + public DeleteUserRoleEventHandler(ILogger logger) + { + _logger = logger; + } + + public Task Handle(DeleteUserRoleEvent notification, CancellationToken cancellationToken) + { + _logger.LogInformation("Domain Event: {DomainEvent}", notification.GetType().Name); + + return Task.CompletedTask; + } +} diff --git a/src/CMSMicroservice.Application/UserRoleCQ/EventHandlers/UpdateUserRoleEventHandlers/UpdateUserRoleEventHandler.cs b/src/CMSMicroservice.Application/UserRoleCQ/EventHandlers/UpdateUserRoleEventHandlers/UpdateUserRoleEventHandler.cs new file mode 100644 index 0000000..31e7b01 --- /dev/null +++ b/src/CMSMicroservice.Application/UserRoleCQ/EventHandlers/UpdateUserRoleEventHandlers/UpdateUserRoleEventHandler.cs @@ -0,0 +1,21 @@ +using CMSMicroservice.Domain.Events; +using Microsoft.Extensions.Logging; + +namespace CMSMicroservice.Application.UserRoleCQ.EventHandlers; + +public class UpdateUserRoleEventHandler : INotificationHandler +{ + private readonly ILogger _logger; + + public UpdateUserRoleEventHandler(ILogger logger) + { + _logger = logger; + } + + public Task Handle(UpdateUserRoleEvent notification, CancellationToken cancellationToken) + { + _logger.LogInformation("Domain Event: {DomainEvent}", notification.GetType().Name); + + return Task.CompletedTask; + } +} diff --git a/src/CMSMicroservice.Application/UserRoleCQ/Queries/GetAllUserRoleByFilter/GetAllUserRoleByFilterQuery.cs b/src/CMSMicroservice.Application/UserRoleCQ/Queries/GetAllUserRoleByFilter/GetAllUserRoleByFilterQuery.cs new file mode 100644 index 0000000..d129fd4 --- /dev/null +++ b/src/CMSMicroservice.Application/UserRoleCQ/Queries/GetAllUserRoleByFilter/GetAllUserRoleByFilterQuery.cs @@ -0,0 +1,19 @@ +namespace CMSMicroservice.Application.UserRoleCQ.Queries.GetAllUserRoleByFilter; +public record GetAllUserRoleByFilterQuery : IRequest +{ + //موقعیت صفحه بندی + public PaginationState? PaginationState { get; init; } + //مرتب سازی بر اساس + public string? SortBy { get; init; } + //فیلتر + public GetAllUserRoleByFilterFilter? Filter { get; init; } + +}public class GetAllUserRoleByFilterFilter +{ + //شناسه + public long? Id { get; set; } + //شناسه نقش + public long? RoleId { get; set; } + //شناسه کاربر + public long? UserId { get; set; } +} diff --git a/src/CMSMicroservice.Application/UserRoleCQ/Queries/GetAllUserRoleByFilter/GetAllUserRoleByFilterQueryHandler.cs b/src/CMSMicroservice.Application/UserRoleCQ/Queries/GetAllUserRoleByFilter/GetAllUserRoleByFilterQueryHandler.cs new file mode 100644 index 0000000..3a7b943 --- /dev/null +++ b/src/CMSMicroservice.Application/UserRoleCQ/Queries/GetAllUserRoleByFilter/GetAllUserRoleByFilterQueryHandler.cs @@ -0,0 +1,32 @@ +namespace CMSMicroservice.Application.UserRoleCQ.Queries.GetAllUserRoleByFilter; +public class GetAllUserRoleByFilterQueryHandler : IRequestHandler +{ + private readonly IApplicationDbContext _context; + + public GetAllUserRoleByFilterQueryHandler(IApplicationDbContext context) + { + _context = context; + } + + public async Task Handle(GetAllUserRoleByFilterQuery request, CancellationToken cancellationToken) + { + var query = _context.UserRoles + .ApplyOrder(sortBy: request.SortBy) + .AsNoTracking() + .AsQueryable(); + if (request.Filter is not null) + { + query = query + .Where(x => request.Filter.Id == null || x.Id == request.Filter.Id) + .Where(x => request.Filter.RoleId == null || x.RoleId == request.Filter.RoleId) + .Where(x => request.Filter.UserId == null || x.UserId == request.Filter.UserId) +; + } + return new GetAllUserRoleByFilterResponseDto + { + MetaData = await query.GetMetaData(request.PaginationState, cancellationToken), + Models = await query.PaginatedListAsync(paginationState: request.PaginationState) + .ProjectToType().ToListAsync(cancellationToken) + }; + } +} diff --git a/src/CMSMicroservice.Application/UserRoleCQ/Queries/GetAllUserRoleByFilter/GetAllUserRoleByFilterQueryValidator.cs b/src/CMSMicroservice.Application/UserRoleCQ/Queries/GetAllUserRoleByFilter/GetAllUserRoleByFilterQueryValidator.cs new file mode 100644 index 0000000..7eceb0a --- /dev/null +++ b/src/CMSMicroservice.Application/UserRoleCQ/Queries/GetAllUserRoleByFilter/GetAllUserRoleByFilterQueryValidator.cs @@ -0,0 +1,14 @@ +namespace CMSMicroservice.Application.UserRoleCQ.Queries.GetAllUserRoleByFilter; +public class GetAllUserRoleByFilterQueryValidator : AbstractValidator +{ + public GetAllUserRoleByFilterQueryValidator() + { + } + public Func>> ValidateValue => async (model, propertyName) => + { + var result = await ValidateAsync(ValidationContext.CreateWithOptions((GetAllUserRoleByFilterQuery)model, x => x.IncludeProperties(propertyName))); + if (result.IsValid) + return Array.Empty(); + return result.Errors.Select(e => e.ErrorMessage); + }; +} diff --git a/src/CMSMicroservice.Application/UserRoleCQ/Queries/GetAllUserRoleByFilter/GetAllUserRoleByFilterResponseDto.cs b/src/CMSMicroservice.Application/UserRoleCQ/Queries/GetAllUserRoleByFilter/GetAllUserRoleByFilterResponseDto.cs new file mode 100644 index 0000000..9550735 --- /dev/null +++ b/src/CMSMicroservice.Application/UserRoleCQ/Queries/GetAllUserRoleByFilter/GetAllUserRoleByFilterResponseDto.cs @@ -0,0 +1,17 @@ +namespace CMSMicroservice.Application.UserRoleCQ.Queries.GetAllUserRoleByFilter; +public class GetAllUserRoleByFilterResponseDto +{ + //متادیتا + public MetaData MetaData { get; set; } + //مدل خروجی + public List? Models { get; set; } + +}public class GetAllUserRoleByFilterResponseModel +{ + //شناسه + public long Id { get; set; } + //شناسه نقش + public long RoleId { get; set; } + //شناسه کاربر + public long UserId { get; set; } +} diff --git a/src/CMSMicroservice.Application/UserRoleCQ/Queries/GetUserRole/GetUserRoleQuery.cs b/src/CMSMicroservice.Application/UserRoleCQ/Queries/GetUserRole/GetUserRoleQuery.cs new file mode 100644 index 0000000..94e2689 --- /dev/null +++ b/src/CMSMicroservice.Application/UserRoleCQ/Queries/GetUserRole/GetUserRoleQuery.cs @@ -0,0 +1,7 @@ +namespace CMSMicroservice.Application.UserRoleCQ.Queries.GetUserRole; +public record GetUserRoleQuery : IRequest +{ + //شناسه + public long Id { get; init; } + +} \ No newline at end of file diff --git a/src/CMSMicroservice.Application/UserRoleCQ/Queries/GetUserRole/GetUserRoleQueryHandler.cs b/src/CMSMicroservice.Application/UserRoleCQ/Queries/GetUserRole/GetUserRoleQueryHandler.cs new file mode 100644 index 0000000..84de775 --- /dev/null +++ b/src/CMSMicroservice.Application/UserRoleCQ/Queries/GetUserRole/GetUserRoleQueryHandler.cs @@ -0,0 +1,22 @@ +namespace CMSMicroservice.Application.UserRoleCQ.Queries.GetUserRole; +public class GetUserRoleQueryHandler : IRequestHandler +{ + private readonly IApplicationDbContext _context; + + public GetUserRoleQueryHandler(IApplicationDbContext context) + { + _context = context; + } + + public async Task Handle(GetUserRoleQuery request, + CancellationToken cancellationToken) + { + var response = await _context.UserRoles + .AsNoTracking() + .Where(x => x.Id == request.Id) + .ProjectToType() + .FirstOrDefaultAsync(cancellationToken); + + return response ?? throw new NotFoundException(nameof(UserRole), request.Id); + } +} diff --git a/src/CMSMicroservice.Application/UserRoleCQ/Queries/GetUserRole/GetUserRoleQueryValidator.cs b/src/CMSMicroservice.Application/UserRoleCQ/Queries/GetUserRole/GetUserRoleQueryValidator.cs new file mode 100644 index 0000000..0e13eae --- /dev/null +++ b/src/CMSMicroservice.Application/UserRoleCQ/Queries/GetUserRole/GetUserRoleQueryValidator.cs @@ -0,0 +1,16 @@ +namespace CMSMicroservice.Application.UserRoleCQ.Queries.GetUserRole; +public class GetUserRoleQueryValidator : AbstractValidator +{ + public GetUserRoleQueryValidator() + { + RuleFor(model => model.Id) + .NotNull(); + } + public Func>> ValidateValue => async (model, propertyName) => + { + var result = await ValidateAsync(ValidationContext.CreateWithOptions((GetUserRoleQuery)model, x => x.IncludeProperties(propertyName))); + if (result.IsValid) + return Array.Empty(); + return result.Errors.Select(e => e.ErrorMessage); + }; +} diff --git a/src/CMSMicroservice.Application/UserRoleCQ/Queries/GetUserRole/GetUserRoleResponseDto.cs b/src/CMSMicroservice.Application/UserRoleCQ/Queries/GetUserRole/GetUserRoleResponseDto.cs new file mode 100644 index 0000000..bbf9342 --- /dev/null +++ b/src/CMSMicroservice.Application/UserRoleCQ/Queries/GetUserRole/GetUserRoleResponseDto.cs @@ -0,0 +1,11 @@ +namespace CMSMicroservice.Application.UserRoleCQ.Queries.GetUserRole; +public class GetUserRoleResponseDto +{ + //شناسه + public long Id { get; set; } + //شناسه نقش + public long RoleId { get; set; } + //شناسه کاربر + public long UserId { get; set; } + +} \ No newline at end of file diff --git a/src/CMSMicroservice.Domain/CMSMicroservice.Domain.csproj b/src/CMSMicroservice.Domain/CMSMicroservice.Domain.csproj new file mode 100644 index 0000000..8d4bd93 --- /dev/null +++ b/src/CMSMicroservice.Domain/CMSMicroservice.Domain.csproj @@ -0,0 +1,12 @@ + + + + net7.0 + enable + + + + + + + diff --git a/src/CMSMicroservice.Domain/Common/BaseAuditableEntity.cs b/src/CMSMicroservice.Domain/Common/BaseAuditableEntity.cs new file mode 100644 index 0000000..583dcca --- /dev/null +++ b/src/CMSMicroservice.Domain/Common/BaseAuditableEntity.cs @@ -0,0 +1,13 @@ +namespace CMSMicroservice.Domain.Common; +public abstract class BaseAuditableEntity : BaseEntity +{ + public DateTime Created { get; set; } + + public string? CreatedBy { get; set; } + + public DateTime? LastModified { get; set; } + + public string? LastModifiedBy { get; set; } + + public bool IsDeleted { get; set; } +} \ No newline at end of file diff --git a/src/CMSMicroservice.Domain/Common/BaseEntity.cs b/src/CMSMicroservice.Domain/Common/BaseEntity.cs new file mode 100644 index 0000000..a3f377d --- /dev/null +++ b/src/CMSMicroservice.Domain/Common/BaseEntity.cs @@ -0,0 +1,24 @@ +namespace CMSMicroservice.Domain.Common; +public abstract class BaseEntity +{ + public long Id { get; set; } + + private readonly List _domainEvents = new(); + + public IReadOnlyCollection DomainEvents => _domainEvents.AsReadOnly(); + + public void AddDomainEvent(BaseEvent domainEvent) + { + _domainEvents.Add(domainEvent); + } + + public void RemoveDomainEvent(BaseEvent domainEvent) + { + _domainEvents.Remove(domainEvent); + } + + public void ClearDomainEvents() + { + _domainEvents.Clear(); + } +} \ No newline at end of file diff --git a/src/CMSMicroservice.Domain/Common/BaseEvent.cs b/src/CMSMicroservice.Domain/Common/BaseEvent.cs new file mode 100644 index 0000000..493fda6 --- /dev/null +++ b/src/CMSMicroservice.Domain/Common/BaseEvent.cs @@ -0,0 +1,4 @@ +namespace CMSMicroservice.Domain.Common; +public abstract class BaseEvent : INotification +{ +} \ No newline at end of file diff --git a/src/CMSMicroservice.Domain/Common/ValueObject.cs b/src/CMSMicroservice.Domain/Common/ValueObject.cs new file mode 100644 index 0000000..df26785 --- /dev/null +++ b/src/CMSMicroservice.Domain/Common/ValueObject.cs @@ -0,0 +1,38 @@ +namespace CMSMicroservice.Domain.Common; +public abstract class ValueObject +{ + protected static bool EqualOperator(ValueObject left, ValueObject right) + { + if (left is null ^ right is null) + { + return false; + } + + return left?.Equals(right!) != false; + } + + protected static bool NotEqualOperator(ValueObject left, ValueObject right) + { + return !(EqualOperator(left, right)); + } + + protected abstract IEnumerable GetEqualityComponents(); + + public override bool Equals(object? obj) + { + if (obj == null || obj.GetType() != GetType()) + { + return false; + } + + var other = (ValueObject)obj; + return GetEqualityComponents().SequenceEqual(other.GetEqualityComponents()); + } + + public override int GetHashCode() + { + return GetEqualityComponents() + .Select(x => x != null ? x.GetHashCode() : 0) + .Aggregate((x, y) => x ^ y); + } +} \ No newline at end of file diff --git a/src/CMSMicroservice.Domain/Entities/Package.cs b/src/CMSMicroservice.Domain/Entities/Package.cs new file mode 100644 index 0000000..05c3484 --- /dev/null +++ b/src/CMSMicroservice.Domain/Entities/Package.cs @@ -0,0 +1,15 @@ +namespace CMSMicroservice.Domain.Entities; +//پکیج +public class Package : BaseAuditableEntity +{ + //عنوان + public string Title { get; set; } + //توضیحات + public string Description { get; set; } + //آدرس تصویر + public string ImagePath { get; set; } + //قیمت + public long Price { get; set; } + //UserOrder Collection Navigation Reference + public virtual ICollection UserOrders { get; set; } +} \ No newline at end of file diff --git a/src/CMSMicroservice.Domain/Entities/Role.cs b/src/CMSMicroservice.Domain/Entities/Role.cs new file mode 100644 index 0000000..ab41c83 --- /dev/null +++ b/src/CMSMicroservice.Domain/Entities/Role.cs @@ -0,0 +1,11 @@ +namespace CMSMicroservice.Domain.Entities; +//نقش +public class Role : BaseAuditableEntity +{ + //نام لاتین + public string Name { get; set; } + //عنوان + public string Title { get; set; } + //UserRole Collection Navigation Reference + public virtual ICollection UserRoles { get; set; } +} \ No newline at end of file diff --git a/src/CMSMicroservice.Domain/Entities/User.cs b/src/CMSMicroservice.Domain/Entities/User.cs new file mode 100644 index 0000000..02b8cf8 --- /dev/null +++ b/src/CMSMicroservice.Domain/Entities/User.cs @@ -0,0 +1,27 @@ +namespace CMSMicroservice.Domain.Entities; +//کاربر +public class User : BaseAuditableEntity +{ + //نام + public string? FirstName { get; set; } + //نام خانوادگی + public string? LastName { get; set; } + //شماره موبایل + public string Mobile { get; set; } + //کد ملی + public string? NationalCode { get; set; } + //آدرس آواتار + public string? AvatarPath { get; set; } + //شناسه والد + public long? ParentId { get; set; } + //User Navigation Property + public virtual User? Parent { get; set; } + //User Collection Navigation Reference + public virtual ICollection Users { get; set; } + //UserAddress Collection Navigation Reference + public virtual ICollection UserAddresss { get; set; } + //UserOrder Collection Navigation Reference + public virtual ICollection UserOrders { get; set; } + //UserRole Collection Navigation Reference + public virtual ICollection UserRoles { get; set; } +} \ No newline at end of file diff --git a/src/CMSMicroservice.Domain/Entities/UserAddress.cs b/src/CMSMicroservice.Domain/Entities/UserAddress.cs new file mode 100644 index 0000000..2929e33 --- /dev/null +++ b/src/CMSMicroservice.Domain/Entities/UserAddress.cs @@ -0,0 +1,19 @@ +namespace CMSMicroservice.Domain.Entities; +//آدرس کاربر +public class UserAddress : BaseAuditableEntity +{ + //شناسه کاربر + public long UserId { get; set; } + //User Navigation Property + public virtual User User { get; set; } + //عنوان + public string Title { get; set; } + //آدرس + public string Address { get; set; } + //کدپستی + public string PostalCode { get; set; } + //پیشفرض؟ + public bool IsDefault { get; set; } + //شناسه شهر + public long CityId { get; set; } +} \ No newline at end of file diff --git a/src/CMSMicroservice.Domain/Entities/UserOrder.cs b/src/CMSMicroservice.Domain/Entities/UserOrder.cs new file mode 100644 index 0000000..d2d658b --- /dev/null +++ b/src/CMSMicroservice.Domain/Entities/UserOrder.cs @@ -0,0 +1,21 @@ +namespace CMSMicroservice.Domain.Entities; +//سفارش کاربر +public class UserOrder : BaseAuditableEntity +{ + //قیمت + public long Price { get; set; } + //شناسه پکیج + public long PackageId { get; set; } + //Package Navigation Property + public virtual Package Package { get; set; } + //شناسه تراکنش + public long? TransactionId { get; set; } + //وضعیت پرداخت + public bool PaymentStatus { get; set; } + //تاریخ پرداخت + public DateTime? PaymentDate { get; set; } + //شناسه کاربر + public long UserId { get; set; } + //User Navigation Property + public virtual User User { get; set; } +} \ No newline at end of file diff --git a/src/CMSMicroservice.Domain/Entities/UserRole.cs b/src/CMSMicroservice.Domain/Entities/UserRole.cs new file mode 100644 index 0000000..3798634 --- /dev/null +++ b/src/CMSMicroservice.Domain/Entities/UserRole.cs @@ -0,0 +1,13 @@ +namespace CMSMicroservice.Domain.Entities; +//نقش کاربر +public class UserRole : BaseAuditableEntity +{ + //شناسه نقش + public long RoleId { get; set; } + //Role Navigation Property + public virtual Role Role { get; set; } + //شناسه کاربر + public long UserId { get; set; } + //User Navigation Property + public virtual User User { get; set; } +} \ No newline at end of file diff --git a/src/CMSMicroservice.Domain/Events/PackageEvents/CreateNewPackageEvent.cs b/src/CMSMicroservice.Domain/Events/PackageEvents/CreateNewPackageEvent.cs new file mode 100644 index 0000000..c831060 --- /dev/null +++ b/src/CMSMicroservice.Domain/Events/PackageEvents/CreateNewPackageEvent.cs @@ -0,0 +1,10 @@ +namespace CMSMicroservice.Domain.Events; +public class CreateNewPackageEvent : BaseEvent +{ + public CreateNewPackageEvent(Package item) + { + Item = item; + } + + public Package Item { get; } +} diff --git a/src/CMSMicroservice.Domain/Events/PackageEvents/DeletePackageEvent.cs b/src/CMSMicroservice.Domain/Events/PackageEvents/DeletePackageEvent.cs new file mode 100644 index 0000000..766331c --- /dev/null +++ b/src/CMSMicroservice.Domain/Events/PackageEvents/DeletePackageEvent.cs @@ -0,0 +1,10 @@ +namespace CMSMicroservice.Domain.Events; +public class DeletePackageEvent : BaseEvent +{ + public DeletePackageEvent(Package item) + { + Item = item; + } + + public Package Item { get; } +} diff --git a/src/CMSMicroservice.Domain/Events/PackageEvents/UpdatePackageEvent.cs b/src/CMSMicroservice.Domain/Events/PackageEvents/UpdatePackageEvent.cs new file mode 100644 index 0000000..1a7ab20 --- /dev/null +++ b/src/CMSMicroservice.Domain/Events/PackageEvents/UpdatePackageEvent.cs @@ -0,0 +1,10 @@ +namespace CMSMicroservice.Domain.Events; +public class UpdatePackageEvent : BaseEvent +{ + public UpdatePackageEvent(Package item) + { + Item = item; + } + + public Package Item { get; } +} diff --git a/src/CMSMicroservice.Domain/Events/RoleEvents/CreateNewRoleEvent.cs b/src/CMSMicroservice.Domain/Events/RoleEvents/CreateNewRoleEvent.cs new file mode 100644 index 0000000..04a1e14 --- /dev/null +++ b/src/CMSMicroservice.Domain/Events/RoleEvents/CreateNewRoleEvent.cs @@ -0,0 +1,10 @@ +namespace CMSMicroservice.Domain.Events; +public class CreateNewRoleEvent : BaseEvent +{ + public CreateNewRoleEvent(Role item) + { + Item = item; + } + + public Role Item { get; } +} diff --git a/src/CMSMicroservice.Domain/Events/RoleEvents/DeleteRoleEvent.cs b/src/CMSMicroservice.Domain/Events/RoleEvents/DeleteRoleEvent.cs new file mode 100644 index 0000000..80bd3e7 --- /dev/null +++ b/src/CMSMicroservice.Domain/Events/RoleEvents/DeleteRoleEvent.cs @@ -0,0 +1,10 @@ +namespace CMSMicroservice.Domain.Events; +public class DeleteRoleEvent : BaseEvent +{ + public DeleteRoleEvent(Role item) + { + Item = item; + } + + public Role Item { get; } +} diff --git a/src/CMSMicroservice.Domain/Events/RoleEvents/UpdateRoleEvent.cs b/src/CMSMicroservice.Domain/Events/RoleEvents/UpdateRoleEvent.cs new file mode 100644 index 0000000..99ff4a2 --- /dev/null +++ b/src/CMSMicroservice.Domain/Events/RoleEvents/UpdateRoleEvent.cs @@ -0,0 +1,10 @@ +namespace CMSMicroservice.Domain.Events; +public class UpdateRoleEvent : BaseEvent +{ + public UpdateRoleEvent(Role item) + { + Item = item; + } + + public Role Item { get; } +} diff --git a/src/CMSMicroservice.Domain/Events/UserAddressEvents/CreateNewUserAddressEvent.cs b/src/CMSMicroservice.Domain/Events/UserAddressEvents/CreateNewUserAddressEvent.cs new file mode 100644 index 0000000..eeb0bb1 --- /dev/null +++ b/src/CMSMicroservice.Domain/Events/UserAddressEvents/CreateNewUserAddressEvent.cs @@ -0,0 +1,10 @@ +namespace CMSMicroservice.Domain.Events; +public class CreateNewUserAddressEvent : BaseEvent +{ + public CreateNewUserAddressEvent(UserAddress item) + { + Item = item; + } + + public UserAddress Item { get; } +} diff --git a/src/CMSMicroservice.Domain/Events/UserAddressEvents/DeleteUserAddressEvent.cs b/src/CMSMicroservice.Domain/Events/UserAddressEvents/DeleteUserAddressEvent.cs new file mode 100644 index 0000000..7db3a92 --- /dev/null +++ b/src/CMSMicroservice.Domain/Events/UserAddressEvents/DeleteUserAddressEvent.cs @@ -0,0 +1,10 @@ +namespace CMSMicroservice.Domain.Events; +public class DeleteUserAddressEvent : BaseEvent +{ + public DeleteUserAddressEvent(UserAddress item) + { + Item = item; + } + + public UserAddress Item { get; } +} diff --git a/src/CMSMicroservice.Domain/Events/UserAddressEvents/UpdateUserAddressEvent.cs b/src/CMSMicroservice.Domain/Events/UserAddressEvents/UpdateUserAddressEvent.cs new file mode 100644 index 0000000..5b0bdb3 --- /dev/null +++ b/src/CMSMicroservice.Domain/Events/UserAddressEvents/UpdateUserAddressEvent.cs @@ -0,0 +1,10 @@ +namespace CMSMicroservice.Domain.Events; +public class UpdateUserAddressEvent : BaseEvent +{ + public UpdateUserAddressEvent(UserAddress item) + { + Item = item; + } + + public UserAddress Item { get; } +} diff --git a/src/CMSMicroservice.Domain/Events/UserEvents/CreateNewUserEvent.cs b/src/CMSMicroservice.Domain/Events/UserEvents/CreateNewUserEvent.cs new file mode 100644 index 0000000..f6413bf --- /dev/null +++ b/src/CMSMicroservice.Domain/Events/UserEvents/CreateNewUserEvent.cs @@ -0,0 +1,10 @@ +namespace CMSMicroservice.Domain.Events; +public class CreateNewUserEvent : BaseEvent +{ + public CreateNewUserEvent(User item) + { + Item = item; + } + + public User Item { get; } +} diff --git a/src/CMSMicroservice.Domain/Events/UserEvents/DeleteUserEvent.cs b/src/CMSMicroservice.Domain/Events/UserEvents/DeleteUserEvent.cs new file mode 100644 index 0000000..5b67460 --- /dev/null +++ b/src/CMSMicroservice.Domain/Events/UserEvents/DeleteUserEvent.cs @@ -0,0 +1,10 @@ +namespace CMSMicroservice.Domain.Events; +public class DeleteUserEvent : BaseEvent +{ + public DeleteUserEvent(User item) + { + Item = item; + } + + public User Item { get; } +} diff --git a/src/CMSMicroservice.Domain/Events/UserEvents/UpdateUserEvent.cs b/src/CMSMicroservice.Domain/Events/UserEvents/UpdateUserEvent.cs new file mode 100644 index 0000000..196e835 --- /dev/null +++ b/src/CMSMicroservice.Domain/Events/UserEvents/UpdateUserEvent.cs @@ -0,0 +1,10 @@ +namespace CMSMicroservice.Domain.Events; +public class UpdateUserEvent : BaseEvent +{ + public UpdateUserEvent(User item) + { + Item = item; + } + + public User Item { get; } +} diff --git a/src/CMSMicroservice.Domain/Events/UserOrderEvents/CreateNewUserOrderEvent.cs b/src/CMSMicroservice.Domain/Events/UserOrderEvents/CreateNewUserOrderEvent.cs new file mode 100644 index 0000000..84cb7cb --- /dev/null +++ b/src/CMSMicroservice.Domain/Events/UserOrderEvents/CreateNewUserOrderEvent.cs @@ -0,0 +1,10 @@ +namespace CMSMicroservice.Domain.Events; +public class CreateNewUserOrderEvent : BaseEvent +{ + public CreateNewUserOrderEvent(UserOrder item) + { + Item = item; + } + + public UserOrder Item { get; } +} diff --git a/src/CMSMicroservice.Domain/Events/UserOrderEvents/DeleteUserOrderEvent.cs b/src/CMSMicroservice.Domain/Events/UserOrderEvents/DeleteUserOrderEvent.cs new file mode 100644 index 0000000..a3b1777 --- /dev/null +++ b/src/CMSMicroservice.Domain/Events/UserOrderEvents/DeleteUserOrderEvent.cs @@ -0,0 +1,10 @@ +namespace CMSMicroservice.Domain.Events; +public class DeleteUserOrderEvent : BaseEvent +{ + public DeleteUserOrderEvent(UserOrder item) + { + Item = item; + } + + public UserOrder Item { get; } +} diff --git a/src/CMSMicroservice.Domain/Events/UserOrderEvents/UpdateUserOrderEvent.cs b/src/CMSMicroservice.Domain/Events/UserOrderEvents/UpdateUserOrderEvent.cs new file mode 100644 index 0000000..708d58c --- /dev/null +++ b/src/CMSMicroservice.Domain/Events/UserOrderEvents/UpdateUserOrderEvent.cs @@ -0,0 +1,10 @@ +namespace CMSMicroservice.Domain.Events; +public class UpdateUserOrderEvent : BaseEvent +{ + public UpdateUserOrderEvent(UserOrder item) + { + Item = item; + } + + public UserOrder Item { get; } +} diff --git a/src/CMSMicroservice.Domain/Events/UserRoleEvents/CreateNewUserRoleEvent.cs b/src/CMSMicroservice.Domain/Events/UserRoleEvents/CreateNewUserRoleEvent.cs new file mode 100644 index 0000000..22b4c36 --- /dev/null +++ b/src/CMSMicroservice.Domain/Events/UserRoleEvents/CreateNewUserRoleEvent.cs @@ -0,0 +1,10 @@ +namespace CMSMicroservice.Domain.Events; +public class CreateNewUserRoleEvent : BaseEvent +{ + public CreateNewUserRoleEvent(UserRole item) + { + Item = item; + } + + public UserRole Item { get; } +} diff --git a/src/CMSMicroservice.Domain/Events/UserRoleEvents/DeleteUserRoleEvent.cs b/src/CMSMicroservice.Domain/Events/UserRoleEvents/DeleteUserRoleEvent.cs new file mode 100644 index 0000000..aef9805 --- /dev/null +++ b/src/CMSMicroservice.Domain/Events/UserRoleEvents/DeleteUserRoleEvent.cs @@ -0,0 +1,10 @@ +namespace CMSMicroservice.Domain.Events; +public class DeleteUserRoleEvent : BaseEvent +{ + public DeleteUserRoleEvent(UserRole item) + { + Item = item; + } + + public UserRole Item { get; } +} diff --git a/src/CMSMicroservice.Domain/Events/UserRoleEvents/UpdateUserRoleEvent.cs b/src/CMSMicroservice.Domain/Events/UserRoleEvents/UpdateUserRoleEvent.cs new file mode 100644 index 0000000..61d8b1a --- /dev/null +++ b/src/CMSMicroservice.Domain/Events/UserRoleEvents/UpdateUserRoleEvent.cs @@ -0,0 +1,10 @@ +namespace CMSMicroservice.Domain.Events; +public class UpdateUserRoleEvent : BaseEvent +{ + public UpdateUserRoleEvent(UserRole item) + { + Item = item; + } + + public UserRole Item { get; } +} diff --git a/src/CMSMicroservice.Domain/GlobalUsings.cs b/src/CMSMicroservice.Domain/GlobalUsings.cs new file mode 100644 index 0000000..e6d77cb --- /dev/null +++ b/src/CMSMicroservice.Domain/GlobalUsings.cs @@ -0,0 +1,10 @@ +global using CMSMicroservice.Domain.Common; +global using CMSMicroservice.Domain.Entities; + +global using CMSMicroservice.Domain.Events; +global using System.Threading; +global using System.Threading.Tasks; +global using System; +global using System.Collections.Generic; +global using System.Linq; +global using MediatR; diff --git a/src/CMSMicroservice.Infrastructure/CMSMicroservice.Infrastructure.csproj b/src/CMSMicroservice.Infrastructure/CMSMicroservice.Infrastructure.csproj new file mode 100644 index 0000000..c53f550 --- /dev/null +++ b/src/CMSMicroservice.Infrastructure/CMSMicroservice.Infrastructure.csproj @@ -0,0 +1,23 @@ + + + + net7.0 + enable + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + \ No newline at end of file diff --git a/src/CMSMicroservice.Infrastructure/Common/MediatorExtensions.cs b/src/CMSMicroservice.Infrastructure/Common/MediatorExtensions.cs new file mode 100644 index 0000000..0944dd5 --- /dev/null +++ b/src/CMSMicroservice.Infrastructure/Common/MediatorExtensions.cs @@ -0,0 +1,24 @@ +using CMSMicroservice.Domain.Common; +using Microsoft.EntityFrameworkCore; + +namespace MediatR; + +public static class MediatorExtensions +{ + public static async Task DispatchDomainEvents(this IMediator mediator, DbContext context) + { + var entities = context.ChangeTracker + .Entries() + .Where(e => e.Entity.DomainEvents.Any()) + .Select(e => e.Entity); + + var domainEvents = entities + .SelectMany(e => e.DomainEvents) + .ToList(); + + entities.ToList().ForEach(e => e.ClearDomainEvents()); + + foreach (var domainEvent in domainEvents) + await mediator.Publish(domainEvent); + } +} \ No newline at end of file diff --git a/src/CMSMicroservice.Infrastructure/ConfigureServices.cs b/src/CMSMicroservice.Infrastructure/ConfigureServices.cs new file mode 100644 index 0000000..8da1474 --- /dev/null +++ b/src/CMSMicroservice.Infrastructure/ConfigureServices.cs @@ -0,0 +1,92 @@ +using CMSMicroservice.Application.Common.Interfaces; +using CMSMicroservice.Infrastructure.Persistence; +using CMSMicroservice.Infrastructure.Persistence.Interceptors; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Configuration; +using Microsoft.AspNetCore.Authentication.JwtBearer; +using Microsoft.AspNetCore.Http; +using System.Diagnostics; +using Microsoft.Extensions.Configuration; + +namespace Microsoft.Extensions.DependencyInjection; + +public static class ConfigureServices +{ + public static IServiceCollection AddInfrastructureServices(this IServiceCollection services, IConfiguration configuration) + { + services.AddScoped(); + services.AddScoped(); + services.AddScoped(p => p.GetRequiredService()); + if (configuration.GetValue("UseInMemoryDatabase")) + { + services.AddDbContext(options => + options.UseInMemoryDatabase("MyMemoryDb")); + } + else + { + services.AddDbContext(options => + options.UseSqlServer(configuration.GetConnectionString("DefaultConnection"), + builder => builder.MigrationsAssembly(typeof(ApplicationDbContext).Assembly.FullName))); + } + #region AddAuthentication + + var message = ""; + services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) + .AddJwtBearer(jwtBearerOptions => + { + jwtBearerOptions.Authority = configuration["Authentication:Authority"]; + jwtBearerOptions.Audience = configuration["Authentication:Audience"]; + jwtBearerOptions.TokenValidationParameters.ValidateAudience = false; + jwtBearerOptions.TokenValidationParameters.ValidateIssuer = true; + jwtBearerOptions.TokenValidationParameters.ValidateIssuerSigningKey = false; + try + { + jwtBearerOptions.Events = new JwtBearerEvents + { + OnAuthenticationFailed = ctx => + { + ctx.Response.StatusCode = StatusCodes.Status401Unauthorized; + message += "From OnAuthenticationFailed:\n"; + message += ctx.Exception.Message; + return Task.CompletedTask; + }, + + OnChallenge = ctx => + { + message += "From OnChallenge:\n"; + ctx.Response.StatusCode = StatusCodes.Status401Unauthorized; + ctx.Response.ContentType = "text/plain"; + return ctx.Response.WriteAsync(message); + }, + + OnMessageReceived = ctx => + { + message = "From OnMessageReceived:\n"; + ctx.Request.Headers.TryGetValue("Authorization", out var BearerToken); + if (BearerToken.Count == 0) + BearerToken = "no Bearer token sent\n"; + message += "Authorization Header sent: " + BearerToken + "\n"; + return Task.CompletedTask; + }, + + OnTokenValidated = ctx => + { + Debug.WriteLine("token: " + ctx.SecurityToken.ToString()); + return Task.CompletedTask; + } + }; + } + catch (Exception e) + { + Console.WriteLine(e); + throw; + } + }); + + services.AddAuthorization(); + + #endregion + + return services; + } +} \ No newline at end of file diff --git a/src/CMSMicroservice.Infrastructure/GlobalUsings.cs b/src/CMSMicroservice.Infrastructure/GlobalUsings.cs new file mode 100644 index 0000000..95a993b --- /dev/null +++ b/src/CMSMicroservice.Infrastructure/GlobalUsings.cs @@ -0,0 +1,4 @@ +global using System.Threading; +global using System.Threading.Tasks; +global using System; +global using System.Linq; \ No newline at end of file diff --git a/src/CMSMicroservice.Infrastructure/Persistence/ApplicationDbContext.cs b/src/CMSMicroservice.Infrastructure/Persistence/ApplicationDbContext.cs new file mode 100644 index 0000000..bc84efd --- /dev/null +++ b/src/CMSMicroservice.Infrastructure/Persistence/ApplicationDbContext.cs @@ -0,0 +1,49 @@ +using System.Reflection; +using CMSMicroservice.Application.Common.Interfaces; +using CMSMicroservice.Domain.Entities; +using CMSMicroservice.Infrastructure.Persistence.Interceptors; +using MediatR; +using Microsoft.EntityFrameworkCore; + +namespace CMSMicroservice.Infrastructure.Persistence; + +public class ApplicationDbContext : DbContext, IApplicationDbContext +{ + private readonly IMediator _mediator; + private readonly AuditableEntitySaveChangesInterceptor _auditableEntitySaveChangesInterceptor; + + public ApplicationDbContext( + DbContextOptions options, + IMediator mediator, + AuditableEntitySaveChangesInterceptor auditableEntitySaveChangesInterceptor) + : base(options) + { + _mediator = mediator; + _auditableEntitySaveChangesInterceptor = auditableEntitySaveChangesInterceptor; + } + protected override void OnModelCreating(ModelBuilder builder) + { + builder.ApplyConfigurationsFromAssembly(Assembly.GetExecutingAssembly()); + builder.HasDefaultSchema("CMS"); + base.OnModelCreating(builder); + } + + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + { + optionsBuilder.AddInterceptors(_auditableEntitySaveChangesInterceptor); + } + + public override async Task SaveChangesAsync(CancellationToken cancellationToken = default) + { + await _mediator.DispatchDomainEvents(this); + + return await base.SaveChangesAsync(cancellationToken); + } + public DbSet Users => Set(); + public DbSet UserAddresss => Set(); + public DbSet Packages => Set(); + public DbSet UserOrders => Set(); + public DbSet Roles => Set(); + public DbSet UserRoles => Set(); + +} \ No newline at end of file diff --git a/src/CMSMicroservice.Infrastructure/Persistence/ApplicationDbContextInitialiser.cs b/src/CMSMicroservice.Infrastructure/Persistence/ApplicationDbContextInitialiser.cs new file mode 100644 index 0000000..2d603b8 --- /dev/null +++ b/src/CMSMicroservice.Infrastructure/Persistence/ApplicationDbContextInitialiser.cs @@ -0,0 +1,49 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Logging; + +namespace CMSMicroservice.Infrastructure.Persistence; + +public class ApplicationDbContextInitialiser +{ + private readonly ApplicationDbContext _context; + private readonly ILogger _logger; + + public ApplicationDbContextInitialiser(ApplicationDbContext context, ILogger logger) + { + _context = context; + _logger = logger; + } + + public async Task InitialiseAsync() + { + try + { + if (_context.Database.IsSqlServer()) + { + await _context.Database.MigrateAsync(); + } + } + catch (Exception ex) + { + _logger.LogError(ex, "An error occurred while initialising the database."); + throw; + } + } + + public async Task SeedAsync() + { + try + { + await TrySeedAsync(); + } + catch (Exception ex) + { + _logger.LogError(ex, "An error occurred while seeding the database."); + throw; + } + } + public async Task TrySeedAsync() + { + + } +} diff --git a/src/CMSMicroservice.Infrastructure/Persistence/Configurations/PackageConfiguration.cs b/src/CMSMicroservice.Infrastructure/Persistence/Configurations/PackageConfiguration.cs new file mode 100644 index 0000000..d10f72b --- /dev/null +++ b/src/CMSMicroservice.Infrastructure/Persistence/Configurations/PackageConfiguration.cs @@ -0,0 +1,20 @@ +using CMSMicroservice.Domain.Entities; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace CMSMicroservice.Infrastructure.Persistence.Configurations; + +public class PackageConfiguration : IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder builder) + { + builder.HasQueryFilter(p => !p.IsDeleted); + builder.Ignore(entity => entity.DomainEvents); + builder.HasKey(entity => entity.Id); + builder.Property(entity => entity.Id).UseIdentityColumn(); + builder.Property(entity => entity.Title).IsRequired(true); + builder.Property(entity => entity.Description).IsRequired(true); + builder.Property(entity => entity.ImagePath).IsRequired(true); + builder.Property(entity => entity.Price).IsRequired(true); + } +} \ No newline at end of file diff --git a/src/CMSMicroservice.Infrastructure/Persistence/Configurations/RoleConfiguration.cs b/src/CMSMicroservice.Infrastructure/Persistence/Configurations/RoleConfiguration.cs new file mode 100644 index 0000000..696a8cf --- /dev/null +++ b/src/CMSMicroservice.Infrastructure/Persistence/Configurations/RoleConfiguration.cs @@ -0,0 +1,18 @@ +using CMSMicroservice.Domain.Entities; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace CMSMicroservice.Infrastructure.Persistence.Configurations; + +public class RoleConfiguration : IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder builder) + { + builder.HasQueryFilter(p => !p.IsDeleted); + builder.Ignore(entity => entity.DomainEvents); + builder.HasKey(entity => entity.Id); + builder.Property(entity => entity.Id).UseIdentityColumn(); + builder.Property(entity => entity.Name).IsRequired(true); + builder.Property(entity => entity.Title).IsRequired(true); + } +} \ No newline at end of file diff --git a/src/CMSMicroservice.Infrastructure/Persistence/Configurations/UserAddressConfiguration.cs b/src/CMSMicroservice.Infrastructure/Persistence/Configurations/UserAddressConfiguration.cs new file mode 100644 index 0000000..61167c9 --- /dev/null +++ b/src/CMSMicroservice.Infrastructure/Persistence/Configurations/UserAddressConfiguration.cs @@ -0,0 +1,26 @@ +using CMSMicroservice.Domain.Entities; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace CMSMicroservice.Infrastructure.Persistence.Configurations; + +public class UserAddressConfiguration : IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder builder) + { + builder.HasQueryFilter(p => !p.IsDeleted); + builder.Ignore(entity => entity.DomainEvents); + builder.HasKey(entity => entity.Id); + builder.Property(entity => entity.Id).UseIdentityColumn(); + builder + .HasOne(entity => entity.User) + .WithMany(entity => entity.UserAddresss) + .HasForeignKey(entity => entity.UserId) + .IsRequired(true); + builder.Property(entity => entity.Title).IsRequired(true); + builder.Property(entity => entity.Address).IsRequired(true); + builder.Property(entity => entity.PostalCode).IsRequired(true); + builder.Property(entity => entity.IsDefault).IsRequired(true); + builder.Property(entity => entity.CityId).IsRequired(true); + } +} \ No newline at end of file diff --git a/src/CMSMicroservice.Infrastructure/Persistence/Configurations/UserConfiguration.cs b/src/CMSMicroservice.Infrastructure/Persistence/Configurations/UserConfiguration.cs new file mode 100644 index 0000000..b69e77e --- /dev/null +++ b/src/CMSMicroservice.Infrastructure/Persistence/Configurations/UserConfiguration.cs @@ -0,0 +1,26 @@ +using CMSMicroservice.Domain.Entities; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace CMSMicroservice.Infrastructure.Persistence.Configurations; + +public class UserConfiguration : IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder builder) + { + builder.HasQueryFilter(p => !p.IsDeleted); + builder.Ignore(entity => entity.DomainEvents); + builder.HasKey(entity => entity.Id); + builder.Property(entity => entity.Id).UseIdentityColumn(); + builder.Property(entity => entity.FirstName).IsRequired(false); + builder.Property(entity => entity.LastName).IsRequired(false); + builder.Property(entity => entity.Mobile).IsRequired(true); + builder.Property(entity => entity.NationalCode).IsRequired(false); + builder.Property(entity => entity.AvatarPath).IsRequired(false); + builder + .HasOne(entity => entity.Parent) + .WithMany(entity => entity.Users) + .HasForeignKey(entity => entity.ParentId) + .IsRequired(false); + } +} \ No newline at end of file diff --git a/src/CMSMicroservice.Infrastructure/Persistence/Configurations/UserOrderConfiguration.cs b/src/CMSMicroservice.Infrastructure/Persistence/Configurations/UserOrderConfiguration.cs new file mode 100644 index 0000000..656ba1f --- /dev/null +++ b/src/CMSMicroservice.Infrastructure/Persistence/Configurations/UserOrderConfiguration.cs @@ -0,0 +1,30 @@ +using CMSMicroservice.Domain.Entities; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace CMSMicroservice.Infrastructure.Persistence.Configurations; + +public class UserOrderConfiguration : IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder builder) + { + builder.HasQueryFilter(p => !p.IsDeleted); + builder.Ignore(entity => entity.DomainEvents); + builder.HasKey(entity => entity.Id); + builder.Property(entity => entity.Id).UseIdentityColumn(); + builder.Property(entity => entity.Price).IsRequired(true); + builder + .HasOne(entity => entity.Package) + .WithMany(entity => entity.UserOrders) + .HasForeignKey(entity => entity.PackageId) + .IsRequired(true); + builder.Property(entity => entity.TransactionId).IsRequired(false); + builder.Property(entity => entity.PaymentStatus).IsRequired(true); + builder.Property(entity => entity.PaymentDate).IsRequired(false); + builder + .HasOne(entity => entity.User) + .WithMany(entity => entity.UserOrders) + .HasForeignKey(entity => entity.UserId) + .IsRequired(true); + } +} \ No newline at end of file diff --git a/src/CMSMicroservice.Infrastructure/Persistence/Configurations/UserRoleConfiguration.cs b/src/CMSMicroservice.Infrastructure/Persistence/Configurations/UserRoleConfiguration.cs new file mode 100644 index 0000000..717b2a3 --- /dev/null +++ b/src/CMSMicroservice.Infrastructure/Persistence/Configurations/UserRoleConfiguration.cs @@ -0,0 +1,26 @@ +using CMSMicroservice.Domain.Entities; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace CMSMicroservice.Infrastructure.Persistence.Configurations; + +public class UserRoleConfiguration : IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder builder) + { + builder.HasQueryFilter(p => !p.IsDeleted); + builder.Ignore(entity => entity.DomainEvents); + builder.HasKey(entity => entity.Id); + builder.Property(entity => entity.Id).UseIdentityColumn(); + builder + .HasOne(entity => entity.Role) + .WithMany(entity => entity.UserRoles) + .HasForeignKey(entity => entity.RoleId) + .IsRequired(true); + builder + .HasOne(entity => entity.User) + .WithMany(entity => entity.UserRoles) + .HasForeignKey(entity => entity.UserId) + .IsRequired(true); + } +} \ No newline at end of file diff --git a/src/CMSMicroservice.Infrastructure/Persistence/Interceptors/AuditableEntitySaveChangesInterceptor.cs b/src/CMSMicroservice.Infrastructure/Persistence/Interceptors/AuditableEntitySaveChangesInterceptor.cs new file mode 100644 index 0000000..6e426a5 --- /dev/null +++ b/src/CMSMicroservice.Infrastructure/Persistence/Interceptors/AuditableEntitySaveChangesInterceptor.cs @@ -0,0 +1,58 @@ +using CMSMicroservice.Application.Common.Interfaces; +using CMSMicroservice.Domain.Common; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.ChangeTracking; +using Microsoft.EntityFrameworkCore.Diagnostics; + +namespace CMSMicroservice.Infrastructure.Persistence.Interceptors; + +public class AuditableEntitySaveChangesInterceptor : SaveChangesInterceptor +{ + private readonly ICurrentUserService _currentUserService; + + public AuditableEntitySaveChangesInterceptor( + ICurrentUserService currentUserService) + { + _currentUserService = currentUserService; + } + public override InterceptionResult SavingChanges(DbContextEventData eventData, InterceptionResult result) + { + UpdateEntities(eventData.Context); + return base.SavingChanges(eventData, result); + } + + public override ValueTask> SavingChangesAsync(DbContextEventData eventData, InterceptionResult result, CancellationToken cancellationToken = default) + { + UpdateEntities(eventData.Context); + return base.SavingChangesAsync(eventData, result, cancellationToken); + } + + public void UpdateEntities(DbContext? context) + { + if (context == null) return; + + foreach (var entry in context.ChangeTracker.Entries()) + { + if (entry.State == EntityState.Added) + { + entry.Entity.CreatedBy = _currentUserService.UserId; + entry.Entity.Created = DateTime.Now; + } + + if (entry.State == EntityState.Added || entry.State == EntityState.Modified || entry.HasChangedOwnedEntities()) + { + entry.Entity.LastModifiedBy = _currentUserService.UserId; + entry.Entity.LastModified = DateTime.Now; + } + } + } + +} +public static class Extensions +{ + public static bool HasChangedOwnedEntities(this EntityEntry entry) => + entry.References.Any(r => + r.TargetEntry != null && + r.TargetEntry.Metadata.IsOwned() && + (r.TargetEntry.State == EntityState.Added || r.TargetEntry.State == EntityState.Modified)); +} \ No newline at end of file diff --git a/src/CMSMicroservice.Protobuf/CMSMicroservice.Protobuf.csproj b/src/CMSMicroservice.Protobuf/CMSMicroservice.Protobuf.csproj new file mode 100644 index 0000000..3eaba99 --- /dev/null +++ b/src/CMSMicroservice.Protobuf/CMSMicroservice.Protobuf.csproj @@ -0,0 +1,33 @@ + + + + net7.0 + enable + enable + 1.0.0 + None + False + False + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + + + + + + + + diff --git a/src/CMSMicroservice.Protobuf/ConfigureServices.cs b/src/CMSMicroservice.Protobuf/ConfigureServices.cs new file mode 100644 index 0000000..f506871 --- /dev/null +++ b/src/CMSMicroservice.Protobuf/ConfigureServices.cs @@ -0,0 +1,14 @@ +using FluentValidation; +using System.Reflection; + +namespace Microsoft.Extensions.DependencyInjection; + +public static class ConfigureServices +{ + public static IServiceCollection AddProtobufServices(this IServiceCollection services) + { + services.AddValidatorsFromAssembly(Assembly.GetExecutingAssembly()); + return services; + } +} + diff --git a/src/CMSMicroservice.Protobuf/Protos/google/api/annotations.proto b/src/CMSMicroservice.Protobuf/Protos/google/api/annotations.proto new file mode 100644 index 0000000..85c361b --- /dev/null +++ b/src/CMSMicroservice.Protobuf/Protos/google/api/annotations.proto @@ -0,0 +1,31 @@ +// Copyright (c) 2015, Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.api; + +import "google/api/http.proto"; +import "google/protobuf/descriptor.proto"; + +option go_package = "google.golang.org/genproto/googleapis/api/annotations;annotations"; +option java_multiple_files = true; +option java_outer_classname = "AnnotationsProto"; +option java_package = "com.google.api"; +option objc_class_prefix = "GAPI"; + +extend google.protobuf.MethodOptions { + // See `HttpRule`. + HttpRule http = 72295728; +} diff --git a/src/CMSMicroservice.Protobuf/Protos/google/api/http.proto b/src/CMSMicroservice.Protobuf/Protos/google/api/http.proto new file mode 100644 index 0000000..b8426ba --- /dev/null +++ b/src/CMSMicroservice.Protobuf/Protos/google/api/http.proto @@ -0,0 +1,377 @@ +// Copyright 2019 Google LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +syntax = "proto3"; + +package google.api; + +option cc_enable_arenas = true; +option go_package = "google.golang.org/genproto/googleapis/api/annotations;annotations"; +option java_multiple_files = true; +option java_outer_classname = "HttpProto"; +option java_package = "com.google.api"; +option objc_class_prefix = "GAPI"; + +// Defines the HTTP configuration for an API service. It contains a list of +// [HttpRule][google.api.HttpRule], each specifying the mapping of an RPC method +// to one or more HTTP REST API methods. +message Http { + // A list of HTTP configuration rules that apply to individual API methods. + // + // **NOTE:** All service configuration rules follow "last one wins" order. + repeated HttpRule rules = 1; + + // When set to true, URL path parameters will be fully URI-decoded except in + // cases of single segment matches in reserved expansion, where "%2F" will be + // left encoded. + // + // The default behavior is to not decode RFC 6570 reserved characters in multi + // segment matches. + bool fully_decode_reserved_expansion = 2; +} + +// # gRPC Transcoding +// +// gRPC Transcoding is a feature for mapping between a gRPC method and one or +// more HTTP REST endpoints. It allows developers to build a single API service +// that supports both gRPC APIs and REST APIs. Many systems, including [Google +// APIs](https://github.com/googleapis/googleapis), +// [Cloud Endpoints](https://cloud.google.com/endpoints), [gRPC +// Gateway](https://github.com/grpc-ecosystem/grpc-gateway), +// and [Envoy](https://github.com/envoyproxy/envoy) proxy support this feature +// and use it for large scale production services. +// +// `HttpRule` defines the schema of the gRPC/REST mapping. The mapping specifies +// how different portions of the gRPC request message are mapped to the URL +// path, URL query parameters, and HTTP request body. It also controls how the +// gRPC response message is mapped to the HTTP response body. `HttpRule` is +// typically specified as an `google.api.http` annotation on the gRPC method. +// +// Each mapping specifies a URL path template and an HTTP method. The path +// template may refer to one or more fields in the gRPC request message, as long +// as each field is a non-repeated field with a primitive (non-message) type. +// The path template controls how fields of the request message are mapped to +// the URL path. +// +// Example: +// +// service Messaging { +// rpc GetMessage(GetMessageRequest) returns (Message) { +// option (google.api.http) = { +// get: "/v1/{name=messages/*}" +// }; +// } +// } +// message GetMessageRequest { +// string name = 1; // Mapped to URL path. +// } +// message Message { +// string text = 1; // The resource content. +// } +// +// This enables an HTTP REST to gRPC mapping as below: +// +// HTTP | gRPC +// -----|----- +// `GET /v1/messages/123456` | `GetMessage(name: "messages/123456")` +// +// Any fields in the request message which are not bound by the path template +// automatically become HTTP query parameters if there is no HTTP request body. +// For example: +// +// service Messaging { +// rpc GetMessage(GetMessageRequest) returns (Message) { +// option (google.api.http) = { +// get:"/v1/messages/{message_id}" +// }; +// } +// } +// message GetMessageRequest { +// message SubMessage { +// string subfield = 1; +// } +// string message_id = 1; // Mapped to URL path. +// int64 revision = 2; // Mapped to URL query parameter `revision`. +// SubMessage sub = 3; // Mapped to URL query parameter `sub.subfield`. +// } +// +// This enables a HTTP JSON to RPC mapping as below: +// +// HTTP | gRPC +// -----|----- +// `GET /v1/messages/123456?revision=2&sub.subfield=foo` | +// `GetMessage(message_id: "123456" revision: 2 sub: SubMessage(subfield: +// "foo"))` +// +// Note that fields which are mapped to URL query parameters must have a +// primitive type or a repeated primitive type or a non-repeated message type. +// In the case of a repeated type, the parameter can be repeated in the URL +// as `...?param=A¶m=B`. In the case of a message type, each field of the +// message is mapped to a separate parameter, such as +// `...?foo.a=A&foo.b=B&foo.c=C`. +// +// For HTTP methods that allow a request body, the `body` field +// specifies the mapping. Consider a REST update method on the +// message resource collection: +// +// service Messaging { +// rpc UpdateMessage(UpdateMessageRequest) returns (Message) { +// option (google.api.http) = { +// patch: "/v1/messages/{message_id}" +// body: "message" +// }; +// } +// } +// message UpdateMessageRequest { +// string message_id = 1; // mapped to the URL +// Message message = 2; // mapped to the body +// } +// +// The following HTTP JSON to RPC mapping is enabled, where the +// representation of the JSON in the request body is determined by +// protos JSON encoding: +// +// HTTP | gRPC +// -----|----- +// `PATCH /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: +// "123456" message { text: "Hi!" })` +// +// The special name `*` can be used in the body mapping to define that +// every field not bound by the path template should be mapped to the +// request body. This enables the following alternative definition of +// the update method: +// +// service Messaging { +// rpc UpdateMessage(Message) returns (Message) { +// option (google.api.http) = { +// patch: "/v1/messages/{message_id}" +// body: "*" +// }; +// } +// } +// message Message { +// string message_id = 1; +// string text = 2; +// } +// +// +// The following HTTP JSON to RPC mapping is enabled: +// +// HTTP | gRPC +// -----|----- +// `PATCH /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: +// "123456" text: "Hi!")` +// +// Note that when using `*` in the body mapping, it is not possible to +// have HTTP parameters, as all fields not bound by the path end in +// the body. This makes this option more rarely used in practice when +// defining REST APIs. The common usage of `*` is in custom methods +// which don't use the URL at all for transferring data. +// +// It is possible to define multiple HTTP methods for one RPC by using +// the `additional_bindings` option. Example: +// +// service Messaging { +// rpc GetMessage(GetMessageRequest) returns (Message) { +// option (google.api.http) = { +// get: "/v1/messages/{message_id}" +// additional_bindings { +// get: "/v1/users/{user_id}/messages/{message_id}" +// } +// }; +// } +// } +// message GetMessageRequest { +// string message_id = 1; +// string user_id = 2; +// } +// +// This enables the following two alternative HTTP JSON to RPC mappings: +// +// HTTP | gRPC +// -----|----- +// `GET /v1/messages/123456` | `GetMessage(message_id: "123456")` +// `GET /v1/users/me/messages/123456` | `GetMessage(user_id: "me" message_id: +// "123456")` +// +// ## Rules for HTTP mapping +// +// 1. Leaf request fields (recursive expansion nested messages in the request +// message) are classified into three categories: +// - Fields referred by the path template. They are passed via the URL path. +// - Fields referred by the [HttpRule.body][google.api.HttpRule.body]. They are passed via the HTTP +// request body. +// - All other fields are passed via the URL query parameters, and the +// parameter name is the field path in the request message. A repeated +// field can be represented as multiple query parameters under the same +// name. +// 2. If [HttpRule.body][google.api.HttpRule.body] is "*", there is no URL query parameter, all fields +// are passed via URL path and HTTP request body. +// 3. If [HttpRule.body][google.api.HttpRule.body] is omitted, there is no HTTP request body, all +// fields are passed via URL path and URL query parameters. +// +// ### Path template syntax +// +// Template = "/" Segments [ Verb ] ; +// Segments = Segment { "/" Segment } ; +// Segment = "*" | "**" | LITERAL | Variable ; +// Variable = "{" FieldPath [ "=" Segments ] "}" ; +// FieldPath = IDENT { "." IDENT } ; +// Verb = ":" LITERAL ; +// +// The syntax `*` matches a single URL path segment. The syntax `**` matches +// zero or more URL path segments, which must be the last part of the URL path +// except the `Verb`. +// +// The syntax `Variable` matches part of the URL path as specified by its +// template. A variable template must not contain other variables. If a variable +// matches a single path segment, its template may be omitted, e.g. `{var}` +// is equivalent to `{var=*}`. +// +// The syntax `LITERAL` matches literal text in the URL path. If the `LITERAL` +// contains any reserved character, such characters should be percent-encoded +// before the matching. +// +// If a variable contains exactly one path segment, such as `"{var}"` or +// `"{var=*}"`, when such a variable is expanded into a URL path on the client +// side, all characters except `[-_.~0-9a-zA-Z]` are percent-encoded. The +// server side does the reverse decoding. Such variables show up in the +// [Discovery +// Document](https://developers.google.com/discovery/v1/reference/apis) as +// `{var}`. +// +// If a variable contains multiple path segments, such as `"{var=foo/*}"` +// or `"{var=**}"`, when such a variable is expanded into a URL path on the +// client side, all characters except `[-_.~/0-9a-zA-Z]` are percent-encoded. +// The server side does the reverse decoding, except "%2F" and "%2f" are left +// unchanged. Such variables show up in the +// [Discovery +// Document](https://developers.google.com/discovery/v1/reference/apis) as +// `{+var}`. +// +// ## Using gRPC API Service Configuration +// +// gRPC API Service Configuration (service config) is a configuration language +// for configuring a gRPC service to become a user-facing product. The +// service config is simply the YAML representation of the `google.api.Service` +// proto message. +// +// As an alternative to annotating your proto file, you can configure gRPC +// transcoding in your service config YAML files. You do this by specifying a +// `HttpRule` that maps the gRPC method to a REST endpoint, achieving the same +// effect as the proto annotation. This can be particularly useful if you +// have a proto that is reused in multiple services. Note that any transcoding +// specified in the service config will override any matching transcoding +// configuration in the proto. +// +// Example: +// +// http: +// rules: +// # Selects a gRPC method and applies HttpRule to it. +// - selector: example.v1.Messaging.GetMessage +// get: /v1/messages/{message_id}/{sub.subfield} +// +// ## Special notes +// +// When gRPC Transcoding is used to map a gRPC to JSON REST endpoints, the +// proto to JSON conversion must follow the [proto3 +// specification](https://developers.google.com/protocol-buffers/docs/proto3#json). +// +// While the single segment variable follows the semantics of +// [RFC 6570](https://tools.ietf.org/html/rfc6570) Section 3.2.2 Simple String +// Expansion, the multi segment variable **does not** follow RFC 6570 Section +// 3.2.3 Reserved Expansion. The reason is that the Reserved Expansion +// does not expand special characters like `?` and `#`, which would lead +// to invalid URLs. As the result, gRPC Transcoding uses a custom encoding +// for multi segment variables. +// +// The path variables **must not** refer to any repeated or mapped field, +// because client libraries are not capable of handling such variable expansion. +// +// The path variables **must not** capture the leading "/" character. The reason +// is that the most common use case "{var}" does not capture the leading "/" +// character. For consistency, all path variables must share the same behavior. +// +// Repeated message fields must not be mapped to URL query parameters, because +// no client library can support such complicated mapping. +// +// If an API needs to use a JSON array for request or response body, it can map +// the request or response body to a repeated field. However, some gRPC +// Transcoding implementations may not support this feature. +message HttpRule { + // Selects a method to which this rule applies. + // + // Refer to [selector][google.api.DocumentationRule.selector] for syntax details. + string selector = 1; + + // Determines the URL pattern is matched by this rules. This pattern can be + // used with any of the {get|put|post|delete|patch} methods. A custom method + // can be defined using the 'custom' field. + oneof pattern { + // Maps to HTTP GET. Used for listing and getting information about + // resources. + string get = 2; + + // Maps to HTTP PUT. Used for replacing a resource. + string put = 3; + + // Maps to HTTP POST. Used for creating a resource or performing an action. + string post = 4; + + // Maps to HTTP DELETE. Used for deleting a resource. + string delete = 5; + + // Maps to HTTP PATCH. Used for updating a resource. + string patch = 6; + + // The custom pattern is used for specifying an HTTP method that is not + // included in the `pattern` field, such as HEAD, or "*" to leave the + // HTTP method unspecified for this rule. The wild-card rule is useful + // for services that provide content to Web (HTML) clients. + CustomHttpPattern custom = 8; + } + + // The name of the request field whose value is mapped to the HTTP request + // body, or `*` for mapping all request fields not captured by the path + // pattern to the HTTP body, or omitted for not having any HTTP request body. + // + // NOTE: the referred field must be present at the top-level of the request + // message type. + string body = 7; + + // Optional. The name of the response field whose value is mapped to the HTTP + // response body. When omitted, the entire response message will be used + // as the HTTP response body. + // + // NOTE: The referred field must be present at the top-level of the response + // message type. + string response_body = 12; + + // Additional HTTP bindings for the selector. Nested bindings must + // not contain an `additional_bindings` field themselves (that is, + // the nesting may only be one level deep). + repeated HttpRule additional_bindings = 11; +} + +// A custom pattern is used for defining custom HTTP verb. +message CustomHttpPattern { + // The name of this custom HTTP verb. + string kind = 1; + + // The path matched by this custom verb. + string path = 2; +} + diff --git a/src/CMSMicroservice.Protobuf/Protos/package.proto b/src/CMSMicroservice.Protobuf/Protos/package.proto new file mode 100644 index 0000000..6424de0 --- /dev/null +++ b/src/CMSMicroservice.Protobuf/Protos/package.proto @@ -0,0 +1,108 @@ +syntax = "proto3"; + +package package; + +import "public_messages.proto"; +import "google/protobuf/empty.proto"; +import "google/protobuf/wrappers.proto"; +import "google/protobuf/duration.proto"; +import "google/protobuf/timestamp.proto"; +import "google/api/annotations.proto"; + +option csharp_namespace = "CMSMicroservice.Protobuf.Protos.Package"; + +service PackageContract +{ + rpc CreateNewPackage(CreateNewPackageRequest) returns (CreateNewPackageResponse){ + option (google.api.http) = { + post: "/CreateNewPackage" + body: "*" + }; + }; + rpc UpdatePackage(UpdatePackageRequest) returns (google.protobuf.Empty){ + option (google.api.http) = { + put: "/UpdatePackage" + body: "*" + }; + }; + rpc DeletePackage(DeletePackageRequest) returns (google.protobuf.Empty){ + option (google.api.http) = { + delete: "/DeletePackage" + body: "*" + }; + }; + rpc GetPackage(GetPackageRequest) returns (GetPackageResponse){ + option (google.api.http) = { + get: "/GetPackage" + + }; + }; + rpc GetAllPackageByFilter(GetAllPackageByFilterRequest) returns (GetAllPackageByFilterResponse){ + option (google.api.http) = { + get: "/GetAllPackageByFilter" + + }; + }; +} +message CreateNewPackageRequest +{ + string title = 1; + string description = 2; + string image_path = 3; + int64 price = 4; +} +message CreateNewPackageResponse +{ + int64 id = 1; +} +message UpdatePackageRequest +{ + int64 id = 1; + string title = 2; + string description = 3; + string image_path = 4; + int64 price = 5; +} +message DeletePackageRequest +{ + int64 id = 1; +} +message GetPackageRequest +{ + int64 id = 1; +} +message GetPackageResponse +{ + int64 id = 1; + string title = 2; + string description = 3; + string image_path = 4; + int64 price = 5; +} +message GetAllPackageByFilterRequest +{ + messages.PaginationState pagination_state = 1; + google.protobuf.StringValue sort_by = 2; + GetAllPackageByFilterFilter filter = 3; +} +message GetAllPackageByFilterFilter +{ + google.protobuf.Int64Value id = 1; + google.protobuf.StringValue title = 2; + google.protobuf.StringValue description = 3; + google.protobuf.StringValue image_path = 4; + google.protobuf.Int64Value price = 5; +} +message GetAllPackageByFilterResponse +{ + messages.MetaData meta_data = 1; + repeated GetAllPackageByFilterResponseModel models = 2; +} +message GetAllPackageByFilterResponseModel +{ + int64 id = 1; + string title = 2; + string description = 3; + string image_path = 4; + int64 price = 5; +} diff --git a/src/CMSMicroservice.Protobuf/Protos/public_messages.proto b/src/CMSMicroservice.Protobuf/Protos/public_messages.proto new file mode 100644 index 0000000..6b907cb --- /dev/null +++ b/src/CMSMicroservice.Protobuf/Protos/public_messages.proto @@ -0,0 +1,33 @@ +syntax = "proto3"; + +package messages; + +option csharp_namespace = "CMSMicroservice.Protobuf.Protos"; +service PublicMessageContract{} +message PaginationState +{ + int32 page_number = 1; + + int32 page_size = 2; +} +message MetaData +{ + int64 current_page = 1; + + int64 total_page = 2; + + int64 page_size = 3; + + int64 total_count = 4; + + bool has_previous = 5; + + bool has_next = 6; +} +message DecimalValue +{ + + int64 units = 1; + + sfixed32 nanos = 2; +} diff --git a/src/CMSMicroservice.Protobuf/Protos/role.proto b/src/CMSMicroservice.Protobuf/Protos/role.proto new file mode 100644 index 0000000..92c6d00 --- /dev/null +++ b/src/CMSMicroservice.Protobuf/Protos/role.proto @@ -0,0 +1,98 @@ +syntax = "proto3"; + +package role; + +import "public_messages.proto"; +import "google/protobuf/empty.proto"; +import "google/protobuf/wrappers.proto"; +import "google/protobuf/duration.proto"; +import "google/protobuf/timestamp.proto"; +import "google/api/annotations.proto"; + +option csharp_namespace = "CMSMicroservice.Protobuf.Protos.Role"; + +service RoleContract +{ + rpc CreateNewRole(CreateNewRoleRequest) returns (CreateNewRoleResponse){ + option (google.api.http) = { + post: "/CreateNewRole" + body: "*" + }; + }; + rpc UpdateRole(UpdateRoleRequest) returns (google.protobuf.Empty){ + option (google.api.http) = { + put: "/UpdateRole" + body: "*" + }; + }; + rpc DeleteRole(DeleteRoleRequest) returns (google.protobuf.Empty){ + option (google.api.http) = { + delete: "/DeleteRole" + body: "*" + }; + }; + rpc GetRole(GetRoleRequest) returns (GetRoleResponse){ + option (google.api.http) = { + get: "/GetRole" + + }; + }; + rpc GetAllRoleByFilter(GetAllRoleByFilterRequest) returns (GetAllRoleByFilterResponse){ + option (google.api.http) = { + get: "/GetAllRoleByFilter" + + }; + }; +} +message CreateNewRoleRequest +{ + string name = 1; + string title = 2; +} +message CreateNewRoleResponse +{ + int64 id = 1; +} +message UpdateRoleRequest +{ + int64 id = 1; + string name = 2; + string title = 3; +} +message DeleteRoleRequest +{ + int64 id = 1; +} +message GetRoleRequest +{ + int64 id = 1; +} +message GetRoleResponse +{ + int64 id = 1; + string name = 2; + string title = 3; +} +message GetAllRoleByFilterRequest +{ + messages.PaginationState pagination_state = 1; + google.protobuf.StringValue sort_by = 2; + GetAllRoleByFilterFilter filter = 3; +} +message GetAllRoleByFilterFilter +{ + google.protobuf.Int64Value id = 1; + google.protobuf.StringValue name = 2; + google.protobuf.StringValue title = 3; +} +message GetAllRoleByFilterResponse +{ + messages.MetaData meta_data = 1; + repeated GetAllRoleByFilterResponseModel models = 2; +} +message GetAllRoleByFilterResponseModel +{ + int64 id = 1; + string name = 2; + string title = 3; +} diff --git a/src/CMSMicroservice.Protobuf/Protos/user.proto b/src/CMSMicroservice.Protobuf/Protos/user.proto new file mode 100644 index 0000000..0af6c13 --- /dev/null +++ b/src/CMSMicroservice.Protobuf/Protos/user.proto @@ -0,0 +1,118 @@ +syntax = "proto3"; + +package user; + +import "public_messages.proto"; +import "google/protobuf/empty.proto"; +import "google/protobuf/wrappers.proto"; +import "google/protobuf/duration.proto"; +import "google/protobuf/timestamp.proto"; +import "google/api/annotations.proto"; + +option csharp_namespace = "CMSMicroservice.Protobuf.Protos.User"; + +service UserContract +{ + rpc CreateNewUser(CreateNewUserRequest) returns (CreateNewUserResponse){ + option (google.api.http) = { + post: "/CreateNewUser" + body: "*" + }; + }; + rpc UpdateUser(UpdateUserRequest) returns (google.protobuf.Empty){ + option (google.api.http) = { + put: "/UpdateUser" + body: "*" + }; + }; + rpc DeleteUser(DeleteUserRequest) returns (google.protobuf.Empty){ + option (google.api.http) = { + delete: "/DeleteUser" + body: "*" + }; + }; + rpc GetUser(GetUserRequest) returns (GetUserResponse){ + option (google.api.http) = { + get: "/GetUser" + + }; + }; + rpc GetAllUserByFilter(GetAllUserByFilterRequest) returns (GetAllUserByFilterResponse){ + option (google.api.http) = { + get: "/GetAllUserByFilter" + + }; + }; +} +message CreateNewUserRequest +{ + google.protobuf.StringValue first_name = 1; + google.protobuf.StringValue last_name = 2; + string mobile = 3; + google.protobuf.StringValue national_code = 4; + google.protobuf.StringValue avatar_path = 5; + google.protobuf.Int64Value parent_id = 6; +} +message CreateNewUserResponse +{ + int64 id = 1; +} +message UpdateUserRequest +{ + int64 id = 1; + google.protobuf.StringValue first_name = 2; + google.protobuf.StringValue last_name = 3; + string mobile = 4; + google.protobuf.StringValue national_code = 5; + google.protobuf.StringValue avatar_path = 6; + google.protobuf.Int64Value parent_id = 7; +} +message DeleteUserRequest +{ + int64 id = 1; +} +message GetUserRequest +{ + int64 id = 1; +} +message GetUserResponse +{ + int64 id = 1; + google.protobuf.StringValue first_name = 2; + google.protobuf.StringValue last_name = 3; + string mobile = 4; + google.protobuf.StringValue national_code = 5; + google.protobuf.StringValue avatar_path = 6; + google.protobuf.Int64Value parent_id = 7; +} +message GetAllUserByFilterRequest +{ + messages.PaginationState pagination_state = 1; + google.protobuf.StringValue sort_by = 2; + GetAllUserByFilterFilter filter = 3; +} +message GetAllUserByFilterFilter +{ + google.protobuf.Int64Value id = 1; + google.protobuf.StringValue first_name = 2; + google.protobuf.StringValue last_name = 3; + google.protobuf.StringValue mobile = 4; + google.protobuf.StringValue national_code = 5; + google.protobuf.StringValue avatar_path = 6; + google.protobuf.Int64Value parent_id = 7; +} +message GetAllUserByFilterResponse +{ + messages.MetaData meta_data = 1; + repeated GetAllUserByFilterResponseModel models = 2; +} +message GetAllUserByFilterResponseModel +{ + int64 id = 1; + google.protobuf.StringValue first_name = 2; + google.protobuf.StringValue last_name = 3; + string mobile = 4; + google.protobuf.StringValue national_code = 5; + google.protobuf.StringValue avatar_path = 6; + google.protobuf.Int64Value parent_id = 7; +} diff --git a/src/CMSMicroservice.Protobuf/Protos/useraddress.proto b/src/CMSMicroservice.Protobuf/Protos/useraddress.proto new file mode 100644 index 0000000..c918159 --- /dev/null +++ b/src/CMSMicroservice.Protobuf/Protos/useraddress.proto @@ -0,0 +1,118 @@ +syntax = "proto3"; + +package useraddress; + +import "public_messages.proto"; +import "google/protobuf/empty.proto"; +import "google/protobuf/wrappers.proto"; +import "google/protobuf/duration.proto"; +import "google/protobuf/timestamp.proto"; +import "google/api/annotations.proto"; + +option csharp_namespace = "CMSMicroservice.Protobuf.Protos.UserAddress"; + +service UserAddressContract +{ + rpc CreateNewUserAddress(CreateNewUserAddressRequest) returns (CreateNewUserAddressResponse){ + option (google.api.http) = { + post: "/CreateNewUserAddress" + body: "*" + }; + }; + rpc UpdateUserAddress(UpdateUserAddressRequest) returns (google.protobuf.Empty){ + option (google.api.http) = { + put: "/UpdateUserAddress" + body: "*" + }; + }; + rpc DeleteUserAddress(DeleteUserAddressRequest) returns (google.protobuf.Empty){ + option (google.api.http) = { + delete: "/DeleteUserAddress" + body: "*" + }; + }; + rpc GetUserAddress(GetUserAddressRequest) returns (GetUserAddressResponse){ + option (google.api.http) = { + get: "/GetUserAddress" + + }; + }; + rpc GetAllUserAddressByFilter(GetAllUserAddressByFilterRequest) returns (GetAllUserAddressByFilterResponse){ + option (google.api.http) = { + get: "/GetAllUserAddressByFilter" + + }; + }; +} +message CreateNewUserAddressRequest +{ + int64 user_id = 1; + string title = 2; + string address = 3; + string postal_code = 4; + bool is_default = 5; + int64 city_id = 6; +} +message CreateNewUserAddressResponse +{ + int64 id = 1; +} +message UpdateUserAddressRequest +{ + int64 id = 1; + int64 user_id = 2; + string title = 3; + string address = 4; + string postal_code = 5; + bool is_default = 6; + int64 city_id = 7; +} +message DeleteUserAddressRequest +{ + int64 id = 1; +} +message GetUserAddressRequest +{ + int64 id = 1; +} +message GetUserAddressResponse +{ + int64 id = 1; + int64 user_id = 2; + string title = 3; + string address = 4; + string postal_code = 5; + bool is_default = 6; + int64 city_id = 7; +} +message GetAllUserAddressByFilterRequest +{ + messages.PaginationState pagination_state = 1; + google.protobuf.StringValue sort_by = 2; + GetAllUserAddressByFilterFilter filter = 3; +} +message GetAllUserAddressByFilterFilter +{ + google.protobuf.Int64Value id = 1; + google.protobuf.Int64Value user_id = 2; + google.protobuf.StringValue title = 3; + google.protobuf.StringValue address = 4; + google.protobuf.StringValue postal_code = 5; + google.protobuf.BoolValue is_default = 6; + google.protobuf.Int64Value city_id = 7; +} +message GetAllUserAddressByFilterResponse +{ + messages.MetaData meta_data = 1; + repeated GetAllUserAddressByFilterResponseModel models = 2; +} +message GetAllUserAddressByFilterResponseModel +{ + int64 id = 1; + int64 user_id = 2; + string title = 3; + string address = 4; + string postal_code = 5; + bool is_default = 6; + int64 city_id = 7; +} diff --git a/src/CMSMicroservice.Protobuf/Protos/userorder.proto b/src/CMSMicroservice.Protobuf/Protos/userorder.proto new file mode 100644 index 0000000..f2c98e9 --- /dev/null +++ b/src/CMSMicroservice.Protobuf/Protos/userorder.proto @@ -0,0 +1,118 @@ +syntax = "proto3"; + +package userorder; + +import "public_messages.proto"; +import "google/protobuf/empty.proto"; +import "google/protobuf/wrappers.proto"; +import "google/protobuf/duration.proto"; +import "google/protobuf/timestamp.proto"; +import "google/api/annotations.proto"; + +option csharp_namespace = "CMSMicroservice.Protobuf.Protos.UserOrder"; + +service UserOrderContract +{ + rpc CreateNewUserOrder(CreateNewUserOrderRequest) returns (CreateNewUserOrderResponse){ + option (google.api.http) = { + post: "/CreateNewUserOrder" + body: "*" + }; + }; + rpc UpdateUserOrder(UpdateUserOrderRequest) returns (google.protobuf.Empty){ + option (google.api.http) = { + put: "/UpdateUserOrder" + body: "*" + }; + }; + rpc DeleteUserOrder(DeleteUserOrderRequest) returns (google.protobuf.Empty){ + option (google.api.http) = { + delete: "/DeleteUserOrder" + body: "*" + }; + }; + rpc GetUserOrder(GetUserOrderRequest) returns (GetUserOrderResponse){ + option (google.api.http) = { + get: "/GetUserOrder" + + }; + }; + rpc GetAllUserOrderByFilter(GetAllUserOrderByFilterRequest) returns (GetAllUserOrderByFilterResponse){ + option (google.api.http) = { + get: "/GetAllUserOrderByFilter" + + }; + }; +} +message CreateNewUserOrderRequest +{ + int64 price = 1; + int64 package_id = 2; + google.protobuf.Int64Value transaction_id = 3; + bool payment_status = 4; + google.protobuf.Timestamp payment_date = 5; + int64 user_id = 6; +} +message CreateNewUserOrderResponse +{ + int64 id = 1; +} +message UpdateUserOrderRequest +{ + int64 id = 1; + int64 price = 2; + int64 package_id = 3; + google.protobuf.Int64Value transaction_id = 4; + bool payment_status = 5; + google.protobuf.Timestamp payment_date = 6; + int64 user_id = 7; +} +message DeleteUserOrderRequest +{ + int64 id = 1; +} +message GetUserOrderRequest +{ + int64 id = 1; +} +message GetUserOrderResponse +{ + int64 id = 1; + int64 price = 2; + int64 package_id = 3; + google.protobuf.Int64Value transaction_id = 4; + bool payment_status = 5; + google.protobuf.Timestamp payment_date = 6; + int64 user_id = 7; +} +message GetAllUserOrderByFilterRequest +{ + messages.PaginationState pagination_state = 1; + google.protobuf.StringValue sort_by = 2; + GetAllUserOrderByFilterFilter filter = 3; +} +message GetAllUserOrderByFilterFilter +{ + google.protobuf.Int64Value id = 1; + google.protobuf.Int64Value price = 2; + google.protobuf.Int64Value package_id = 3; + google.protobuf.Int64Value transaction_id = 4; + google.protobuf.BoolValue payment_status = 5; + google.protobuf.Timestamp payment_date = 6; + google.protobuf.Int64Value user_id = 7; +} +message GetAllUserOrderByFilterResponse +{ + messages.MetaData meta_data = 1; + repeated GetAllUserOrderByFilterResponseModel models = 2; +} +message GetAllUserOrderByFilterResponseModel +{ + int64 id = 1; + int64 price = 2; + int64 package_id = 3; + google.protobuf.Int64Value transaction_id = 4; + bool payment_status = 5; + google.protobuf.Timestamp payment_date = 6; + int64 user_id = 7; +} diff --git a/src/CMSMicroservice.Protobuf/Protos/userrole.proto b/src/CMSMicroservice.Protobuf/Protos/userrole.proto new file mode 100644 index 0000000..602c1a4 --- /dev/null +++ b/src/CMSMicroservice.Protobuf/Protos/userrole.proto @@ -0,0 +1,98 @@ +syntax = "proto3"; + +package userrole; + +import "public_messages.proto"; +import "google/protobuf/empty.proto"; +import "google/protobuf/wrappers.proto"; +import "google/protobuf/duration.proto"; +import "google/protobuf/timestamp.proto"; +import "google/api/annotations.proto"; + +option csharp_namespace = "CMSMicroservice.Protobuf.Protos.UserRole"; + +service UserRoleContract +{ + rpc CreateNewUserRole(CreateNewUserRoleRequest) returns (CreateNewUserRoleResponse){ + option (google.api.http) = { + post: "/CreateNewUserRole" + body: "*" + }; + }; + rpc UpdateUserRole(UpdateUserRoleRequest) returns (google.protobuf.Empty){ + option (google.api.http) = { + put: "/UpdateUserRole" + body: "*" + }; + }; + rpc DeleteUserRole(DeleteUserRoleRequest) returns (google.protobuf.Empty){ + option (google.api.http) = { + delete: "/DeleteUserRole" + body: "*" + }; + }; + rpc GetUserRole(GetUserRoleRequest) returns (GetUserRoleResponse){ + option (google.api.http) = { + get: "/GetUserRole" + + }; + }; + rpc GetAllUserRoleByFilter(GetAllUserRoleByFilterRequest) returns (GetAllUserRoleByFilterResponse){ + option (google.api.http) = { + get: "/GetAllUserRoleByFilter" + + }; + }; +} +message CreateNewUserRoleRequest +{ + int64 role_id = 1; + int64 user_id = 2; +} +message CreateNewUserRoleResponse +{ + int64 id = 1; +} +message UpdateUserRoleRequest +{ + int64 id = 1; + int64 role_id = 2; + int64 user_id = 3; +} +message DeleteUserRoleRequest +{ + int64 id = 1; +} +message GetUserRoleRequest +{ + int64 id = 1; +} +message GetUserRoleResponse +{ + int64 id = 1; + int64 role_id = 2; + int64 user_id = 3; +} +message GetAllUserRoleByFilterRequest +{ + messages.PaginationState pagination_state = 1; + google.protobuf.StringValue sort_by = 2; + GetAllUserRoleByFilterFilter filter = 3; +} +message GetAllUserRoleByFilterFilter +{ + google.protobuf.Int64Value id = 1; + google.protobuf.Int64Value role_id = 2; + google.protobuf.Int64Value user_id = 3; +} +message GetAllUserRoleByFilterResponse +{ + messages.MetaData meta_data = 1; + repeated GetAllUserRoleByFilterResponseModel models = 2; +} +message GetAllUserRoleByFilterResponseModel +{ + int64 id = 1; + int64 role_id = 2; + int64 user_id = 3; +} diff --git a/src/CMSMicroservice.Protobuf/Validator/Package/CreateNewPackageRequestValidator.cs b/src/CMSMicroservice.Protobuf/Validator/Package/CreateNewPackageRequestValidator.cs new file mode 100644 index 0000000..d587940 --- /dev/null +++ b/src/CMSMicroservice.Protobuf/Validator/Package/CreateNewPackageRequestValidator.cs @@ -0,0 +1,25 @@ +using FluentValidation; +using CMSMicroservice.Protobuf.Protos.Package; +namespace CMSMicroservice.Protobuf.Validator.Package; + +public class CreateNewPackageRequestValidator : AbstractValidator +{ + public CreateNewPackageRequestValidator() + { + RuleFor(model => model.Title) + .NotEmpty(); + RuleFor(model => model.Description) + .NotEmpty(); + RuleFor(model => model.ImagePath) + .NotEmpty(); + RuleFor(model => model.Price) + .NotNull(); + } + public Func>> ValidateValue => async (model, propertyName) => + { + var result = await ValidateAsync(ValidationContext.CreateWithOptions((CreateNewPackageRequest)model, x => x.IncludeProperties(propertyName))); + if (result.IsValid) + return Array.Empty(); + return result.Errors.Select(e => e.ErrorMessage); + }; +} diff --git a/src/CMSMicroservice.Protobuf/Validator/Package/DeletePackageRequestValidator.cs b/src/CMSMicroservice.Protobuf/Validator/Package/DeletePackageRequestValidator.cs new file mode 100644 index 0000000..c904f24 --- /dev/null +++ b/src/CMSMicroservice.Protobuf/Validator/Package/DeletePackageRequestValidator.cs @@ -0,0 +1,19 @@ +using FluentValidation; +using CMSMicroservice.Protobuf.Protos.Package; +namespace CMSMicroservice.Protobuf.Validator.Package; + +public class DeletePackageRequestValidator : AbstractValidator +{ + public DeletePackageRequestValidator() + { + RuleFor(model => model.Id) + .NotNull(); + } + public Func>> ValidateValue => async (model, propertyName) => + { + var result = await ValidateAsync(ValidationContext.CreateWithOptions((DeletePackageRequest)model, x => x.IncludeProperties(propertyName))); + if (result.IsValid) + return Array.Empty(); + return result.Errors.Select(e => e.ErrorMessage); + }; +} diff --git a/src/CMSMicroservice.Protobuf/Validator/Package/GetAllPackageByFilterRequestValidator.cs b/src/CMSMicroservice.Protobuf/Validator/Package/GetAllPackageByFilterRequestValidator.cs new file mode 100644 index 0000000..b82c2e8 --- /dev/null +++ b/src/CMSMicroservice.Protobuf/Validator/Package/GetAllPackageByFilterRequestValidator.cs @@ -0,0 +1,17 @@ +using FluentValidation; +using CMSMicroservice.Protobuf.Protos.Package; +namespace CMSMicroservice.Protobuf.Validator.Package; + +public class GetAllPackageByFilterRequestValidator : AbstractValidator +{ + public GetAllPackageByFilterRequestValidator() + { + } + public Func>> ValidateValue => async (model, propertyName) => + { + var result = await ValidateAsync(ValidationContext.CreateWithOptions((GetAllPackageByFilterRequest)model, x => x.IncludeProperties(propertyName))); + if (result.IsValid) + return Array.Empty(); + return result.Errors.Select(e => e.ErrorMessage); + }; +} diff --git a/src/CMSMicroservice.Protobuf/Validator/Package/GetPackageRequestValidator.cs b/src/CMSMicroservice.Protobuf/Validator/Package/GetPackageRequestValidator.cs new file mode 100644 index 0000000..0c68654 --- /dev/null +++ b/src/CMSMicroservice.Protobuf/Validator/Package/GetPackageRequestValidator.cs @@ -0,0 +1,19 @@ +using FluentValidation; +using CMSMicroservice.Protobuf.Protos.Package; +namespace CMSMicroservice.Protobuf.Validator.Package; + +public class GetPackageRequestValidator : AbstractValidator +{ + public GetPackageRequestValidator() + { + RuleFor(model => model.Id) + .NotNull(); + } + public Func>> ValidateValue => async (model, propertyName) => + { + var result = await ValidateAsync(ValidationContext.CreateWithOptions((GetPackageRequest)model, x => x.IncludeProperties(propertyName))); + if (result.IsValid) + return Array.Empty(); + return result.Errors.Select(e => e.ErrorMessage); + }; +} diff --git a/src/CMSMicroservice.Protobuf/Validator/Package/UpdatePackageRequestValidator.cs b/src/CMSMicroservice.Protobuf/Validator/Package/UpdatePackageRequestValidator.cs new file mode 100644 index 0000000..0e1d29e --- /dev/null +++ b/src/CMSMicroservice.Protobuf/Validator/Package/UpdatePackageRequestValidator.cs @@ -0,0 +1,27 @@ +using FluentValidation; +using CMSMicroservice.Protobuf.Protos.Package; +namespace CMSMicroservice.Protobuf.Validator.Package; + +public class UpdatePackageRequestValidator : AbstractValidator +{ + public UpdatePackageRequestValidator() + { + RuleFor(model => model.Id) + .NotNull(); + RuleFor(model => model.Title) + .NotEmpty(); + RuleFor(model => model.Description) + .NotEmpty(); + RuleFor(model => model.ImagePath) + .NotEmpty(); + RuleFor(model => model.Price) + .NotNull(); + } + public Func>> ValidateValue => async (model, propertyName) => + { + var result = await ValidateAsync(ValidationContext.CreateWithOptions((UpdatePackageRequest)model, x => x.IncludeProperties(propertyName))); + if (result.IsValid) + return Array.Empty(); + return result.Errors.Select(e => e.ErrorMessage); + }; +} diff --git a/src/CMSMicroservice.Protobuf/Validator/Role/CreateNewRoleRequestValidator.cs b/src/CMSMicroservice.Protobuf/Validator/Role/CreateNewRoleRequestValidator.cs new file mode 100644 index 0000000..e72a9c2 --- /dev/null +++ b/src/CMSMicroservice.Protobuf/Validator/Role/CreateNewRoleRequestValidator.cs @@ -0,0 +1,21 @@ +using FluentValidation; +using CMSMicroservice.Protobuf.Protos.Role; +namespace CMSMicroservice.Protobuf.Validator.Role; + +public class CreateNewRoleRequestValidator : AbstractValidator +{ + public CreateNewRoleRequestValidator() + { + RuleFor(model => model.Name) + .NotEmpty(); + RuleFor(model => model.Title) + .NotEmpty(); + } + public Func>> ValidateValue => async (model, propertyName) => + { + var result = await ValidateAsync(ValidationContext.CreateWithOptions((CreateNewRoleRequest)model, x => x.IncludeProperties(propertyName))); + if (result.IsValid) + return Array.Empty(); + return result.Errors.Select(e => e.ErrorMessage); + }; +} diff --git a/src/CMSMicroservice.Protobuf/Validator/Role/DeleteRoleRequestValidator.cs b/src/CMSMicroservice.Protobuf/Validator/Role/DeleteRoleRequestValidator.cs new file mode 100644 index 0000000..7c7702b --- /dev/null +++ b/src/CMSMicroservice.Protobuf/Validator/Role/DeleteRoleRequestValidator.cs @@ -0,0 +1,19 @@ +using FluentValidation; +using CMSMicroservice.Protobuf.Protos.Role; +namespace CMSMicroservice.Protobuf.Validator.Role; + +public class DeleteRoleRequestValidator : AbstractValidator +{ + public DeleteRoleRequestValidator() + { + RuleFor(model => model.Id) + .NotNull(); + } + public Func>> ValidateValue => async (model, propertyName) => + { + var result = await ValidateAsync(ValidationContext.CreateWithOptions((DeleteRoleRequest)model, x => x.IncludeProperties(propertyName))); + if (result.IsValid) + return Array.Empty(); + return result.Errors.Select(e => e.ErrorMessage); + }; +} diff --git a/src/CMSMicroservice.Protobuf/Validator/Role/GetAllRoleByFilterRequestValidator.cs b/src/CMSMicroservice.Protobuf/Validator/Role/GetAllRoleByFilterRequestValidator.cs new file mode 100644 index 0000000..b58565e --- /dev/null +++ b/src/CMSMicroservice.Protobuf/Validator/Role/GetAllRoleByFilterRequestValidator.cs @@ -0,0 +1,17 @@ +using FluentValidation; +using CMSMicroservice.Protobuf.Protos.Role; +namespace CMSMicroservice.Protobuf.Validator.Role; + +public class GetAllRoleByFilterRequestValidator : AbstractValidator +{ + public GetAllRoleByFilterRequestValidator() + { + } + public Func>> ValidateValue => async (model, propertyName) => + { + var result = await ValidateAsync(ValidationContext.CreateWithOptions((GetAllRoleByFilterRequest)model, x => x.IncludeProperties(propertyName))); + if (result.IsValid) + return Array.Empty(); + return result.Errors.Select(e => e.ErrorMessage); + }; +} diff --git a/src/CMSMicroservice.Protobuf/Validator/Role/GetRoleRequestValidator.cs b/src/CMSMicroservice.Protobuf/Validator/Role/GetRoleRequestValidator.cs new file mode 100644 index 0000000..4a967fd --- /dev/null +++ b/src/CMSMicroservice.Protobuf/Validator/Role/GetRoleRequestValidator.cs @@ -0,0 +1,19 @@ +using FluentValidation; +using CMSMicroservice.Protobuf.Protos.Role; +namespace CMSMicroservice.Protobuf.Validator.Role; + +public class GetRoleRequestValidator : AbstractValidator +{ + public GetRoleRequestValidator() + { + RuleFor(model => model.Id) + .NotNull(); + } + public Func>> ValidateValue => async (model, propertyName) => + { + var result = await ValidateAsync(ValidationContext.CreateWithOptions((GetRoleRequest)model, x => x.IncludeProperties(propertyName))); + if (result.IsValid) + return Array.Empty(); + return result.Errors.Select(e => e.ErrorMessage); + }; +} diff --git a/src/CMSMicroservice.Protobuf/Validator/Role/UpdateRoleRequestValidator.cs b/src/CMSMicroservice.Protobuf/Validator/Role/UpdateRoleRequestValidator.cs new file mode 100644 index 0000000..1ffee94 --- /dev/null +++ b/src/CMSMicroservice.Protobuf/Validator/Role/UpdateRoleRequestValidator.cs @@ -0,0 +1,23 @@ +using FluentValidation; +using CMSMicroservice.Protobuf.Protos.Role; +namespace CMSMicroservice.Protobuf.Validator.Role; + +public class UpdateRoleRequestValidator : AbstractValidator +{ + public UpdateRoleRequestValidator() + { + RuleFor(model => model.Id) + .NotNull(); + RuleFor(model => model.Name) + .NotEmpty(); + RuleFor(model => model.Title) + .NotEmpty(); + } + public Func>> ValidateValue => async (model, propertyName) => + { + var result = await ValidateAsync(ValidationContext.CreateWithOptions((UpdateRoleRequest)model, x => x.IncludeProperties(propertyName))); + if (result.IsValid) + return Array.Empty(); + return result.Errors.Select(e => e.ErrorMessage); + }; +} diff --git a/src/CMSMicroservice.Protobuf/Validator/User/CreateNewUserRequestValidator.cs b/src/CMSMicroservice.Protobuf/Validator/User/CreateNewUserRequestValidator.cs new file mode 100644 index 0000000..434e58a --- /dev/null +++ b/src/CMSMicroservice.Protobuf/Validator/User/CreateNewUserRequestValidator.cs @@ -0,0 +1,19 @@ +using FluentValidation; +using CMSMicroservice.Protobuf.Protos.User; +namespace CMSMicroservice.Protobuf.Validator.User; + +public class CreateNewUserRequestValidator : AbstractValidator +{ + public CreateNewUserRequestValidator() + { + RuleFor(model => model.Mobile) + .NotEmpty(); + } + public Func>> ValidateValue => async (model, propertyName) => + { + var result = await ValidateAsync(ValidationContext.CreateWithOptions((CreateNewUserRequest)model, x => x.IncludeProperties(propertyName))); + if (result.IsValid) + return Array.Empty(); + return result.Errors.Select(e => e.ErrorMessage); + }; +} diff --git a/src/CMSMicroservice.Protobuf/Validator/User/DeleteUserRequestValidator.cs b/src/CMSMicroservice.Protobuf/Validator/User/DeleteUserRequestValidator.cs new file mode 100644 index 0000000..3a9b86f --- /dev/null +++ b/src/CMSMicroservice.Protobuf/Validator/User/DeleteUserRequestValidator.cs @@ -0,0 +1,19 @@ +using FluentValidation; +using CMSMicroservice.Protobuf.Protos.User; +namespace CMSMicroservice.Protobuf.Validator.User; + +public class DeleteUserRequestValidator : AbstractValidator +{ + public DeleteUserRequestValidator() + { + RuleFor(model => model.Id) + .NotNull(); + } + public Func>> ValidateValue => async (model, propertyName) => + { + var result = await ValidateAsync(ValidationContext.CreateWithOptions((DeleteUserRequest)model, x => x.IncludeProperties(propertyName))); + if (result.IsValid) + return Array.Empty(); + return result.Errors.Select(e => e.ErrorMessage); + }; +} diff --git a/src/CMSMicroservice.Protobuf/Validator/User/GetAllUserByFilterRequestValidator.cs b/src/CMSMicroservice.Protobuf/Validator/User/GetAllUserByFilterRequestValidator.cs new file mode 100644 index 0000000..21c206a --- /dev/null +++ b/src/CMSMicroservice.Protobuf/Validator/User/GetAllUserByFilterRequestValidator.cs @@ -0,0 +1,17 @@ +using FluentValidation; +using CMSMicroservice.Protobuf.Protos.User; +namespace CMSMicroservice.Protobuf.Validator.User; + +public class GetAllUserByFilterRequestValidator : AbstractValidator +{ + public GetAllUserByFilterRequestValidator() + { + } + public Func>> ValidateValue => async (model, propertyName) => + { + var result = await ValidateAsync(ValidationContext.CreateWithOptions((GetAllUserByFilterRequest)model, x => x.IncludeProperties(propertyName))); + if (result.IsValid) + return Array.Empty(); + return result.Errors.Select(e => e.ErrorMessage); + }; +} diff --git a/src/CMSMicroservice.Protobuf/Validator/User/GetUserRequestValidator.cs b/src/CMSMicroservice.Protobuf/Validator/User/GetUserRequestValidator.cs new file mode 100644 index 0000000..2693d29 --- /dev/null +++ b/src/CMSMicroservice.Protobuf/Validator/User/GetUserRequestValidator.cs @@ -0,0 +1,19 @@ +using FluentValidation; +using CMSMicroservice.Protobuf.Protos.User; +namespace CMSMicroservice.Protobuf.Validator.User; + +public class GetUserRequestValidator : AbstractValidator +{ + public GetUserRequestValidator() + { + RuleFor(model => model.Id) + .NotNull(); + } + public Func>> ValidateValue => async (model, propertyName) => + { + var result = await ValidateAsync(ValidationContext.CreateWithOptions((GetUserRequest)model, x => x.IncludeProperties(propertyName))); + if (result.IsValid) + return Array.Empty(); + return result.Errors.Select(e => e.ErrorMessage); + }; +} diff --git a/src/CMSMicroservice.Protobuf/Validator/User/UpdateUserRequestValidator.cs b/src/CMSMicroservice.Protobuf/Validator/User/UpdateUserRequestValidator.cs new file mode 100644 index 0000000..f65bc5f --- /dev/null +++ b/src/CMSMicroservice.Protobuf/Validator/User/UpdateUserRequestValidator.cs @@ -0,0 +1,21 @@ +using FluentValidation; +using CMSMicroservice.Protobuf.Protos.User; +namespace CMSMicroservice.Protobuf.Validator.User; + +public class UpdateUserRequestValidator : AbstractValidator +{ + public UpdateUserRequestValidator() + { + RuleFor(model => model.Id) + .NotNull(); + RuleFor(model => model.Mobile) + .NotEmpty(); + } + public Func>> ValidateValue => async (model, propertyName) => + { + var result = await ValidateAsync(ValidationContext.CreateWithOptions((UpdateUserRequest)model, x => x.IncludeProperties(propertyName))); + if (result.IsValid) + return Array.Empty(); + return result.Errors.Select(e => e.ErrorMessage); + }; +} diff --git a/src/CMSMicroservice.Protobuf/Validator/UserAddress/CreateNewUserAddressRequestValidator.cs b/src/CMSMicroservice.Protobuf/Validator/UserAddress/CreateNewUserAddressRequestValidator.cs new file mode 100644 index 0000000..778cae9 --- /dev/null +++ b/src/CMSMicroservice.Protobuf/Validator/UserAddress/CreateNewUserAddressRequestValidator.cs @@ -0,0 +1,29 @@ +using FluentValidation; +using CMSMicroservice.Protobuf.Protos.UserAddress; +namespace CMSMicroservice.Protobuf.Validator.UserAddress; + +public class CreateNewUserAddressRequestValidator : AbstractValidator +{ + public CreateNewUserAddressRequestValidator() + { + RuleFor(model => model.UserId) + .NotNull(); + RuleFor(model => model.Title) + .NotEmpty(); + RuleFor(model => model.Address) + .NotEmpty(); + RuleFor(model => model.PostalCode) + .NotEmpty(); + RuleFor(model => model.IsDefault) + .NotNull(); + RuleFor(model => model.CityId) + .NotNull(); + } + public Func>> ValidateValue => async (model, propertyName) => + { + var result = await ValidateAsync(ValidationContext.CreateWithOptions((CreateNewUserAddressRequest)model, x => x.IncludeProperties(propertyName))); + if (result.IsValid) + return Array.Empty(); + return result.Errors.Select(e => e.ErrorMessage); + }; +} diff --git a/src/CMSMicroservice.Protobuf/Validator/UserAddress/DeleteUserAddressRequestValidator.cs b/src/CMSMicroservice.Protobuf/Validator/UserAddress/DeleteUserAddressRequestValidator.cs new file mode 100644 index 0000000..70dd5c9 --- /dev/null +++ b/src/CMSMicroservice.Protobuf/Validator/UserAddress/DeleteUserAddressRequestValidator.cs @@ -0,0 +1,19 @@ +using FluentValidation; +using CMSMicroservice.Protobuf.Protos.UserAddress; +namespace CMSMicroservice.Protobuf.Validator.UserAddress; + +public class DeleteUserAddressRequestValidator : AbstractValidator +{ + public DeleteUserAddressRequestValidator() + { + RuleFor(model => model.Id) + .NotNull(); + } + public Func>> ValidateValue => async (model, propertyName) => + { + var result = await ValidateAsync(ValidationContext.CreateWithOptions((DeleteUserAddressRequest)model, x => x.IncludeProperties(propertyName))); + if (result.IsValid) + return Array.Empty(); + return result.Errors.Select(e => e.ErrorMessage); + }; +} diff --git a/src/CMSMicroservice.Protobuf/Validator/UserAddress/GetAllUserAddressByFilterRequestValidator.cs b/src/CMSMicroservice.Protobuf/Validator/UserAddress/GetAllUserAddressByFilterRequestValidator.cs new file mode 100644 index 0000000..fe00a19 --- /dev/null +++ b/src/CMSMicroservice.Protobuf/Validator/UserAddress/GetAllUserAddressByFilterRequestValidator.cs @@ -0,0 +1,17 @@ +using FluentValidation; +using CMSMicroservice.Protobuf.Protos.UserAddress; +namespace CMSMicroservice.Protobuf.Validator.UserAddress; + +public class GetAllUserAddressByFilterRequestValidator : AbstractValidator +{ + public GetAllUserAddressByFilterRequestValidator() + { + } + public Func>> ValidateValue => async (model, propertyName) => + { + var result = await ValidateAsync(ValidationContext.CreateWithOptions((GetAllUserAddressByFilterRequest)model, x => x.IncludeProperties(propertyName))); + if (result.IsValid) + return Array.Empty(); + return result.Errors.Select(e => e.ErrorMessage); + }; +} diff --git a/src/CMSMicroservice.Protobuf/Validator/UserAddress/GetUserAddressRequestValidator.cs b/src/CMSMicroservice.Protobuf/Validator/UserAddress/GetUserAddressRequestValidator.cs new file mode 100644 index 0000000..c32f4c1 --- /dev/null +++ b/src/CMSMicroservice.Protobuf/Validator/UserAddress/GetUserAddressRequestValidator.cs @@ -0,0 +1,19 @@ +using FluentValidation; +using CMSMicroservice.Protobuf.Protos.UserAddress; +namespace CMSMicroservice.Protobuf.Validator.UserAddress; + +public class GetUserAddressRequestValidator : AbstractValidator +{ + public GetUserAddressRequestValidator() + { + RuleFor(model => model.Id) + .NotNull(); + } + public Func>> ValidateValue => async (model, propertyName) => + { + var result = await ValidateAsync(ValidationContext.CreateWithOptions((GetUserAddressRequest)model, x => x.IncludeProperties(propertyName))); + if (result.IsValid) + return Array.Empty(); + return result.Errors.Select(e => e.ErrorMessage); + }; +} diff --git a/src/CMSMicroservice.Protobuf/Validator/UserAddress/UpdateUserAddressRequestValidator.cs b/src/CMSMicroservice.Protobuf/Validator/UserAddress/UpdateUserAddressRequestValidator.cs new file mode 100644 index 0000000..6235ef6 --- /dev/null +++ b/src/CMSMicroservice.Protobuf/Validator/UserAddress/UpdateUserAddressRequestValidator.cs @@ -0,0 +1,31 @@ +using FluentValidation; +using CMSMicroservice.Protobuf.Protos.UserAddress; +namespace CMSMicroservice.Protobuf.Validator.UserAddress; + +public class UpdateUserAddressRequestValidator : AbstractValidator +{ + public UpdateUserAddressRequestValidator() + { + RuleFor(model => model.Id) + .NotNull(); + RuleFor(model => model.UserId) + .NotNull(); + RuleFor(model => model.Title) + .NotEmpty(); + RuleFor(model => model.Address) + .NotEmpty(); + RuleFor(model => model.PostalCode) + .NotEmpty(); + RuleFor(model => model.IsDefault) + .NotNull(); + RuleFor(model => model.CityId) + .NotNull(); + } + public Func>> ValidateValue => async (model, propertyName) => + { + var result = await ValidateAsync(ValidationContext.CreateWithOptions((UpdateUserAddressRequest)model, x => x.IncludeProperties(propertyName))); + if (result.IsValid) + return Array.Empty(); + return result.Errors.Select(e => e.ErrorMessage); + }; +} diff --git a/src/CMSMicroservice.Protobuf/Validator/UserOrder/CreateNewUserOrderRequestValidator.cs b/src/CMSMicroservice.Protobuf/Validator/UserOrder/CreateNewUserOrderRequestValidator.cs new file mode 100644 index 0000000..efbfe29 --- /dev/null +++ b/src/CMSMicroservice.Protobuf/Validator/UserOrder/CreateNewUserOrderRequestValidator.cs @@ -0,0 +1,25 @@ +using FluentValidation; +using CMSMicroservice.Protobuf.Protos.UserOrder; +namespace CMSMicroservice.Protobuf.Validator.UserOrder; + +public class CreateNewUserOrderRequestValidator : AbstractValidator +{ + public CreateNewUserOrderRequestValidator() + { + RuleFor(model => model.Price) + .NotNull(); + RuleFor(model => model.PackageId) + .NotNull(); + RuleFor(model => model.PaymentStatus) + .NotNull(); + RuleFor(model => model.UserId) + .NotNull(); + } + public Func>> ValidateValue => async (model, propertyName) => + { + var result = await ValidateAsync(ValidationContext.CreateWithOptions((CreateNewUserOrderRequest)model, x => x.IncludeProperties(propertyName))); + if (result.IsValid) + return Array.Empty(); + return result.Errors.Select(e => e.ErrorMessage); + }; +} diff --git a/src/CMSMicroservice.Protobuf/Validator/UserOrder/DeleteUserOrderRequestValidator.cs b/src/CMSMicroservice.Protobuf/Validator/UserOrder/DeleteUserOrderRequestValidator.cs new file mode 100644 index 0000000..de189c1 --- /dev/null +++ b/src/CMSMicroservice.Protobuf/Validator/UserOrder/DeleteUserOrderRequestValidator.cs @@ -0,0 +1,19 @@ +using FluentValidation; +using CMSMicroservice.Protobuf.Protos.UserOrder; +namespace CMSMicroservice.Protobuf.Validator.UserOrder; + +public class DeleteUserOrderRequestValidator : AbstractValidator +{ + public DeleteUserOrderRequestValidator() + { + RuleFor(model => model.Id) + .NotNull(); + } + public Func>> ValidateValue => async (model, propertyName) => + { + var result = await ValidateAsync(ValidationContext.CreateWithOptions((DeleteUserOrderRequest)model, x => x.IncludeProperties(propertyName))); + if (result.IsValid) + return Array.Empty(); + return result.Errors.Select(e => e.ErrorMessage); + }; +} diff --git a/src/CMSMicroservice.Protobuf/Validator/UserOrder/GetAllUserOrderByFilterRequestValidator.cs b/src/CMSMicroservice.Protobuf/Validator/UserOrder/GetAllUserOrderByFilterRequestValidator.cs new file mode 100644 index 0000000..7525ee8 --- /dev/null +++ b/src/CMSMicroservice.Protobuf/Validator/UserOrder/GetAllUserOrderByFilterRequestValidator.cs @@ -0,0 +1,17 @@ +using FluentValidation; +using CMSMicroservice.Protobuf.Protos.UserOrder; +namespace CMSMicroservice.Protobuf.Validator.UserOrder; + +public class GetAllUserOrderByFilterRequestValidator : AbstractValidator +{ + public GetAllUserOrderByFilterRequestValidator() + { + } + public Func>> ValidateValue => async (model, propertyName) => + { + var result = await ValidateAsync(ValidationContext.CreateWithOptions((GetAllUserOrderByFilterRequest)model, x => x.IncludeProperties(propertyName))); + if (result.IsValid) + return Array.Empty(); + return result.Errors.Select(e => e.ErrorMessage); + }; +} diff --git a/src/CMSMicroservice.Protobuf/Validator/UserOrder/GetUserOrderRequestValidator.cs b/src/CMSMicroservice.Protobuf/Validator/UserOrder/GetUserOrderRequestValidator.cs new file mode 100644 index 0000000..ac32366 --- /dev/null +++ b/src/CMSMicroservice.Protobuf/Validator/UserOrder/GetUserOrderRequestValidator.cs @@ -0,0 +1,19 @@ +using FluentValidation; +using CMSMicroservice.Protobuf.Protos.UserOrder; +namespace CMSMicroservice.Protobuf.Validator.UserOrder; + +public class GetUserOrderRequestValidator : AbstractValidator +{ + public GetUserOrderRequestValidator() + { + RuleFor(model => model.Id) + .NotNull(); + } + public Func>> ValidateValue => async (model, propertyName) => + { + var result = await ValidateAsync(ValidationContext.CreateWithOptions((GetUserOrderRequest)model, x => x.IncludeProperties(propertyName))); + if (result.IsValid) + return Array.Empty(); + return result.Errors.Select(e => e.ErrorMessage); + }; +} diff --git a/src/CMSMicroservice.Protobuf/Validator/UserOrder/UpdateUserOrderRequestValidator.cs b/src/CMSMicroservice.Protobuf/Validator/UserOrder/UpdateUserOrderRequestValidator.cs new file mode 100644 index 0000000..c5a0801 --- /dev/null +++ b/src/CMSMicroservice.Protobuf/Validator/UserOrder/UpdateUserOrderRequestValidator.cs @@ -0,0 +1,27 @@ +using FluentValidation; +using CMSMicroservice.Protobuf.Protos.UserOrder; +namespace CMSMicroservice.Protobuf.Validator.UserOrder; + +public class UpdateUserOrderRequestValidator : AbstractValidator +{ + public UpdateUserOrderRequestValidator() + { + RuleFor(model => model.Id) + .NotNull(); + RuleFor(model => model.Price) + .NotNull(); + RuleFor(model => model.PackageId) + .NotNull(); + RuleFor(model => model.PaymentStatus) + .NotNull(); + RuleFor(model => model.UserId) + .NotNull(); + } + public Func>> ValidateValue => async (model, propertyName) => + { + var result = await ValidateAsync(ValidationContext.CreateWithOptions((UpdateUserOrderRequest)model, x => x.IncludeProperties(propertyName))); + if (result.IsValid) + return Array.Empty(); + return result.Errors.Select(e => e.ErrorMessage); + }; +} diff --git a/src/CMSMicroservice.Protobuf/Validator/UserRole/CreateNewUserRoleRequestValidator.cs b/src/CMSMicroservice.Protobuf/Validator/UserRole/CreateNewUserRoleRequestValidator.cs new file mode 100644 index 0000000..7a26ad2 --- /dev/null +++ b/src/CMSMicroservice.Protobuf/Validator/UserRole/CreateNewUserRoleRequestValidator.cs @@ -0,0 +1,21 @@ +using FluentValidation; +using CMSMicroservice.Protobuf.Protos.UserRole; +namespace CMSMicroservice.Protobuf.Validator.UserRole; + +public class CreateNewUserRoleRequestValidator : AbstractValidator +{ + public CreateNewUserRoleRequestValidator() + { + RuleFor(model => model.RoleId) + .NotNull(); + RuleFor(model => model.UserId) + .NotNull(); + } + public Func>> ValidateValue => async (model, propertyName) => + { + var result = await ValidateAsync(ValidationContext.CreateWithOptions((CreateNewUserRoleRequest)model, x => x.IncludeProperties(propertyName))); + if (result.IsValid) + return Array.Empty(); + return result.Errors.Select(e => e.ErrorMessage); + }; +} diff --git a/src/CMSMicroservice.Protobuf/Validator/UserRole/DeleteUserRoleRequestValidator.cs b/src/CMSMicroservice.Protobuf/Validator/UserRole/DeleteUserRoleRequestValidator.cs new file mode 100644 index 0000000..eeda42a --- /dev/null +++ b/src/CMSMicroservice.Protobuf/Validator/UserRole/DeleteUserRoleRequestValidator.cs @@ -0,0 +1,19 @@ +using FluentValidation; +using CMSMicroservice.Protobuf.Protos.UserRole; +namespace CMSMicroservice.Protobuf.Validator.UserRole; + +public class DeleteUserRoleRequestValidator : AbstractValidator +{ + public DeleteUserRoleRequestValidator() + { + RuleFor(model => model.Id) + .NotNull(); + } + public Func>> ValidateValue => async (model, propertyName) => + { + var result = await ValidateAsync(ValidationContext.CreateWithOptions((DeleteUserRoleRequest)model, x => x.IncludeProperties(propertyName))); + if (result.IsValid) + return Array.Empty(); + return result.Errors.Select(e => e.ErrorMessage); + }; +} diff --git a/src/CMSMicroservice.Protobuf/Validator/UserRole/GetAllUserRoleByFilterRequestValidator.cs b/src/CMSMicroservice.Protobuf/Validator/UserRole/GetAllUserRoleByFilterRequestValidator.cs new file mode 100644 index 0000000..0845700 --- /dev/null +++ b/src/CMSMicroservice.Protobuf/Validator/UserRole/GetAllUserRoleByFilterRequestValidator.cs @@ -0,0 +1,17 @@ +using FluentValidation; +using CMSMicroservice.Protobuf.Protos.UserRole; +namespace CMSMicroservice.Protobuf.Validator.UserRole; + +public class GetAllUserRoleByFilterRequestValidator : AbstractValidator +{ + public GetAllUserRoleByFilterRequestValidator() + { + } + public Func>> ValidateValue => async (model, propertyName) => + { + var result = await ValidateAsync(ValidationContext.CreateWithOptions((GetAllUserRoleByFilterRequest)model, x => x.IncludeProperties(propertyName))); + if (result.IsValid) + return Array.Empty(); + return result.Errors.Select(e => e.ErrorMessage); + }; +} diff --git a/src/CMSMicroservice.Protobuf/Validator/UserRole/GetUserRoleRequestValidator.cs b/src/CMSMicroservice.Protobuf/Validator/UserRole/GetUserRoleRequestValidator.cs new file mode 100644 index 0000000..39359bb --- /dev/null +++ b/src/CMSMicroservice.Protobuf/Validator/UserRole/GetUserRoleRequestValidator.cs @@ -0,0 +1,19 @@ +using FluentValidation; +using CMSMicroservice.Protobuf.Protos.UserRole; +namespace CMSMicroservice.Protobuf.Validator.UserRole; + +public class GetUserRoleRequestValidator : AbstractValidator +{ + public GetUserRoleRequestValidator() + { + RuleFor(model => model.Id) + .NotNull(); + } + public Func>> ValidateValue => async (model, propertyName) => + { + var result = await ValidateAsync(ValidationContext.CreateWithOptions((GetUserRoleRequest)model, x => x.IncludeProperties(propertyName))); + if (result.IsValid) + return Array.Empty(); + return result.Errors.Select(e => e.ErrorMessage); + }; +} diff --git a/src/CMSMicroservice.Protobuf/Validator/UserRole/UpdateUserRoleRequestValidator.cs b/src/CMSMicroservice.Protobuf/Validator/UserRole/UpdateUserRoleRequestValidator.cs new file mode 100644 index 0000000..8ea478f --- /dev/null +++ b/src/CMSMicroservice.Protobuf/Validator/UserRole/UpdateUserRoleRequestValidator.cs @@ -0,0 +1,23 @@ +using FluentValidation; +using CMSMicroservice.Protobuf.Protos.UserRole; +namespace CMSMicroservice.Protobuf.Validator.UserRole; + +public class UpdateUserRoleRequestValidator : AbstractValidator +{ + public UpdateUserRoleRequestValidator() + { + RuleFor(model => model.Id) + .NotNull(); + RuleFor(model => model.RoleId) + .NotNull(); + RuleFor(model => model.UserId) + .NotNull(); + } + public Func>> ValidateValue => async (model, propertyName) => + { + var result = await ValidateAsync(ValidationContext.CreateWithOptions((UpdateUserRoleRequest)model, x => x.IncludeProperties(propertyName))); + if (result.IsValid) + return Array.Empty(); + return result.Errors.Select(e => e.ErrorMessage); + }; +} diff --git a/src/CMSMicroservice.WebApi/CMSMicroservice.WebApi.csproj b/src/CMSMicroservice.WebApi/CMSMicroservice.WebApi.csproj new file mode 100644 index 0000000..b54fa53 --- /dev/null +++ b/src/CMSMicroservice.WebApi/CMSMicroservice.WebApi.csproj @@ -0,0 +1,35 @@ + + + + net7.0 + enable + Linux + ..\..\.. + + + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + + + + + diff --git a/src/CMSMicroservice.WebApi/Common/Behaviours/LoggingBehaviour.cs b/src/CMSMicroservice.WebApi/Common/Behaviours/LoggingBehaviour.cs new file mode 100644 index 0000000..8481daa --- /dev/null +++ b/src/CMSMicroservice.WebApi/Common/Behaviours/LoggingBehaviour.cs @@ -0,0 +1,38 @@ +using Grpc.Core.Interceptors; +using Microsoft.Extensions.Logging; +using CMSMicroservice.Application.Common.Interfaces; + +namespace CMSMicroservice.WebApi.Common.Behaviours; + +public class LoggingBehaviour : Interceptor +{ + private readonly ILogger _logger; + private readonly ICurrentUserService _currentUserService; + public LoggingBehaviour(ILogger logger, ICurrentUserService currentUserService) + { + _logger = logger; + _currentUserService = currentUserService; + } + + public override async Task UnaryServerHandler( + TRequest request, + ServerCallContext context, + UnaryServerMethod continuation) + { + var requestName = typeof(TRequest).Name; + var userId = _currentUserService.UserId ?? string.Empty; + _logger.LogInformation("gRPC Starting receiving call. Type/Method: {Type} / {Method} Request: {Name} {@UserId} {@Request}", + MethodType.Unary, context.Method , requestName, userId, request); + + try + { + return await continuation(request, context); + } + catch (Exception ex) + { + _logger.LogError(ex, "gRPC Request: Unhandled Exception for Request {Name} {@Request}", requestName, request); + + throw; + } + } +} diff --git a/src/CMSMicroservice.WebApi/Common/Behaviours/PerformanceBehaviour.cs b/src/CMSMicroservice.WebApi/Common/Behaviours/PerformanceBehaviour.cs new file mode 100644 index 0000000..0a1f266 --- /dev/null +++ b/src/CMSMicroservice.WebApi/Common/Behaviours/PerformanceBehaviour.cs @@ -0,0 +1,44 @@ +using Grpc.Core.Interceptors; +using Microsoft.Extensions.Logging; +using System.Diagnostics; +using CMSMicroservice.Application.Common.Interfaces; + +namespace CMSMicroservice.WebApi.Common.Behaviours; + +public class PerformanceBehaviour : Interceptor +{ + private readonly Stopwatch _timer; + private readonly ILogger _logger; + private readonly ICurrentUserService _currentUserService; + public PerformanceBehaviour(ILogger logger, ICurrentUserService currentUserService) + { + _timer = new Stopwatch(); + _logger = logger; + _currentUserService = currentUserService; + } + + public override async Task UnaryServerHandler( + TRequest request, + ServerCallContext context, + UnaryServerMethod continuation) + { + _timer.Start(); + + var response = await continuation(request, context); + + _timer.Stop(); + + var elapsedMilliseconds = _timer.ElapsedMilliseconds; + + if (elapsedMilliseconds > 500) + { + var requestName = typeof(TRequest).Name; + var userId = _currentUserService.UserId ?? string.Empty; + + _logger.LogWarning("gRPC Long Running Request: {Name} ({ElapsedMilliseconds} milliseconds) {@UserId} {@Request}", + requestName, elapsedMilliseconds, userId, request); + } + return response; + } +} + diff --git a/src/CMSMicroservice.WebApi/Common/Mappings/GeneralMapping.cs b/src/CMSMicroservice.WebApi/Common/Mappings/GeneralMapping.cs new file mode 100644 index 0000000..abf4c10 --- /dev/null +++ b/src/CMSMicroservice.WebApi/Common/Mappings/GeneralMapping.cs @@ -0,0 +1,64 @@ +using System.Globalization; +namespace CMSMicroservice.WebApi.Common.Mappings; + +public class GeneralMapping : IRegister +{ + void IRegister.Register(TypeAdapterConfig config) + { + config.NewConfig() + .MapWith(src => decimal.Parse(src)); + + config.NewConfig() + .MapWith(src => src.ToString("R", new CultureInfo("en-us"))); + + config.NewConfig() + .MapWith(src => src == null ? string.Empty : src.Value.ToString("R", new CultureInfo("en-us"))); + + config.NewConfig() + .MapWith(src => string.IsNullOrEmpty(src) ? null : decimal.Parse(src)); + + config.NewConfig() + .MapWith(src => src == Guid.Empty ? string.Empty : src.ToString()); + + config.NewConfig() + .MapWith(src => string.IsNullOrEmpty(src) ? Guid.Empty : Guid.Parse(src)); + + config.NewConfig() + .MapWith(src => string.IsNullOrEmpty(src) ? null : Guid.Parse(src)); + + config.NewConfig() + .MapWith(src => src.ToDateTime()); + + config.NewConfig() + .MapWith(src => src == null ? null : src.ToDateTime()); + + config.NewConfig() + .MapWith(src => Timestamp.FromDateTime(DateTime.SpecifyKind(src, DateTimeKind.Utc))); + + config.NewConfig() + .MapWith(src => src.HasValue ? Timestamp.FromDateTime(DateTime.SpecifyKind(src.Value, DateTimeKind.Utc)) : null); + + config.NewConfig() + .MapWith(src => src.ToTimeSpan()); + + config.NewConfig() + .MapWith(src => src == null ? null : src.ToTimeSpan()); + + config.NewConfig() + .MapWith(src => Duration.FromTimeSpan(src)); + + config.NewConfig() + .MapWith(src => src.HasValue ? Duration.FromTimeSpan(src.Value) : null); + + config.Default + .UseDestinationValue(member => member.SetterModifier == AccessModifier.None && + member.Type.IsGenericType && + member.Type.GetGenericTypeDefinition() == typeof(Google.Protobuf.Collections.RepeatedField<>)); + + config.NewConfig() + .MapWith(src => src.ToByteArray()); + + config.NewConfig() + .MapWith(src => Google.Protobuf.ByteString.CopyFrom(src)); + } +} diff --git a/src/CMSMicroservice.WebApi/Common/Mappings/PackageProfile.cs b/src/CMSMicroservice.WebApi/Common/Mappings/PackageProfile.cs new file mode 100644 index 0000000..9e8a8f8 --- /dev/null +++ b/src/CMSMicroservice.WebApi/Common/Mappings/PackageProfile.cs @@ -0,0 +1,10 @@ +namespace CMSMicroservice.WebApi.Common.Mappings; + +public class PackageProfile : IRegister +{ + void IRegister.Register(TypeAdapterConfig config) + { + //config.NewConfig() + // .Map(dest => dest.FullName, src => $"{src.Firstname} {src.Lastname}"); + } +} diff --git a/src/CMSMicroservice.WebApi/Common/Mappings/RoleProfile.cs b/src/CMSMicroservice.WebApi/Common/Mappings/RoleProfile.cs new file mode 100644 index 0000000..30a82e1 --- /dev/null +++ b/src/CMSMicroservice.WebApi/Common/Mappings/RoleProfile.cs @@ -0,0 +1,10 @@ +namespace CMSMicroservice.WebApi.Common.Mappings; + +public class RoleProfile : IRegister +{ + void IRegister.Register(TypeAdapterConfig config) + { + //config.NewConfig() + // .Map(dest => dest.FullName, src => $"{src.Firstname} {src.Lastname}"); + } +} diff --git a/src/CMSMicroservice.WebApi/Common/Mappings/UserAddressProfile.cs b/src/CMSMicroservice.WebApi/Common/Mappings/UserAddressProfile.cs new file mode 100644 index 0000000..262770a --- /dev/null +++ b/src/CMSMicroservice.WebApi/Common/Mappings/UserAddressProfile.cs @@ -0,0 +1,10 @@ +namespace CMSMicroservice.WebApi.Common.Mappings; + +public class UserAddressProfile : IRegister +{ + void IRegister.Register(TypeAdapterConfig config) + { + //config.NewConfig() + // .Map(dest => dest.FullName, src => $"{src.Firstname} {src.Lastname}"); + } +} diff --git a/src/CMSMicroservice.WebApi/Common/Mappings/UserOrderProfile.cs b/src/CMSMicroservice.WebApi/Common/Mappings/UserOrderProfile.cs new file mode 100644 index 0000000..ae30672 --- /dev/null +++ b/src/CMSMicroservice.WebApi/Common/Mappings/UserOrderProfile.cs @@ -0,0 +1,10 @@ +namespace CMSMicroservice.WebApi.Common.Mappings; + +public class UserOrderProfile : IRegister +{ + void IRegister.Register(TypeAdapterConfig config) + { + //config.NewConfig() + // .Map(dest => dest.FullName, src => $"{src.Firstname} {src.Lastname}"); + } +} diff --git a/src/CMSMicroservice.WebApi/Common/Mappings/UserProfile.cs b/src/CMSMicroservice.WebApi/Common/Mappings/UserProfile.cs new file mode 100644 index 0000000..02c294f --- /dev/null +++ b/src/CMSMicroservice.WebApi/Common/Mappings/UserProfile.cs @@ -0,0 +1,10 @@ +namespace CMSMicroservice.WebApi.Common.Mappings; + +public class UserProfile : IRegister +{ + void IRegister.Register(TypeAdapterConfig config) + { + //config.NewConfig() + // .Map(dest => dest.FullName, src => $"{src.Firstname} {src.Lastname}"); + } +} diff --git a/src/CMSMicroservice.WebApi/Common/Mappings/UserRoleProfile.cs b/src/CMSMicroservice.WebApi/Common/Mappings/UserRoleProfile.cs new file mode 100644 index 0000000..2be785b --- /dev/null +++ b/src/CMSMicroservice.WebApi/Common/Mappings/UserRoleProfile.cs @@ -0,0 +1,10 @@ +namespace CMSMicroservice.WebApi.Common.Mappings; + +public class UserRoleProfile : IRegister +{ + void IRegister.Register(TypeAdapterConfig config) + { + //config.NewConfig() + // .Map(dest => dest.FullName, src => $"{src.Firstname} {src.Lastname}"); + } +} diff --git a/src/CMSMicroservice.WebApi/Common/Services/CurrentUserService.cs b/src/CMSMicroservice.WebApi/Common/Services/CurrentUserService.cs new file mode 100644 index 0000000..e5ea143 --- /dev/null +++ b/src/CMSMicroservice.WebApi/Common/Services/CurrentUserService.cs @@ -0,0 +1,17 @@ +using System.Security.Claims; +using CMSMicroservice.Application.Common.Interfaces; +using Microsoft.AspNetCore.Http; + +namespace CMSMicroservice.WebApi.Common.Services; + +public class CurrentUserService : ICurrentUserService +{ + private readonly IHttpContextAccessor _httpContextAccessor; + + public CurrentUserService(IHttpContextAccessor httpContextAccessor) + { + _httpContextAccessor = httpContextAccessor; + } + + public string? UserId => _httpContextAccessor.HttpContext?.User?.FindFirstValue(ClaimTypes.NameIdentifier); +} diff --git a/src/CMSMicroservice.WebApi/Common/Services/DispatchRequestToCQRS.cs b/src/CMSMicroservice.WebApi/Common/Services/DispatchRequestToCQRS.cs new file mode 100644 index 0000000..2ed2f9b --- /dev/null +++ b/src/CMSMicroservice.WebApi/Common/Services/DispatchRequestToCQRS.cs @@ -0,0 +1,87 @@ +namespace CMSMicroservice.WebApi.Common.Services; +public interface IDispatchRequestToCQRS +{ + Task Handle(TRequest request, + ServerCallContext context); + Task Handle(TRequest request, + ServerCallContext context); + Task Handle(ServerCallContext context); +} +public class DispatchRequestToCQRS : IDispatchRequestToCQRS +{ + private readonly ISender _sender; + + public DispatchRequestToCQRS(ISender sender) + { + _sender = sender; + } + + public async Task Handle(TRequest request, + ServerCallContext context) + { + try + { + if (request is null) + { + throw new ArgumentNullException(nameof(request)); + } + + var cqrsInput = request.Adapt(); + + if (cqrsInput is null) + { + throw new ArgumentNullException(nameof(cqrsInput)); + } + + var output = await _sender.Send(cqrsInput, context.CancellationToken); + return (output ?? throw new InvalidOperationException()).Adapt(); + } + catch (Exception) + { + throw; + } + } + public async Task Handle(ServerCallContext context) + { + try + { + var cqrsInput = Activator.CreateInstance(); + if (cqrsInput is null) + { + throw new ArgumentNullException(nameof(cqrsInput)); + } + + var output = await _sender.Send(cqrsInput, context.CancellationToken); + return (output ?? throw new InvalidOperationException()).Adapt(); + } + catch (Exception) + { + throw; + } + } + public async Task Handle(TRequest request, + ServerCallContext context) + { + try + { + if (request is null) + { + throw new ArgumentNullException(nameof(request)); + } + + var cqrsInput = request.Adapt(); + + if (cqrsInput is null) + { + throw new ArgumentNullException(nameof(cqrsInput)); + } + + await _sender.Send(cqrsInput, context.CancellationToken); + return new Empty(); + } + catch (Exception) + { + throw; + } + } +} diff --git a/src/CMSMicroservice.WebApi/ConfigureServices.cs b/src/CMSMicroservice.WebApi/ConfigureServices.cs new file mode 100644 index 0000000..9c2c50c --- /dev/null +++ b/src/CMSMicroservice.WebApi/ConfigureServices.cs @@ -0,0 +1,79 @@ +using CMSMicroservice.Application.Common.Interfaces; +using CMSMicroservice.Infrastructure.Persistence; +using CMSMicroservice.WebApi.Common.Services; +using MapsterMapper; +using System.Reflection; +using CMSMicroservice.WebApi.Services; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Routing; +using System.Linq; +using Microsoft.Extensions.Configuration; + +namespace Microsoft.Extensions.DependencyInjection; + +public static class ConfigureServices +{ + public static IServiceCollection AddPresentationServices(this IServiceCollection services, IConfiguration configuration) + { + services.AddMapping(); + + services.AddDatabaseDeveloperPageExceptionFilter(); + + services.AddScoped(); + services.AddScoped(); + + services.AddHttpContextAccessor(); + + services.AddHealthChecks() + .AddDbContextCheck(); + + return services; + } + private static IServiceCollection AddMapping(this IServiceCollection services) + { + var typeAdapterConfig = TypeAdapterConfig.GlobalSettings; + // scans the assembly and gets the IRegister, adding the registration to the TypeAdapterConfig + typeAdapterConfig.Scan(Assembly.GetExecutingAssembly()); + // register the mapper as Singleton service for my application + var mapperConfig = new Mapper(typeAdapterConfig); + services.AddSingleton(mapperConfig); + return services; + } + // get all grpc endpoint that end with "Service" in specified assembly and register them as grpc client + public static WebApplication ConfigureGrpcEndpoints(this WebApplication app, Assembly? assembly = null, + Action? configure = null) + { + if (assembly is not null) + { + var assemblyName = assembly.GetName().Name; + var grpcServices = assembly.GetTypes() + // check name and type + .Where(t => t.Name.EndsWith("Service") && t.IsClass) + // check folder by assembly qualified name + .Where(t => t.AssemblyQualifiedName != null && + t.AssemblyQualifiedName.Contains($"{assemblyName}.Services")) + // check parent name ends with "ContractBase" + .Where(t => t.BaseType?.Name.EndsWith("ContractBase") == true) + .ToList(); + + app.UseEndpoints(endpoints => + { + foreach (var service in grpcServices) + { + // how to use type as generic parameter in csharp? + // https://stackoverflow.com/questions/3957817/calling-generic-method-with-type-variable + var method = typeof(GrpcEndpointRouteBuilderExtensions).GetMethod("MapGrpcService"); + var generic = method?.MakeGenericMethod(service); + generic?.Invoke(null, new object[] { endpoints }); + } + }); + } + + if (configure is not null) + { + app.UseEndpoints(configure.Invoke); + } + + return app; + } +} diff --git a/src/CMSMicroservice.WebApi/Dockerfile b/src/CMSMicroservice.WebApi/Dockerfile new file mode 100644 index 0000000..d1fad2c --- /dev/null +++ b/src/CMSMicroservice.WebApi/Dockerfile @@ -0,0 +1,27 @@ + +#See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging. + +FROM mcr.microsoft.com/dotnet/aspnet:7.0 AS base +WORKDIR /app +EXPOSE 80 +EXPOSE 443 + +FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build +WORKDIR /src +COPY ["CMSMicroservice.WebApi/CMSMicroservice.WebApi.csproj", "CMSMicroservice.WebApi/"] +COPY ["CMSMicroservice.Application/CMSMicroservice.Application.csproj", "CMSMicroservice.Application/"] +COPY ["CMSMicroservice.Domain/CMSMicroservice.Domain.csproj", "CMSMicroservice.Domain/"] +COPY ["CMSMicroservice.Infrastructure/CMSMicroservice.Infrastructure.csproj", "CMSMicroservice.Infrastructure/"] +COPY ["CMSMicroservice.Protobuf/CMSMicroservice.Protobuf.csproj", "CMSMicroservice.Protobuf/"] +RUN dotnet restore "CMSMicroservice.WebApi/CMSMicroservice.WebApi.csproj" +COPY . . +WORKDIR "/src/CMSMicroservice.WebApi" +RUN dotnet build "CMSMicroservice.WebApi.csproj" -c Release -o /app/build + +FROM build AS publish +RUN dotnet publish "CMSMicroservice.WebApi.csproj" -c Release -o /app/publish /p:UseAppHost=false + +FROM base AS final +WORKDIR /app +COPY --from=publish /app/publish . +ENTRYPOINT ["dotnet", "CMSMicroservice.WebApi.dll"] diff --git a/src/CMSMicroservice.WebApi/GlobalUsings.cs b/src/CMSMicroservice.WebApi/GlobalUsings.cs new file mode 100644 index 0000000..dccec5c --- /dev/null +++ b/src/CMSMicroservice.WebApi/GlobalUsings.cs @@ -0,0 +1,7 @@ +global using Google.Protobuf.WellKnownTypes; +global using Grpc.Core; +global using Mapster; +global using MediatR; +global using System.Threading; +global using System.Threading.Tasks; +global using System; diff --git a/src/CMSMicroservice.WebApi/Program.cs b/src/CMSMicroservice.WebApi/Program.cs new file mode 100644 index 0000000..ab8dfaf --- /dev/null +++ b/src/CMSMicroservice.WebApi/Program.cs @@ -0,0 +1,131 @@ +using System.Runtime.InteropServices; +using CMSMicroservice.WebApi.Services; +using CMSMicroservice.Infrastructure.Persistence; +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Server.Kestrel.Core; +using Serilog.Core; +using Serilog; +using Serilog.Sinks.MSSqlServer; +using Microsoft.Extensions.Configuration; +using System.Reflection; +using Microsoft.OpenApi.Models; +using CMSMicroservice.WebApi.Common.Behaviours; + +var builder = WebApplication.CreateBuilder(args); +var levelSwitch = new LoggingLevelSwitch(); +var logger = new LoggerConfiguration() + //.WriteTo.Console() + .WriteTo.MSSqlServer(builder.Configuration.GetConnectionString("LogConnection"), + sinkOptions: new MSSqlServerSinkOptions + { + TableName = "LogCMSEvents", + SchemaName = "Log", + AutoCreateSqlTable = true + }) + /* .WriteTo.Seq("http://localhost:5341", + apiKey: "IeEfKjIMoCGLljdp9e7A", + controlLevelSwitch: levelSwitch)*/ + .CreateLogger(); +builder.Logging.AddSerilog(logger); +#if DEBUG +Serilog.Debugging.SelfLog.Enable(msg => Console.WriteLine(msg)); +#endif + +// Additional configuration is required to successfully run gRPC on macOS. +// For instructions on how to configure Kestrel and gRPC clients on macOS, visit https://go.microsoft.com/fwlink/?linkid=2099682 + +// Add services to the container. + +builder.Services.AddGrpc(options => +{ + options.Interceptors.Add(); + options.Interceptors.Add(); + options.EnableDetailedErrors = true; + options.MaxReceiveMessageSize = 1000 * 1024 * 1024; // 1 GB + options.MaxSendMessageSize = 1000 * 1024 * 1024; // 1 GB +}).AddJsonTranscoding(); +builder.Services.AddApplicationServices(); +builder.Services.AddInfrastructureServices(builder.Configuration); +builder.Services.AddPresentationServices(builder.Configuration); +builder.Services.AddProtobufServices(); + +#region Configure Cors + +builder.Services.AddCors(options => +{ + options.AddPolicy("AllowAll", + builder => builder.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader().WithExposedHeaders("Grpc-Status", + "Grpc-Message", "Grpc-Encoding", "Grpc-Accept-Encoding", "validation-errors-text")); +}); + +#endregion +builder.Services.AddGrpcSwagger(); +builder.Services.AddSwaggerGen(c => +{ + c.SwaggerDoc("v1", new OpenApiInfo { Title = "gRPC transcoding", Version = "v1" }); + c.CustomSchemaIds(type=>type.ToString()); + c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme + { + In = ParameterLocation.Header, + Description = "Please insert JWT with Bearer into field", + Name = "Authorization", + Type = SecuritySchemeType.ApiKey + }); + c.AddSecurityRequirement(new OpenApiSecurityRequirement + { + { + new OpenApiSecurityScheme + { + Reference = new OpenApiReference + { + Type = ReferenceType.SecurityScheme, + Id = "Bearer" + } + }, + new string[] { } + } + }); +}); +var app = builder.Build(); + +// Configure the HTTP request pipeline. +if (app.Environment.IsDevelopment()) +{ + app.UseDeveloperExceptionPage(); + app.UseMigrationsEndPoint(); + + // Initialise and seed database + using (var scope = app.Services.CreateScope()) + { + var initialiser = scope.ServiceProvider.GetRequiredService(); + await initialiser.InitialiseAsync(); + await initialiser.SeedAsync(); + } +} +else +{ + // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. + app.UseHsts(); +} + + +app.UseRouting(); +app.UseCors("AllowAll"); +app.UseAuthentication(); +app.UseAuthorization(); +app.UseGrpcWeb(new GrpcWebOptions { DefaultEnabled = true }); // Configure the HTTP request pipeline. +app.ConfigureGrpcEndpoints(Assembly.GetExecutingAssembly(), endpoints => +{ + // endpoints.MapGrpcService(); +}); + +app.MapGet("/", () => "Communication with gRPC endpoints must be made through a gRPC client. To learn how to create a client, visit: https://go.microsoft.com/fwlink/?linkid=2086909"); +app.UseSwagger(); +app.UseSwaggerUI(c => +{ + c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1"); +}); +app.Run(); diff --git a/src/CMSMicroservice.WebApi/Services/PackageService.cs b/src/CMSMicroservice.WebApi/Services/PackageService.cs new file mode 100644 index 0000000..cfb27ea --- /dev/null +++ b/src/CMSMicroservice.WebApi/Services/PackageService.cs @@ -0,0 +1,37 @@ +using CMSMicroservice.Protobuf.Protos.Package; +using CMSMicroservice.WebApi.Common.Services; +using CMSMicroservice.Application.PackageCQ.Commands.CreateNewPackage; +using CMSMicroservice.Application.PackageCQ.Commands.UpdatePackage; +using CMSMicroservice.Application.PackageCQ.Commands.DeletePackage; +using CMSMicroservice.Application.PackageCQ.Queries.GetPackage; +using CMSMicroservice.Application.PackageCQ.Queries.GetAllPackageByFilter; +namespace CMSMicroservice.WebApi.Services; +public class PackageService : PackageContract.PackageContractBase +{ + private readonly IDispatchRequestToCQRS _dispatchRequestToCQRS; + + public PackageService(IDispatchRequestToCQRS dispatchRequestToCQRS) + { + _dispatchRequestToCQRS = dispatchRequestToCQRS; + } + public override async Task CreateNewPackage(CreateNewPackageRequest request, ServerCallContext context) + { + return await _dispatchRequestToCQRS.Handle(request, context); + } + public override async Task UpdatePackage(UpdatePackageRequest request, ServerCallContext context) + { + return await _dispatchRequestToCQRS.Handle(request, context); + } + public override async Task DeletePackage(DeletePackageRequest request, ServerCallContext context) + { + return await _dispatchRequestToCQRS.Handle(request, context); + } + public override async Task GetPackage(GetPackageRequest request, ServerCallContext context) + { + return await _dispatchRequestToCQRS.Handle(request, context); + } + public override async Task GetAllPackageByFilter(GetAllPackageByFilterRequest request, ServerCallContext context) + { + return await _dispatchRequestToCQRS.Handle(request, context); + } +} diff --git a/src/CMSMicroservice.WebApi/Services/RoleService.cs b/src/CMSMicroservice.WebApi/Services/RoleService.cs new file mode 100644 index 0000000..88fe8b5 --- /dev/null +++ b/src/CMSMicroservice.WebApi/Services/RoleService.cs @@ -0,0 +1,37 @@ +using CMSMicroservice.Protobuf.Protos.Role; +using CMSMicroservice.WebApi.Common.Services; +using CMSMicroservice.Application.RoleCQ.Commands.CreateNewRole; +using CMSMicroservice.Application.RoleCQ.Commands.UpdateRole; +using CMSMicroservice.Application.RoleCQ.Commands.DeleteRole; +using CMSMicroservice.Application.RoleCQ.Queries.GetRole; +using CMSMicroservice.Application.RoleCQ.Queries.GetAllRoleByFilter; +namespace CMSMicroservice.WebApi.Services; +public class RoleService : RoleContract.RoleContractBase +{ + private readonly IDispatchRequestToCQRS _dispatchRequestToCQRS; + + public RoleService(IDispatchRequestToCQRS dispatchRequestToCQRS) + { + _dispatchRequestToCQRS = dispatchRequestToCQRS; + } + public override async Task CreateNewRole(CreateNewRoleRequest request, ServerCallContext context) + { + return await _dispatchRequestToCQRS.Handle(request, context); + } + public override async Task UpdateRole(UpdateRoleRequest request, ServerCallContext context) + { + return await _dispatchRequestToCQRS.Handle(request, context); + } + public override async Task DeleteRole(DeleteRoleRequest request, ServerCallContext context) + { + return await _dispatchRequestToCQRS.Handle(request, context); + } + public override async Task GetRole(GetRoleRequest request, ServerCallContext context) + { + return await _dispatchRequestToCQRS.Handle(request, context); + } + public override async Task GetAllRoleByFilter(GetAllRoleByFilterRequest request, ServerCallContext context) + { + return await _dispatchRequestToCQRS.Handle(request, context); + } +} diff --git a/src/CMSMicroservice.WebApi/Services/UserAddressService.cs b/src/CMSMicroservice.WebApi/Services/UserAddressService.cs new file mode 100644 index 0000000..8872b5a --- /dev/null +++ b/src/CMSMicroservice.WebApi/Services/UserAddressService.cs @@ -0,0 +1,37 @@ +using CMSMicroservice.Protobuf.Protos.UserAddress; +using CMSMicroservice.WebApi.Common.Services; +using CMSMicroservice.Application.UserAddressCQ.Commands.CreateNewUserAddress; +using CMSMicroservice.Application.UserAddressCQ.Commands.UpdateUserAddress; +using CMSMicroservice.Application.UserAddressCQ.Commands.DeleteUserAddress; +using CMSMicroservice.Application.UserAddressCQ.Queries.GetUserAddress; +using CMSMicroservice.Application.UserAddressCQ.Queries.GetAllUserAddressByFilter; +namespace CMSMicroservice.WebApi.Services; +public class UserAddressService : UserAddressContract.UserAddressContractBase +{ + private readonly IDispatchRequestToCQRS _dispatchRequestToCQRS; + + public UserAddressService(IDispatchRequestToCQRS dispatchRequestToCQRS) + { + _dispatchRequestToCQRS = dispatchRequestToCQRS; + } + public override async Task CreateNewUserAddress(CreateNewUserAddressRequest request, ServerCallContext context) + { + return await _dispatchRequestToCQRS.Handle(request, context); + } + public override async Task UpdateUserAddress(UpdateUserAddressRequest request, ServerCallContext context) + { + return await _dispatchRequestToCQRS.Handle(request, context); + } + public override async Task DeleteUserAddress(DeleteUserAddressRequest request, ServerCallContext context) + { + return await _dispatchRequestToCQRS.Handle(request, context); + } + public override async Task GetUserAddress(GetUserAddressRequest request, ServerCallContext context) + { + return await _dispatchRequestToCQRS.Handle(request, context); + } + public override async Task GetAllUserAddressByFilter(GetAllUserAddressByFilterRequest request, ServerCallContext context) + { + return await _dispatchRequestToCQRS.Handle(request, context); + } +} diff --git a/src/CMSMicroservice.WebApi/Services/UserOrderService.cs b/src/CMSMicroservice.WebApi/Services/UserOrderService.cs new file mode 100644 index 0000000..cb93971 --- /dev/null +++ b/src/CMSMicroservice.WebApi/Services/UserOrderService.cs @@ -0,0 +1,37 @@ +using CMSMicroservice.Protobuf.Protos.UserOrder; +using CMSMicroservice.WebApi.Common.Services; +using CMSMicroservice.Application.UserOrderCQ.Commands.CreateNewUserOrder; +using CMSMicroservice.Application.UserOrderCQ.Commands.UpdateUserOrder; +using CMSMicroservice.Application.UserOrderCQ.Commands.DeleteUserOrder; +using CMSMicroservice.Application.UserOrderCQ.Queries.GetUserOrder; +using CMSMicroservice.Application.UserOrderCQ.Queries.GetAllUserOrderByFilter; +namespace CMSMicroservice.WebApi.Services; +public class UserOrderService : UserOrderContract.UserOrderContractBase +{ + private readonly IDispatchRequestToCQRS _dispatchRequestToCQRS; + + public UserOrderService(IDispatchRequestToCQRS dispatchRequestToCQRS) + { + _dispatchRequestToCQRS = dispatchRequestToCQRS; + } + public override async Task CreateNewUserOrder(CreateNewUserOrderRequest request, ServerCallContext context) + { + return await _dispatchRequestToCQRS.Handle(request, context); + } + public override async Task UpdateUserOrder(UpdateUserOrderRequest request, ServerCallContext context) + { + return await _dispatchRequestToCQRS.Handle(request, context); + } + public override async Task DeleteUserOrder(DeleteUserOrderRequest request, ServerCallContext context) + { + return await _dispatchRequestToCQRS.Handle(request, context); + } + public override async Task GetUserOrder(GetUserOrderRequest request, ServerCallContext context) + { + return await _dispatchRequestToCQRS.Handle(request, context); + } + public override async Task GetAllUserOrderByFilter(GetAllUserOrderByFilterRequest request, ServerCallContext context) + { + return await _dispatchRequestToCQRS.Handle(request, context); + } +} diff --git a/src/CMSMicroservice.WebApi/Services/UserRoleService.cs b/src/CMSMicroservice.WebApi/Services/UserRoleService.cs new file mode 100644 index 0000000..dfb09be --- /dev/null +++ b/src/CMSMicroservice.WebApi/Services/UserRoleService.cs @@ -0,0 +1,37 @@ +using CMSMicroservice.Protobuf.Protos.UserRole; +using CMSMicroservice.WebApi.Common.Services; +using CMSMicroservice.Application.UserRoleCQ.Commands.CreateNewUserRole; +using CMSMicroservice.Application.UserRoleCQ.Commands.UpdateUserRole; +using CMSMicroservice.Application.UserRoleCQ.Commands.DeleteUserRole; +using CMSMicroservice.Application.UserRoleCQ.Queries.GetUserRole; +using CMSMicroservice.Application.UserRoleCQ.Queries.GetAllUserRoleByFilter; +namespace CMSMicroservice.WebApi.Services; +public class UserRoleService : UserRoleContract.UserRoleContractBase +{ + private readonly IDispatchRequestToCQRS _dispatchRequestToCQRS; + + public UserRoleService(IDispatchRequestToCQRS dispatchRequestToCQRS) + { + _dispatchRequestToCQRS = dispatchRequestToCQRS; + } + public override async Task CreateNewUserRole(CreateNewUserRoleRequest request, ServerCallContext context) + { + return await _dispatchRequestToCQRS.Handle(request, context); + } + public override async Task UpdateUserRole(UpdateUserRoleRequest request, ServerCallContext context) + { + return await _dispatchRequestToCQRS.Handle(request, context); + } + public override async Task DeleteUserRole(DeleteUserRoleRequest request, ServerCallContext context) + { + return await _dispatchRequestToCQRS.Handle(request, context); + } + public override async Task GetUserRole(GetUserRoleRequest request, ServerCallContext context) + { + return await _dispatchRequestToCQRS.Handle(request, context); + } + public override async Task GetAllUserRoleByFilter(GetAllUserRoleByFilterRequest request, ServerCallContext context) + { + return await _dispatchRequestToCQRS.Handle(request, context); + } +} diff --git a/src/CMSMicroservice.WebApi/Services/UserService.cs b/src/CMSMicroservice.WebApi/Services/UserService.cs new file mode 100644 index 0000000..f01ed16 --- /dev/null +++ b/src/CMSMicroservice.WebApi/Services/UserService.cs @@ -0,0 +1,37 @@ +using CMSMicroservice.Protobuf.Protos.User; +using CMSMicroservice.WebApi.Common.Services; +using CMSMicroservice.Application.UserCQ.Commands.CreateNewUser; +using CMSMicroservice.Application.UserCQ.Commands.UpdateUser; +using CMSMicroservice.Application.UserCQ.Commands.DeleteUser; +using CMSMicroservice.Application.UserCQ.Queries.GetUser; +using CMSMicroservice.Application.UserCQ.Queries.GetAllUserByFilter; +namespace CMSMicroservice.WebApi.Services; +public class UserService : UserContract.UserContractBase +{ + private readonly IDispatchRequestToCQRS _dispatchRequestToCQRS; + + public UserService(IDispatchRequestToCQRS dispatchRequestToCQRS) + { + _dispatchRequestToCQRS = dispatchRequestToCQRS; + } + public override async Task CreateNewUser(CreateNewUserRequest request, ServerCallContext context) + { + return await _dispatchRequestToCQRS.Handle(request, context); + } + public override async Task UpdateUser(UpdateUserRequest request, ServerCallContext context) + { + return await _dispatchRequestToCQRS.Handle(request, context); + } + public override async Task DeleteUser(DeleteUserRequest request, ServerCallContext context) + { + return await _dispatchRequestToCQRS.Handle(request, context); + } + public override async Task GetUser(GetUserRequest request, ServerCallContext context) + { + return await _dispatchRequestToCQRS.Handle(request, context); + } + public override async Task GetAllUserByFilter(GetAllUserByFilterRequest request, ServerCallContext context) + { + return await _dispatchRequestToCQRS.Handle(request, context); + } +} diff --git a/src/CMSMicroservice.WebApi/appsettings.Development.json b/src/CMSMicroservice.WebApi/appsettings.Development.json new file mode 100644 index 0000000..fe20c40 --- /dev/null +++ b/src/CMSMicroservice.WebApi/appsettings.Development.json @@ -0,0 +1,10 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Debug", + "System": "Information", + "Grpc": "Information", + "Microsoft": "Information" + } + } +} diff --git a/src/CMSMicroservice.WebApi/appsettings.json b/src/CMSMicroservice.WebApi/appsettings.json new file mode 100644 index 0000000..49c0979 --- /dev/null +++ b/src/CMSMicroservice.WebApi/appsettings.json @@ -0,0 +1,17 @@ +{ + "ConnectionStrings": { + "LogConnection": "Data Source=.,2019; Initial Catalog=DBName;User ID=dbuser;Password=dbpassword;Connection Timeout=300000;MultipleActiveResultSets=True;Encrypt=False", + "DefaultConnection": "Data Source=.,2019; Initial Catalog=DBName;User ID=dbuser;Password=dbpassword;Connection Timeout=300000;MultipleActiveResultSets=True;Encrypt=False", + "providerName": "System.Data.SqlClient" + }, + "AllowedHosts": "*", + "Kestrel": { + "EndpointDefaults": { + "Protocols": "Http2" + } + }, + "Authentication": { + "Authority": "https://ids.domain.com/", + "Audience": "domain_api" + } +}