From 0e32dc935985ce9a08177c74a96f2f1fc6a9d2cc Mon Sep 17 00:00:00 2001 From: generator Date: Sat, 27 Sep 2025 10:36:00 +0330 Subject: [PATCH] Generator Changes at 9/27/2025 10:36:00 AM --- .../Common/Behaviours/LoggingBehaviour.cs | 24 ++ .../Common/Behaviours/PerformanceBehaviour.cs | 43 ++ .../Behaviours/UnhandledExceptionBehaviour.cs | 31 ++ .../Common/Behaviours/ValidationBehaviour.cs | 37 ++ .../Common/Exceptions/DuplicateException.cs | 29 ++ .../Exceptions/ForbiddenAccessException.cs | 8 + .../Common/Exceptions/NotFoundException.cs | 24 ++ .../Common/Exceptions/ValidationException.cs | 22 + .../Interfaces/IApplicationContractContext.cs | 10 + .../Common/Interfaces/ICurrentUserService.cs | 6 + .../Common/Interfaces/ITokenProvider.cs | 6 + .../Common/Mappings/GeneralMapping.cs | 64 +++ .../Common/Mappings/PackageProfile.cs | 10 + .../Common/Mappings/RoleProfile.cs | 10 + .../Common/Mappings/UserAddressProfile.cs | 10 + .../Common/Mappings/UserOrderProfile.cs | 10 + .../Common/Mappings/UserProfile.cs | 10 + .../Common/Mappings/UserRoleProfile.cs | 10 + .../Common/Models/MetaData.cs | 22 + .../Common/Models/PaginationState.cs | 10 + .../ConfigureServices.cs | 32 ++ .../FrontOffice.BFF.Application.csproj | 18 + .../GlobalUsings.cs | 12 + .../CreateNewPackageCommand.cs | 13 + .../CreateNewPackageCommandHandler.cs | 16 + .../CreateNewPackageCommandValidator.cs | 22 + .../CreateNewPackageResponseDto.cs | 7 + .../DeletePackage/DeletePackageCommand.cs | 7 + .../DeletePackageCommandHandler.cs | 16 + .../DeletePackageCommandValidator.cs | 16 + .../UpdatePackage/UpdatePackageCommand.cs | 15 + .../UpdatePackageCommandHandler.cs | 16 + .../UpdatePackageCommandValidator.cs | 24 ++ .../GetAllPackageByFilterQuery.cs | 23 ++ .../GetAllPackageByFilterQueryHandler.cs | 16 + .../GetAllPackageByFilterQueryValidator.cs | 14 + .../GetAllPackageByFilterResponseDto.cs | 21 + .../Queries/GetPackage/GetPackageQuery.cs | 7 + .../GetPackage/GetPackageQueryHandler.cs | 16 + .../GetPackage/GetPackageQueryValidator.cs | 16 + .../GetPackage/GetPackageResponseDto.cs | 15 + .../CreateNewRole/CreateNewRoleCommand.cs | 9 + .../CreateNewRoleCommandHandler.cs | 16 + .../CreateNewRoleCommandValidator.cs | 18 + .../CreateNewRole/CreateNewRoleResponseDto.cs | 7 + .../Commands/DeleteRole/DeleteRoleCommand.cs | 7 + .../DeleteRole/DeleteRoleCommandHandler.cs | 16 + .../DeleteRole/DeleteRoleCommandValidator.cs | 16 + .../Commands/UpdateRole/UpdateRoleCommand.cs | 11 + .../UpdateRole/UpdateRoleCommandHandler.cs | 16 + .../UpdateRole/UpdateRoleCommandValidator.cs | 20 + .../GetAllRoleByFilterQuery.cs | 19 + .../GetAllRoleByFilterQueryHandler.cs | 16 + .../GetAllRoleByFilterQueryValidator.cs | 14 + .../GetAllRoleByFilterResponseDto.cs | 17 + .../RoleCQ/Queries/GetRole/GetRoleQuery.cs | 7 + .../Queries/GetRole/GetRoleQueryHandler.cs | 16 + .../Queries/GetRole/GetRoleQueryValidator.cs | 16 + .../Queries/GetRole/GetRoleResponseDto.cs | 11 + .../CreateNewUserAddressCommand.cs | 17 + .../CreateNewUserAddressCommandHandler.cs | 16 + .../CreateNewUserAddressCommandValidator.cs | 26 ++ .../CreateNewUserAddressResponseDto.cs | 7 + .../DeleteUserAddressCommand.cs | 7 + .../DeleteUserAddressCommandHandler.cs | 16 + .../DeleteUserAddressCommandValidator.cs | 16 + .../UpdateUserAddressCommand.cs | 19 + .../UpdateUserAddressCommandHandler.cs | 16 + .../UpdateUserAddressCommandValidator.cs | 28 ++ .../GetAllUserAddressByFilterQuery.cs | 27 ++ .../GetAllUserAddressByFilterQueryHandler.cs | 16 + ...GetAllUserAddressByFilterQueryValidator.cs | 14 + .../GetAllUserAddressByFilterResponseDto.cs | 25 ++ .../GetUserAddress/GetUserAddressQuery.cs | 7 + .../GetUserAddressQueryHandler.cs | 16 + .../GetUserAddressQueryValidator.cs | 16 + .../GetUserAddressResponseDto.cs | 19 + .../CreateNewUser/CreateNewUserCommand.cs | 17 + .../CreateNewUserCommandHandler.cs | 16 + .../CreateNewUserCommandValidator.cs | 16 + .../CreateNewUser/CreateNewUserResponseDto.cs | 7 + .../Commands/DeleteUser/DeleteUserCommand.cs | 7 + .../DeleteUser/DeleteUserCommandHandler.cs | 16 + .../DeleteUser/DeleteUserCommandValidator.cs | 16 + .../Commands/UpdateUser/UpdateUserCommand.cs | 19 + .../UpdateUser/UpdateUserCommandHandler.cs | 16 + .../UpdateUser/UpdateUserCommandValidator.cs | 18 + .../GetAllUserByFilterQuery.cs | 27 ++ .../GetAllUserByFilterQueryHandler.cs | 16 + .../GetAllUserByFilterQueryValidator.cs | 14 + .../GetAllUserByFilterResponseDto.cs | 25 ++ .../UserCQ/Queries/GetUser/GetUserQuery.cs | 7 + .../Queries/GetUser/GetUserQueryHandler.cs | 16 + .../Queries/GetUser/GetUserQueryValidator.cs | 16 + .../Queries/GetUser/GetUserResponseDto.cs | 19 + .../CreateNewUserOrderCommand.cs | 17 + .../CreateNewUserOrderCommandHandler.cs | 16 + .../CreateNewUserOrderCommandValidator.cs | 22 + .../CreateNewUserOrderResponseDto.cs | 7 + .../DeleteUserOrder/DeleteUserOrderCommand.cs | 7 + .../DeleteUserOrderCommandHandler.cs | 16 + .../DeleteUserOrderCommandValidator.cs | 16 + .../UpdateUserOrder/UpdateUserOrderCommand.cs | 19 + .../UpdateUserOrderCommandHandler.cs | 16 + .../UpdateUserOrderCommandValidator.cs | 24 ++ .../GetAllUserOrderByFilterQuery.cs | 27 ++ .../GetAllUserOrderByFilterQueryHandler.cs | 16 + .../GetAllUserOrderByFilterQueryValidator.cs | 14 + .../GetAllUserOrderByFilterResponseDto.cs | 25 ++ .../Queries/GetUserOrder/GetUserOrderQuery.cs | 7 + .../GetUserOrder/GetUserOrderQueryHandler.cs | 16 + .../GetUserOrderQueryValidator.cs | 16 + .../GetUserOrder/GetUserOrderResponseDto.cs | 19 + .../CreateNewUserRoleCommand.cs | 9 + .../CreateNewUserRoleCommandHandler.cs | 16 + .../CreateNewUserRoleCommandValidator.cs | 18 + .../CreateNewUserRoleResponseDto.cs | 7 + .../DeleteUserRole/DeleteUserRoleCommand.cs | 7 + .../DeleteUserRoleCommandHandler.cs | 16 + .../DeleteUserRoleCommandValidator.cs | 16 + .../UpdateUserRole/UpdateUserRoleCommand.cs | 11 + .../UpdateUserRoleCommandHandler.cs | 16 + .../UpdateUserRoleCommandValidator.cs | 20 + .../GetAllUserRoleByFilterQuery.cs | 19 + .../GetAllUserRoleByFilterQueryHandler.cs | 16 + .../GetAllUserRoleByFilterQueryValidator.cs | 14 + .../GetAllUserRoleByFilterResponseDto.cs | 17 + .../Queries/GetUserRole/GetUserRoleQuery.cs | 7 + .../GetUserRole/GetUserRoleQueryHandler.cs | 16 + .../GetUserRole/GetUserRoleQueryValidator.cs | 16 + .../GetUserRole/GetUserRoleResponseDto.cs | 11 + .../FrontOffice.BFF.Domain.csproj | 17 + .../ConfigureGrpcServices.cs | 101 +++++ .../ConfigureServices.cs | 77 ++++ .../FrontOffice.BFF.Infrastructure.csproj | 16 + .../GlobalUsings.cs | 5 + .../Services/ApplicationContractContext.cs | 36 ++ .../Common/Mappings/GeneralMapping.cs | 64 +++ .../Common/Mappings/PackageProfile.cs | 10 + .../Common/Mappings/RoleProfile.cs | 10 + .../Common/Mappings/UserAddressProfile.cs | 10 + .../Common/Mappings/UserOrderProfile.cs | 10 + .../Common/Mappings/UserProfile.cs | 10 + .../Common/Mappings/UserRoleProfile.cs | 10 + .../Common/Services/AppTokenProvider.cs | 49 +++ .../Common/Services/CurrentUserService.cs | 17 + .../Common/Services/DispatchRequestToCQRS.cs | 87 ++++ .../ConfigureServices.cs | 68 ++++ .../FrontOffice.BFF.WebApi.csproj | 32 ++ src/FrontOffice.BFF.WebApi/GlobalUsings.cs | 11 + src/FrontOffice.BFF.WebApi/Program.cs | 109 +++++ .../Services/PackageService.cs | 37 ++ .../Services/RoleService.cs | 37 ++ .../Services/UserAddressService.cs | 37 ++ .../Services/UserOrderService.cs | 37 ++ .../Services/UserRoleService.cs | 37 ++ .../Services/UserService.cs | 37 ++ .../appsettings.Development.json | 10 + src/FrontOffice.BFF.WebApi/appsettings.json | 19 + src/FrontOffice.BFF.sln | 39 ++ .../ConfigureServices.cs | 14 + .../FrontOffice.BFF.Package.Protobuf.csproj | 27 ++ .../Protos/google/api/annotations.proto | 31 ++ .../Protos/google/api/http.proto | 377 ++++++++++++++++++ .../Protos/package.proto | 135 +++++++ .../CreateNewPackageRequestValidator.cs | 25 ++ .../DeletePackageRequestValidator.cs | 19 + .../GetAllPackageByFilterRequestValidator.cs | 17 + .../Validator/GetPackageRequestValidator.cs | 19 + .../UpdatePackageRequestValidator.cs | 27 ++ .../ConfigureServices.cs | 14 + .../FrontOffice.BFF.Role.Protobuf.csproj | 27 ++ .../Protos/google/api/annotations.proto | 31 ++ .../Protos/google/api/http.proto | 377 ++++++++++++++++++ .../Protos/role.proto | 125 ++++++ .../CreateNewRoleRequestValidator.cs | 21 + .../Validator/DeleteRoleRequestValidator.cs | 19 + .../GetAllRoleByFilterRequestValidator.cs | 17 + .../Validator/GetRoleRequestValidator.cs | 19 + .../Validator/UpdateRoleRequestValidator.cs | 23 ++ .../ConfigureServices.cs | 14 + .../FrontOffice.BFF.User.Protobuf.csproj | 27 ++ .../Protos/google/api/annotations.proto | 31 ++ .../Protos/google/api/http.proto | 377 ++++++++++++++++++ .../Protos/user.proto | 145 +++++++ .../CreateNewUserRequestValidator.cs | 19 + .../Validator/DeleteUserRequestValidator.cs | 19 + .../GetAllUserByFilterRequestValidator.cs | 17 + .../Validator/GetUserRequestValidator.cs | 19 + .../Validator/UpdateUserRequestValidator.cs | 21 + .../ConfigureServices.cs | 14 + ...rontOffice.BFF.UserAddress.Protobuf.csproj | 27 ++ .../Protos/google/api/annotations.proto | 31 ++ .../Protos/google/api/http.proto | 377 ++++++++++++++++++ .../Protos/useraddress.proto | 145 +++++++ .../CreateNewUserAddressRequestValidator.cs | 29 ++ .../DeleteUserAddressRequestValidator.cs | 19 + ...tAllUserAddressByFilterRequestValidator.cs | 17 + .../GetUserAddressRequestValidator.cs | 19 + .../UpdateUserAddressRequestValidator.cs | 31 ++ .../ConfigureServices.cs | 14 + .../FrontOffice.BFF.UserOrder.Protobuf.csproj | 27 ++ .../Protos/google/api/annotations.proto | 31 ++ .../Protos/google/api/http.proto | 377 ++++++++++++++++++ .../Protos/userorder.proto | 145 +++++++ .../CreateNewUserOrderRequestValidator.cs | 25 ++ .../DeleteUserOrderRequestValidator.cs | 19 + ...GetAllUserOrderByFilterRequestValidator.cs | 17 + .../Validator/GetUserOrderRequestValidator.cs | 19 + .../UpdateUserOrderRequestValidator.cs | 27 ++ .../ConfigureServices.cs | 14 + .../FrontOffice.BFF.UserRole.Protobuf.csproj | 27 ++ .../Protos/google/api/annotations.proto | 31 ++ .../Protos/google/api/http.proto | 377 ++++++++++++++++++ .../Protos/userrole.proto | 125 ++++++ .../CreateNewUserRoleRequestValidator.cs | 21 + .../DeleteUserRoleRequestValidator.cs | 19 + .../GetAllUserRoleByFilterRequestValidator.cs | 17 + .../Validator/GetUserRoleRequestValidator.cs | 19 + .../UpdateUserRoleRequestValidator.cs | 23 ++ 220 files changed, 7313 insertions(+) create mode 100644 src/FrontOffice.BFF.Application/Common/Behaviours/LoggingBehaviour.cs create mode 100644 src/FrontOffice.BFF.Application/Common/Behaviours/PerformanceBehaviour.cs create mode 100644 src/FrontOffice.BFF.Application/Common/Behaviours/UnhandledExceptionBehaviour.cs create mode 100644 src/FrontOffice.BFF.Application/Common/Behaviours/ValidationBehaviour.cs create mode 100644 src/FrontOffice.BFF.Application/Common/Exceptions/DuplicateException.cs create mode 100644 src/FrontOffice.BFF.Application/Common/Exceptions/ForbiddenAccessException.cs create mode 100644 src/FrontOffice.BFF.Application/Common/Exceptions/NotFoundException.cs create mode 100644 src/FrontOffice.BFF.Application/Common/Exceptions/ValidationException.cs create mode 100644 src/FrontOffice.BFF.Application/Common/Interfaces/IApplicationContractContext.cs create mode 100644 src/FrontOffice.BFF.Application/Common/Interfaces/ICurrentUserService.cs create mode 100644 src/FrontOffice.BFF.Application/Common/Interfaces/ITokenProvider.cs create mode 100644 src/FrontOffice.BFF.Application/Common/Mappings/GeneralMapping.cs create mode 100644 src/FrontOffice.BFF.Application/Common/Mappings/PackageProfile.cs create mode 100644 src/FrontOffice.BFF.Application/Common/Mappings/RoleProfile.cs create mode 100644 src/FrontOffice.BFF.Application/Common/Mappings/UserAddressProfile.cs create mode 100644 src/FrontOffice.BFF.Application/Common/Mappings/UserOrderProfile.cs create mode 100644 src/FrontOffice.BFF.Application/Common/Mappings/UserProfile.cs create mode 100644 src/FrontOffice.BFF.Application/Common/Mappings/UserRoleProfile.cs create mode 100644 src/FrontOffice.BFF.Application/Common/Models/MetaData.cs create mode 100644 src/FrontOffice.BFF.Application/Common/Models/PaginationState.cs create mode 100644 src/FrontOffice.BFF.Application/ConfigureServices.cs create mode 100644 src/FrontOffice.BFF.Application/FrontOffice.BFF.Application.csproj create mode 100644 src/FrontOffice.BFF.Application/GlobalUsings.cs create mode 100644 src/FrontOffice.BFF.Application/PackageCQ/Commands/CreateNewPackage/CreateNewPackageCommand.cs create mode 100644 src/FrontOffice.BFF.Application/PackageCQ/Commands/CreateNewPackage/CreateNewPackageCommandHandler.cs create mode 100644 src/FrontOffice.BFF.Application/PackageCQ/Commands/CreateNewPackage/CreateNewPackageCommandValidator.cs create mode 100644 src/FrontOffice.BFF.Application/PackageCQ/Commands/CreateNewPackage/CreateNewPackageResponseDto.cs create mode 100644 src/FrontOffice.BFF.Application/PackageCQ/Commands/DeletePackage/DeletePackageCommand.cs create mode 100644 src/FrontOffice.BFF.Application/PackageCQ/Commands/DeletePackage/DeletePackageCommandHandler.cs create mode 100644 src/FrontOffice.BFF.Application/PackageCQ/Commands/DeletePackage/DeletePackageCommandValidator.cs create mode 100644 src/FrontOffice.BFF.Application/PackageCQ/Commands/UpdatePackage/UpdatePackageCommand.cs create mode 100644 src/FrontOffice.BFF.Application/PackageCQ/Commands/UpdatePackage/UpdatePackageCommandHandler.cs create mode 100644 src/FrontOffice.BFF.Application/PackageCQ/Commands/UpdatePackage/UpdatePackageCommandValidator.cs create mode 100644 src/FrontOffice.BFF.Application/PackageCQ/Queries/GetAllPackageByFilter/GetAllPackageByFilterQuery.cs create mode 100644 src/FrontOffice.BFF.Application/PackageCQ/Queries/GetAllPackageByFilter/GetAllPackageByFilterQueryHandler.cs create mode 100644 src/FrontOffice.BFF.Application/PackageCQ/Queries/GetAllPackageByFilter/GetAllPackageByFilterQueryValidator.cs create mode 100644 src/FrontOffice.BFF.Application/PackageCQ/Queries/GetAllPackageByFilter/GetAllPackageByFilterResponseDto.cs create mode 100644 src/FrontOffice.BFF.Application/PackageCQ/Queries/GetPackage/GetPackageQuery.cs create mode 100644 src/FrontOffice.BFF.Application/PackageCQ/Queries/GetPackage/GetPackageQueryHandler.cs create mode 100644 src/FrontOffice.BFF.Application/PackageCQ/Queries/GetPackage/GetPackageQueryValidator.cs create mode 100644 src/FrontOffice.BFF.Application/PackageCQ/Queries/GetPackage/GetPackageResponseDto.cs create mode 100644 src/FrontOffice.BFF.Application/RoleCQ/Commands/CreateNewRole/CreateNewRoleCommand.cs create mode 100644 src/FrontOffice.BFF.Application/RoleCQ/Commands/CreateNewRole/CreateNewRoleCommandHandler.cs create mode 100644 src/FrontOffice.BFF.Application/RoleCQ/Commands/CreateNewRole/CreateNewRoleCommandValidator.cs create mode 100644 src/FrontOffice.BFF.Application/RoleCQ/Commands/CreateNewRole/CreateNewRoleResponseDto.cs create mode 100644 src/FrontOffice.BFF.Application/RoleCQ/Commands/DeleteRole/DeleteRoleCommand.cs create mode 100644 src/FrontOffice.BFF.Application/RoleCQ/Commands/DeleteRole/DeleteRoleCommandHandler.cs create mode 100644 src/FrontOffice.BFF.Application/RoleCQ/Commands/DeleteRole/DeleteRoleCommandValidator.cs create mode 100644 src/FrontOffice.BFF.Application/RoleCQ/Commands/UpdateRole/UpdateRoleCommand.cs create mode 100644 src/FrontOffice.BFF.Application/RoleCQ/Commands/UpdateRole/UpdateRoleCommandHandler.cs create mode 100644 src/FrontOffice.BFF.Application/RoleCQ/Commands/UpdateRole/UpdateRoleCommandValidator.cs create mode 100644 src/FrontOffice.BFF.Application/RoleCQ/Queries/GetAllRoleByFilter/GetAllRoleByFilterQuery.cs create mode 100644 src/FrontOffice.BFF.Application/RoleCQ/Queries/GetAllRoleByFilter/GetAllRoleByFilterQueryHandler.cs create mode 100644 src/FrontOffice.BFF.Application/RoleCQ/Queries/GetAllRoleByFilter/GetAllRoleByFilterQueryValidator.cs create mode 100644 src/FrontOffice.BFF.Application/RoleCQ/Queries/GetAllRoleByFilter/GetAllRoleByFilterResponseDto.cs create mode 100644 src/FrontOffice.BFF.Application/RoleCQ/Queries/GetRole/GetRoleQuery.cs create mode 100644 src/FrontOffice.BFF.Application/RoleCQ/Queries/GetRole/GetRoleQueryHandler.cs create mode 100644 src/FrontOffice.BFF.Application/RoleCQ/Queries/GetRole/GetRoleQueryValidator.cs create mode 100644 src/FrontOffice.BFF.Application/RoleCQ/Queries/GetRole/GetRoleResponseDto.cs create mode 100644 src/FrontOffice.BFF.Application/UserAddressCQ/Commands/CreateNewUserAddress/CreateNewUserAddressCommand.cs create mode 100644 src/FrontOffice.BFF.Application/UserAddressCQ/Commands/CreateNewUserAddress/CreateNewUserAddressCommandHandler.cs create mode 100644 src/FrontOffice.BFF.Application/UserAddressCQ/Commands/CreateNewUserAddress/CreateNewUserAddressCommandValidator.cs create mode 100644 src/FrontOffice.BFF.Application/UserAddressCQ/Commands/CreateNewUserAddress/CreateNewUserAddressResponseDto.cs create mode 100644 src/FrontOffice.BFF.Application/UserAddressCQ/Commands/DeleteUserAddress/DeleteUserAddressCommand.cs create mode 100644 src/FrontOffice.BFF.Application/UserAddressCQ/Commands/DeleteUserAddress/DeleteUserAddressCommandHandler.cs create mode 100644 src/FrontOffice.BFF.Application/UserAddressCQ/Commands/DeleteUserAddress/DeleteUserAddressCommandValidator.cs create mode 100644 src/FrontOffice.BFF.Application/UserAddressCQ/Commands/UpdateUserAddress/UpdateUserAddressCommand.cs create mode 100644 src/FrontOffice.BFF.Application/UserAddressCQ/Commands/UpdateUserAddress/UpdateUserAddressCommandHandler.cs create mode 100644 src/FrontOffice.BFF.Application/UserAddressCQ/Commands/UpdateUserAddress/UpdateUserAddressCommandValidator.cs create mode 100644 src/FrontOffice.BFF.Application/UserAddressCQ/Queries/GetAllUserAddressByFilter/GetAllUserAddressByFilterQuery.cs create mode 100644 src/FrontOffice.BFF.Application/UserAddressCQ/Queries/GetAllUserAddressByFilter/GetAllUserAddressByFilterQueryHandler.cs create mode 100644 src/FrontOffice.BFF.Application/UserAddressCQ/Queries/GetAllUserAddressByFilter/GetAllUserAddressByFilterQueryValidator.cs create mode 100644 src/FrontOffice.BFF.Application/UserAddressCQ/Queries/GetAllUserAddressByFilter/GetAllUserAddressByFilterResponseDto.cs create mode 100644 src/FrontOffice.BFF.Application/UserAddressCQ/Queries/GetUserAddress/GetUserAddressQuery.cs create mode 100644 src/FrontOffice.BFF.Application/UserAddressCQ/Queries/GetUserAddress/GetUserAddressQueryHandler.cs create mode 100644 src/FrontOffice.BFF.Application/UserAddressCQ/Queries/GetUserAddress/GetUserAddressQueryValidator.cs create mode 100644 src/FrontOffice.BFF.Application/UserAddressCQ/Queries/GetUserAddress/GetUserAddressResponseDto.cs create mode 100644 src/FrontOffice.BFF.Application/UserCQ/Commands/CreateNewUser/CreateNewUserCommand.cs create mode 100644 src/FrontOffice.BFF.Application/UserCQ/Commands/CreateNewUser/CreateNewUserCommandHandler.cs create mode 100644 src/FrontOffice.BFF.Application/UserCQ/Commands/CreateNewUser/CreateNewUserCommandValidator.cs create mode 100644 src/FrontOffice.BFF.Application/UserCQ/Commands/CreateNewUser/CreateNewUserResponseDto.cs create mode 100644 src/FrontOffice.BFF.Application/UserCQ/Commands/DeleteUser/DeleteUserCommand.cs create mode 100644 src/FrontOffice.BFF.Application/UserCQ/Commands/DeleteUser/DeleteUserCommandHandler.cs create mode 100644 src/FrontOffice.BFF.Application/UserCQ/Commands/DeleteUser/DeleteUserCommandValidator.cs create mode 100644 src/FrontOffice.BFF.Application/UserCQ/Commands/UpdateUser/UpdateUserCommand.cs create mode 100644 src/FrontOffice.BFF.Application/UserCQ/Commands/UpdateUser/UpdateUserCommandHandler.cs create mode 100644 src/FrontOffice.BFF.Application/UserCQ/Commands/UpdateUser/UpdateUserCommandValidator.cs create mode 100644 src/FrontOffice.BFF.Application/UserCQ/Queries/GetAllUserByFilter/GetAllUserByFilterQuery.cs create mode 100644 src/FrontOffice.BFF.Application/UserCQ/Queries/GetAllUserByFilter/GetAllUserByFilterQueryHandler.cs create mode 100644 src/FrontOffice.BFF.Application/UserCQ/Queries/GetAllUserByFilter/GetAllUserByFilterQueryValidator.cs create mode 100644 src/FrontOffice.BFF.Application/UserCQ/Queries/GetAllUserByFilter/GetAllUserByFilterResponseDto.cs create mode 100644 src/FrontOffice.BFF.Application/UserCQ/Queries/GetUser/GetUserQuery.cs create mode 100644 src/FrontOffice.BFF.Application/UserCQ/Queries/GetUser/GetUserQueryHandler.cs create mode 100644 src/FrontOffice.BFF.Application/UserCQ/Queries/GetUser/GetUserQueryValidator.cs create mode 100644 src/FrontOffice.BFF.Application/UserCQ/Queries/GetUser/GetUserResponseDto.cs create mode 100644 src/FrontOffice.BFF.Application/UserOrderCQ/Commands/CreateNewUserOrder/CreateNewUserOrderCommand.cs create mode 100644 src/FrontOffice.BFF.Application/UserOrderCQ/Commands/CreateNewUserOrder/CreateNewUserOrderCommandHandler.cs create mode 100644 src/FrontOffice.BFF.Application/UserOrderCQ/Commands/CreateNewUserOrder/CreateNewUserOrderCommandValidator.cs create mode 100644 src/FrontOffice.BFF.Application/UserOrderCQ/Commands/CreateNewUserOrder/CreateNewUserOrderResponseDto.cs create mode 100644 src/FrontOffice.BFF.Application/UserOrderCQ/Commands/DeleteUserOrder/DeleteUserOrderCommand.cs create mode 100644 src/FrontOffice.BFF.Application/UserOrderCQ/Commands/DeleteUserOrder/DeleteUserOrderCommandHandler.cs create mode 100644 src/FrontOffice.BFF.Application/UserOrderCQ/Commands/DeleteUserOrder/DeleteUserOrderCommandValidator.cs create mode 100644 src/FrontOffice.BFF.Application/UserOrderCQ/Commands/UpdateUserOrder/UpdateUserOrderCommand.cs create mode 100644 src/FrontOffice.BFF.Application/UserOrderCQ/Commands/UpdateUserOrder/UpdateUserOrderCommandHandler.cs create mode 100644 src/FrontOffice.BFF.Application/UserOrderCQ/Commands/UpdateUserOrder/UpdateUserOrderCommandValidator.cs create mode 100644 src/FrontOffice.BFF.Application/UserOrderCQ/Queries/GetAllUserOrderByFilter/GetAllUserOrderByFilterQuery.cs create mode 100644 src/FrontOffice.BFF.Application/UserOrderCQ/Queries/GetAllUserOrderByFilter/GetAllUserOrderByFilterQueryHandler.cs create mode 100644 src/FrontOffice.BFF.Application/UserOrderCQ/Queries/GetAllUserOrderByFilter/GetAllUserOrderByFilterQueryValidator.cs create mode 100644 src/FrontOffice.BFF.Application/UserOrderCQ/Queries/GetAllUserOrderByFilter/GetAllUserOrderByFilterResponseDto.cs create mode 100644 src/FrontOffice.BFF.Application/UserOrderCQ/Queries/GetUserOrder/GetUserOrderQuery.cs create mode 100644 src/FrontOffice.BFF.Application/UserOrderCQ/Queries/GetUserOrder/GetUserOrderQueryHandler.cs create mode 100644 src/FrontOffice.BFF.Application/UserOrderCQ/Queries/GetUserOrder/GetUserOrderQueryValidator.cs create mode 100644 src/FrontOffice.BFF.Application/UserOrderCQ/Queries/GetUserOrder/GetUserOrderResponseDto.cs create mode 100644 src/FrontOffice.BFF.Application/UserRoleCQ/Commands/CreateNewUserRole/CreateNewUserRoleCommand.cs create mode 100644 src/FrontOffice.BFF.Application/UserRoleCQ/Commands/CreateNewUserRole/CreateNewUserRoleCommandHandler.cs create mode 100644 src/FrontOffice.BFF.Application/UserRoleCQ/Commands/CreateNewUserRole/CreateNewUserRoleCommandValidator.cs create mode 100644 src/FrontOffice.BFF.Application/UserRoleCQ/Commands/CreateNewUserRole/CreateNewUserRoleResponseDto.cs create mode 100644 src/FrontOffice.BFF.Application/UserRoleCQ/Commands/DeleteUserRole/DeleteUserRoleCommand.cs create mode 100644 src/FrontOffice.BFF.Application/UserRoleCQ/Commands/DeleteUserRole/DeleteUserRoleCommandHandler.cs create mode 100644 src/FrontOffice.BFF.Application/UserRoleCQ/Commands/DeleteUserRole/DeleteUserRoleCommandValidator.cs create mode 100644 src/FrontOffice.BFF.Application/UserRoleCQ/Commands/UpdateUserRole/UpdateUserRoleCommand.cs create mode 100644 src/FrontOffice.BFF.Application/UserRoleCQ/Commands/UpdateUserRole/UpdateUserRoleCommandHandler.cs create mode 100644 src/FrontOffice.BFF.Application/UserRoleCQ/Commands/UpdateUserRole/UpdateUserRoleCommandValidator.cs create mode 100644 src/FrontOffice.BFF.Application/UserRoleCQ/Queries/GetAllUserRoleByFilter/GetAllUserRoleByFilterQuery.cs create mode 100644 src/FrontOffice.BFF.Application/UserRoleCQ/Queries/GetAllUserRoleByFilter/GetAllUserRoleByFilterQueryHandler.cs create mode 100644 src/FrontOffice.BFF.Application/UserRoleCQ/Queries/GetAllUserRoleByFilter/GetAllUserRoleByFilterQueryValidator.cs create mode 100644 src/FrontOffice.BFF.Application/UserRoleCQ/Queries/GetAllUserRoleByFilter/GetAllUserRoleByFilterResponseDto.cs create mode 100644 src/FrontOffice.BFF.Application/UserRoleCQ/Queries/GetUserRole/GetUserRoleQuery.cs create mode 100644 src/FrontOffice.BFF.Application/UserRoleCQ/Queries/GetUserRole/GetUserRoleQueryHandler.cs create mode 100644 src/FrontOffice.BFF.Application/UserRoleCQ/Queries/GetUserRole/GetUserRoleQueryValidator.cs create mode 100644 src/FrontOffice.BFF.Application/UserRoleCQ/Queries/GetUserRole/GetUserRoleResponseDto.cs create mode 100644 src/FrontOffice.BFF.Domain/FrontOffice.BFF.Domain.csproj create mode 100644 src/FrontOffice.BFF.Infrastructure/ConfigureGrpcServices.cs create mode 100644 src/FrontOffice.BFF.Infrastructure/ConfigureServices.cs create mode 100644 src/FrontOffice.BFF.Infrastructure/FrontOffice.BFF.Infrastructure.csproj create mode 100644 src/FrontOffice.BFF.Infrastructure/GlobalUsings.cs create mode 100644 src/FrontOffice.BFF.Infrastructure/Services/ApplicationContractContext.cs create mode 100644 src/FrontOffice.BFF.WebApi/Common/Mappings/GeneralMapping.cs create mode 100644 src/FrontOffice.BFF.WebApi/Common/Mappings/PackageProfile.cs create mode 100644 src/FrontOffice.BFF.WebApi/Common/Mappings/RoleProfile.cs create mode 100644 src/FrontOffice.BFF.WebApi/Common/Mappings/UserAddressProfile.cs create mode 100644 src/FrontOffice.BFF.WebApi/Common/Mappings/UserOrderProfile.cs create mode 100644 src/FrontOffice.BFF.WebApi/Common/Mappings/UserProfile.cs create mode 100644 src/FrontOffice.BFF.WebApi/Common/Mappings/UserRoleProfile.cs create mode 100644 src/FrontOffice.BFF.WebApi/Common/Services/AppTokenProvider.cs create mode 100644 src/FrontOffice.BFF.WebApi/Common/Services/CurrentUserService.cs create mode 100644 src/FrontOffice.BFF.WebApi/Common/Services/DispatchRequestToCQRS.cs create mode 100644 src/FrontOffice.BFF.WebApi/ConfigureServices.cs create mode 100644 src/FrontOffice.BFF.WebApi/FrontOffice.BFF.WebApi.csproj create mode 100644 src/FrontOffice.BFF.WebApi/GlobalUsings.cs create mode 100644 src/FrontOffice.BFF.WebApi/Program.cs create mode 100644 src/FrontOffice.BFF.WebApi/Services/PackageService.cs create mode 100644 src/FrontOffice.BFF.WebApi/Services/RoleService.cs create mode 100644 src/FrontOffice.BFF.WebApi/Services/UserAddressService.cs create mode 100644 src/FrontOffice.BFF.WebApi/Services/UserOrderService.cs create mode 100644 src/FrontOffice.BFF.WebApi/Services/UserRoleService.cs create mode 100644 src/FrontOffice.BFF.WebApi/Services/UserService.cs create mode 100644 src/FrontOffice.BFF.WebApi/appsettings.Development.json create mode 100644 src/FrontOffice.BFF.WebApi/appsettings.json create mode 100644 src/FrontOffice.BFF.sln create mode 100644 src/Protobufs/FrontOffice.BFF.Package.Protobuf/ConfigureServices.cs create mode 100644 src/Protobufs/FrontOffice.BFF.Package.Protobuf/FrontOffice.BFF.Package.Protobuf.csproj create mode 100644 src/Protobufs/FrontOffice.BFF.Package.Protobuf/Protos/google/api/annotations.proto create mode 100644 src/Protobufs/FrontOffice.BFF.Package.Protobuf/Protos/google/api/http.proto create mode 100644 src/Protobufs/FrontOffice.BFF.Package.Protobuf/Protos/package.proto create mode 100644 src/Protobufs/FrontOffice.BFF.Package.Protobuf/Validator/CreateNewPackageRequestValidator.cs create mode 100644 src/Protobufs/FrontOffice.BFF.Package.Protobuf/Validator/DeletePackageRequestValidator.cs create mode 100644 src/Protobufs/FrontOffice.BFF.Package.Protobuf/Validator/GetAllPackageByFilterRequestValidator.cs create mode 100644 src/Protobufs/FrontOffice.BFF.Package.Protobuf/Validator/GetPackageRequestValidator.cs create mode 100644 src/Protobufs/FrontOffice.BFF.Package.Protobuf/Validator/UpdatePackageRequestValidator.cs create mode 100644 src/Protobufs/FrontOffice.BFF.Role.Protobuf/ConfigureServices.cs create mode 100644 src/Protobufs/FrontOffice.BFF.Role.Protobuf/FrontOffice.BFF.Role.Protobuf.csproj create mode 100644 src/Protobufs/FrontOffice.BFF.Role.Protobuf/Protos/google/api/annotations.proto create mode 100644 src/Protobufs/FrontOffice.BFF.Role.Protobuf/Protos/google/api/http.proto create mode 100644 src/Protobufs/FrontOffice.BFF.Role.Protobuf/Protos/role.proto create mode 100644 src/Protobufs/FrontOffice.BFF.Role.Protobuf/Validator/CreateNewRoleRequestValidator.cs create mode 100644 src/Protobufs/FrontOffice.BFF.Role.Protobuf/Validator/DeleteRoleRequestValidator.cs create mode 100644 src/Protobufs/FrontOffice.BFF.Role.Protobuf/Validator/GetAllRoleByFilterRequestValidator.cs create mode 100644 src/Protobufs/FrontOffice.BFF.Role.Protobuf/Validator/GetRoleRequestValidator.cs create mode 100644 src/Protobufs/FrontOffice.BFF.Role.Protobuf/Validator/UpdateRoleRequestValidator.cs create mode 100644 src/Protobufs/FrontOffice.BFF.User.Protobuf/ConfigureServices.cs create mode 100644 src/Protobufs/FrontOffice.BFF.User.Protobuf/FrontOffice.BFF.User.Protobuf.csproj create mode 100644 src/Protobufs/FrontOffice.BFF.User.Protobuf/Protos/google/api/annotations.proto create mode 100644 src/Protobufs/FrontOffice.BFF.User.Protobuf/Protos/google/api/http.proto create mode 100644 src/Protobufs/FrontOffice.BFF.User.Protobuf/Protos/user.proto create mode 100644 src/Protobufs/FrontOffice.BFF.User.Protobuf/Validator/CreateNewUserRequestValidator.cs create mode 100644 src/Protobufs/FrontOffice.BFF.User.Protobuf/Validator/DeleteUserRequestValidator.cs create mode 100644 src/Protobufs/FrontOffice.BFF.User.Protobuf/Validator/GetAllUserByFilterRequestValidator.cs create mode 100644 src/Protobufs/FrontOffice.BFF.User.Protobuf/Validator/GetUserRequestValidator.cs create mode 100644 src/Protobufs/FrontOffice.BFF.User.Protobuf/Validator/UpdateUserRequestValidator.cs create mode 100644 src/Protobufs/FrontOffice.BFF.UserAddress.Protobuf/ConfigureServices.cs create mode 100644 src/Protobufs/FrontOffice.BFF.UserAddress.Protobuf/FrontOffice.BFF.UserAddress.Protobuf.csproj create mode 100644 src/Protobufs/FrontOffice.BFF.UserAddress.Protobuf/Protos/google/api/annotations.proto create mode 100644 src/Protobufs/FrontOffice.BFF.UserAddress.Protobuf/Protos/google/api/http.proto create mode 100644 src/Protobufs/FrontOffice.BFF.UserAddress.Protobuf/Protos/useraddress.proto create mode 100644 src/Protobufs/FrontOffice.BFF.UserAddress.Protobuf/Validator/CreateNewUserAddressRequestValidator.cs create mode 100644 src/Protobufs/FrontOffice.BFF.UserAddress.Protobuf/Validator/DeleteUserAddressRequestValidator.cs create mode 100644 src/Protobufs/FrontOffice.BFF.UserAddress.Protobuf/Validator/GetAllUserAddressByFilterRequestValidator.cs create mode 100644 src/Protobufs/FrontOffice.BFF.UserAddress.Protobuf/Validator/GetUserAddressRequestValidator.cs create mode 100644 src/Protobufs/FrontOffice.BFF.UserAddress.Protobuf/Validator/UpdateUserAddressRequestValidator.cs create mode 100644 src/Protobufs/FrontOffice.BFF.UserOrder.Protobuf/ConfigureServices.cs create mode 100644 src/Protobufs/FrontOffice.BFF.UserOrder.Protobuf/FrontOffice.BFF.UserOrder.Protobuf.csproj create mode 100644 src/Protobufs/FrontOffice.BFF.UserOrder.Protobuf/Protos/google/api/annotations.proto create mode 100644 src/Protobufs/FrontOffice.BFF.UserOrder.Protobuf/Protos/google/api/http.proto create mode 100644 src/Protobufs/FrontOffice.BFF.UserOrder.Protobuf/Protos/userorder.proto create mode 100644 src/Protobufs/FrontOffice.BFF.UserOrder.Protobuf/Validator/CreateNewUserOrderRequestValidator.cs create mode 100644 src/Protobufs/FrontOffice.BFF.UserOrder.Protobuf/Validator/DeleteUserOrderRequestValidator.cs create mode 100644 src/Protobufs/FrontOffice.BFF.UserOrder.Protobuf/Validator/GetAllUserOrderByFilterRequestValidator.cs create mode 100644 src/Protobufs/FrontOffice.BFF.UserOrder.Protobuf/Validator/GetUserOrderRequestValidator.cs create mode 100644 src/Protobufs/FrontOffice.BFF.UserOrder.Protobuf/Validator/UpdateUserOrderRequestValidator.cs create mode 100644 src/Protobufs/FrontOffice.BFF.UserRole.Protobuf/ConfigureServices.cs create mode 100644 src/Protobufs/FrontOffice.BFF.UserRole.Protobuf/FrontOffice.BFF.UserRole.Protobuf.csproj create mode 100644 src/Protobufs/FrontOffice.BFF.UserRole.Protobuf/Protos/google/api/annotations.proto create mode 100644 src/Protobufs/FrontOffice.BFF.UserRole.Protobuf/Protos/google/api/http.proto create mode 100644 src/Protobufs/FrontOffice.BFF.UserRole.Protobuf/Protos/userrole.proto create mode 100644 src/Protobufs/FrontOffice.BFF.UserRole.Protobuf/Validator/CreateNewUserRoleRequestValidator.cs create mode 100644 src/Protobufs/FrontOffice.BFF.UserRole.Protobuf/Validator/DeleteUserRoleRequestValidator.cs create mode 100644 src/Protobufs/FrontOffice.BFF.UserRole.Protobuf/Validator/GetAllUserRoleByFilterRequestValidator.cs create mode 100644 src/Protobufs/FrontOffice.BFF.UserRole.Protobuf/Validator/GetUserRoleRequestValidator.cs create mode 100644 src/Protobufs/FrontOffice.BFF.UserRole.Protobuf/Validator/UpdateUserRoleRequestValidator.cs diff --git a/src/FrontOffice.BFF.Application/Common/Behaviours/LoggingBehaviour.cs b/src/FrontOffice.BFF.Application/Common/Behaviours/LoggingBehaviour.cs new file mode 100644 index 0000000..7958111 --- /dev/null +++ b/src/FrontOffice.BFF.Application/Common/Behaviours/LoggingBehaviour.cs @@ -0,0 +1,24 @@ +using MediatR.Pipeline; +using Microsoft.Extensions.Logging; + +namespace FrontOffice.BFF.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/FrontOffice.BFF.Application/Common/Behaviours/PerformanceBehaviour.cs b/src/FrontOffice.BFF.Application/Common/Behaviours/PerformanceBehaviour.cs new file mode 100644 index 0000000..51f16ce --- /dev/null +++ b/src/FrontOffice.BFF.Application/Common/Behaviours/PerformanceBehaviour.cs @@ -0,0 +1,43 @@ +using System.Diagnostics; +using MediatR; +using Microsoft.Extensions.Logging; + +namespace FrontOffice.BFF.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/FrontOffice.BFF.Application/Common/Behaviours/UnhandledExceptionBehaviour.cs b/src/FrontOffice.BFF.Application/Common/Behaviours/UnhandledExceptionBehaviour.cs new file mode 100644 index 0000000..f4e7810 --- /dev/null +++ b/src/FrontOffice.BFF.Application/Common/Behaviours/UnhandledExceptionBehaviour.cs @@ -0,0 +1,31 @@ +using Microsoft.Extensions.Logging; + +namespace FrontOffice.BFF.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/FrontOffice.BFF.Application/Common/Behaviours/ValidationBehaviour.cs b/src/FrontOffice.BFF.Application/Common/Behaviours/ValidationBehaviour.cs new file mode 100644 index 0000000..fe84d14 --- /dev/null +++ b/src/FrontOffice.BFF.Application/Common/Behaviours/ValidationBehaviour.cs @@ -0,0 +1,37 @@ +using ValidationException = FrontOffice.BFF.Application.Common.Exceptions.ValidationException; + +namespace FrontOffice.BFF.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/FrontOffice.BFF.Application/Common/Exceptions/DuplicateException.cs b/src/FrontOffice.BFF.Application/Common/Exceptions/DuplicateException.cs new file mode 100644 index 0000000..362ab97 --- /dev/null +++ b/src/FrontOffice.BFF.Application/Common/Exceptions/DuplicateException.cs @@ -0,0 +1,29 @@ +namespace FrontOffice.BFF.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/FrontOffice.BFF.Application/Common/Exceptions/ForbiddenAccessException.cs b/src/FrontOffice.BFF.Application/Common/Exceptions/ForbiddenAccessException.cs new file mode 100644 index 0000000..590d946 --- /dev/null +++ b/src/FrontOffice.BFF.Application/Common/Exceptions/ForbiddenAccessException.cs @@ -0,0 +1,8 @@ +namespace FrontOffice.BFF.Application.Common.Exceptions; + +public class ForbiddenAccessException : Exception +{ + public ForbiddenAccessException() : base() + { + } +} diff --git a/src/FrontOffice.BFF.Application/Common/Exceptions/NotFoundException.cs b/src/FrontOffice.BFF.Application/Common/Exceptions/NotFoundException.cs new file mode 100644 index 0000000..bdc70d9 --- /dev/null +++ b/src/FrontOffice.BFF.Application/Common/Exceptions/NotFoundException.cs @@ -0,0 +1,24 @@ +namespace FrontOffice.BFF.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/FrontOffice.BFF.Application/Common/Exceptions/ValidationException.cs b/src/FrontOffice.BFF.Application/Common/Exceptions/ValidationException.cs new file mode 100644 index 0000000..bcc839e --- /dev/null +++ b/src/FrontOffice.BFF.Application/Common/Exceptions/ValidationException.cs @@ -0,0 +1,22 @@ +using FluentValidation.Results; + +namespace FrontOffice.BFF.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/FrontOffice.BFF.Application/Common/Interfaces/IApplicationContractContext.cs b/src/FrontOffice.BFF.Application/Common/Interfaces/IApplicationContractContext.cs new file mode 100644 index 0000000..235732f --- /dev/null +++ b/src/FrontOffice.BFF.Application/Common/Interfaces/IApplicationContractContext.cs @@ -0,0 +1,10 @@ +namespace FrontOffice.BFF.Application.Common.Interfaces; + +public interface IApplicationContractContext +{ + #region FM + + //FileLogContract.FileLogContractClient FileManagements { get; } + + #endregion +} diff --git a/src/FrontOffice.BFF.Application/Common/Interfaces/ICurrentUserService.cs b/src/FrontOffice.BFF.Application/Common/Interfaces/ICurrentUserService.cs new file mode 100644 index 0000000..af29fdd --- /dev/null +++ b/src/FrontOffice.BFF.Application/Common/Interfaces/ICurrentUserService.cs @@ -0,0 +1,6 @@ +namespace FrontOffice.BFF.Application.Common.Interfaces; + +public interface ICurrentUserService +{ + string? UserId { get; } +} diff --git a/src/FrontOffice.BFF.Application/Common/Interfaces/ITokenProvider.cs b/src/FrontOffice.BFF.Application/Common/Interfaces/ITokenProvider.cs new file mode 100644 index 0000000..bd0f76c --- /dev/null +++ b/src/FrontOffice.BFF.Application/Common/Interfaces/ITokenProvider.cs @@ -0,0 +1,6 @@ +namespace FrontOffice.BFF.Application.Common.Interfaces; + +public interface ITokenProvider +{ + Task GetTokenAsync(); +} diff --git a/src/FrontOffice.BFF.Application/Common/Mappings/GeneralMapping.cs b/src/FrontOffice.BFF.Application/Common/Mappings/GeneralMapping.cs new file mode 100644 index 0000000..694f38d --- /dev/null +++ b/src/FrontOffice.BFF.Application/Common/Mappings/GeneralMapping.cs @@ -0,0 +1,64 @@ +using System.Globalization; +namespace FrontOffice.BFF.Application.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/FrontOffice.BFF.Application/Common/Mappings/PackageProfile.cs b/src/FrontOffice.BFF.Application/Common/Mappings/PackageProfile.cs new file mode 100644 index 0000000..822723f --- /dev/null +++ b/src/FrontOffice.BFF.Application/Common/Mappings/PackageProfile.cs @@ -0,0 +1,10 @@ +namespace FrontOffice.BFF.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/FrontOffice.BFF.Application/Common/Mappings/RoleProfile.cs b/src/FrontOffice.BFF.Application/Common/Mappings/RoleProfile.cs new file mode 100644 index 0000000..aad0cc1 --- /dev/null +++ b/src/FrontOffice.BFF.Application/Common/Mappings/RoleProfile.cs @@ -0,0 +1,10 @@ +namespace FrontOffice.BFF.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/FrontOffice.BFF.Application/Common/Mappings/UserAddressProfile.cs b/src/FrontOffice.BFF.Application/Common/Mappings/UserAddressProfile.cs new file mode 100644 index 0000000..edc2ef5 --- /dev/null +++ b/src/FrontOffice.BFF.Application/Common/Mappings/UserAddressProfile.cs @@ -0,0 +1,10 @@ +namespace FrontOffice.BFF.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/FrontOffice.BFF.Application/Common/Mappings/UserOrderProfile.cs b/src/FrontOffice.BFF.Application/Common/Mappings/UserOrderProfile.cs new file mode 100644 index 0000000..3707b7b --- /dev/null +++ b/src/FrontOffice.BFF.Application/Common/Mappings/UserOrderProfile.cs @@ -0,0 +1,10 @@ +namespace FrontOffice.BFF.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/FrontOffice.BFF.Application/Common/Mappings/UserProfile.cs b/src/FrontOffice.BFF.Application/Common/Mappings/UserProfile.cs new file mode 100644 index 0000000..5fe23f9 --- /dev/null +++ b/src/FrontOffice.BFF.Application/Common/Mappings/UserProfile.cs @@ -0,0 +1,10 @@ +namespace FrontOffice.BFF.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/FrontOffice.BFF.Application/Common/Mappings/UserRoleProfile.cs b/src/FrontOffice.BFF.Application/Common/Mappings/UserRoleProfile.cs new file mode 100644 index 0000000..b5e81cf --- /dev/null +++ b/src/FrontOffice.BFF.Application/Common/Mappings/UserRoleProfile.cs @@ -0,0 +1,10 @@ +namespace FrontOffice.BFF.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/FrontOffice.BFF.Application/Common/Models/MetaData.cs b/src/FrontOffice.BFF.Application/Common/Models/MetaData.cs new file mode 100644 index 0000000..aae4270 --- /dev/null +++ b/src/FrontOffice.BFF.Application/Common/Models/MetaData.cs @@ -0,0 +1,22 @@ +namespace FrontOffice.BFF.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/FrontOffice.BFF.Application/Common/Models/PaginationState.cs b/src/FrontOffice.BFF.Application/Common/Models/PaginationState.cs new file mode 100644 index 0000000..5a97f24 --- /dev/null +++ b/src/FrontOffice.BFF.Application/Common/Models/PaginationState.cs @@ -0,0 +1,10 @@ +namespace FrontOffice.BFF.Application.Common.Models; + +public class PaginationState +{ + //شماره صفحه + public int PageNumber { get; set; } + + //اندازه صفحه + public int PageSize { get; set; } +} diff --git a/src/FrontOffice.BFF.Application/ConfigureServices.cs b/src/FrontOffice.BFF.Application/ConfigureServices.cs new file mode 100644 index 0000000..8d2e789 --- /dev/null +++ b/src/FrontOffice.BFF.Application/ConfigureServices.cs @@ -0,0 +1,32 @@ +using FrontOffice.BFF.Application.Common.Behaviours; +using MapsterMapper; +using System.Reflection; + +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/FrontOffice.BFF.Application/FrontOffice.BFF.Application.csproj b/src/FrontOffice.BFF.Application/FrontOffice.BFF.Application.csproj new file mode 100644 index 0000000..8935960 --- /dev/null +++ b/src/FrontOffice.BFF.Application/FrontOffice.BFF.Application.csproj @@ -0,0 +1,18 @@ + + + + net7.0 + enable + + + + + + + + + + + + + diff --git a/src/FrontOffice.BFF.Application/GlobalUsings.cs b/src/FrontOffice.BFF.Application/GlobalUsings.cs new file mode 100644 index 0000000..0c14c39 --- /dev/null +++ b/src/FrontOffice.BFF.Application/GlobalUsings.cs @@ -0,0 +1,12 @@ +global using MediatR; +global using FluentValidation; +global using Mapster; +global using System.Threading.Tasks; +global using System.Threading; +global using System.Collections.Generic; +global using System; +global using System.Linq; +global using Google.Protobuf.WellKnownTypes; +global using FrontOffice.BFF.Application.Common.Interfaces; +global using FrontOffice.BFF.Application.Common.Models; +global using FrontOffice.BFF.Application.Common.Exceptions; diff --git a/src/FrontOffice.BFF.Application/PackageCQ/Commands/CreateNewPackage/CreateNewPackageCommand.cs b/src/FrontOffice.BFF.Application/PackageCQ/Commands/CreateNewPackage/CreateNewPackageCommand.cs new file mode 100644 index 0000000..4a291ae --- /dev/null +++ b/src/FrontOffice.BFF.Application/PackageCQ/Commands/CreateNewPackage/CreateNewPackageCommand.cs @@ -0,0 +1,13 @@ +namespace FrontOffice.BFF.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/FrontOffice.BFF.Application/PackageCQ/Commands/CreateNewPackage/CreateNewPackageCommandHandler.cs b/src/FrontOffice.BFF.Application/PackageCQ/Commands/CreateNewPackage/CreateNewPackageCommandHandler.cs new file mode 100644 index 0000000..57f39f6 --- /dev/null +++ b/src/FrontOffice.BFF.Application/PackageCQ/Commands/CreateNewPackage/CreateNewPackageCommandHandler.cs @@ -0,0 +1,16 @@ +namespace FrontOffice.BFF.Application.PackageCQ.Commands.CreateNewPackage; +public class CreateNewPackageCommandHandler : IRequestHandler +{ + private readonly IApplicationContractContext _context; + + public CreateNewPackageCommandHandler(IApplicationContractContext context) + { + _context = context; + } + + public async Task Handle(CreateNewPackageCommand request, CancellationToken cancellationToken) + { + //TODO: Implement your business logic + return new CreateNewPackageResponseDto(); + } +} diff --git a/src/FrontOffice.BFF.Application/PackageCQ/Commands/CreateNewPackage/CreateNewPackageCommandValidator.cs b/src/FrontOffice.BFF.Application/PackageCQ/Commands/CreateNewPackage/CreateNewPackageCommandValidator.cs new file mode 100644 index 0000000..eb52a00 --- /dev/null +++ b/src/FrontOffice.BFF.Application/PackageCQ/Commands/CreateNewPackage/CreateNewPackageCommandValidator.cs @@ -0,0 +1,22 @@ +namespace FrontOffice.BFF.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/FrontOffice.BFF.Application/PackageCQ/Commands/CreateNewPackage/CreateNewPackageResponseDto.cs b/src/FrontOffice.BFF.Application/PackageCQ/Commands/CreateNewPackage/CreateNewPackageResponseDto.cs new file mode 100644 index 0000000..64cb57d --- /dev/null +++ b/src/FrontOffice.BFF.Application/PackageCQ/Commands/CreateNewPackage/CreateNewPackageResponseDto.cs @@ -0,0 +1,7 @@ +namespace FrontOffice.BFF.Application.PackageCQ.Commands.CreateNewPackage; +public class CreateNewPackageResponseDto +{ + //شناسه + public long Id { get; set; } + +} \ No newline at end of file diff --git a/src/FrontOffice.BFF.Application/PackageCQ/Commands/DeletePackage/DeletePackageCommand.cs b/src/FrontOffice.BFF.Application/PackageCQ/Commands/DeletePackage/DeletePackageCommand.cs new file mode 100644 index 0000000..6ed2fcb --- /dev/null +++ b/src/FrontOffice.BFF.Application/PackageCQ/Commands/DeletePackage/DeletePackageCommand.cs @@ -0,0 +1,7 @@ +namespace FrontOffice.BFF.Application.PackageCQ.Commands.DeletePackage; +public record DeletePackageCommand : IRequest +{ + //شناسه + public long Id { get; init; } + +} \ No newline at end of file diff --git a/src/FrontOffice.BFF.Application/PackageCQ/Commands/DeletePackage/DeletePackageCommandHandler.cs b/src/FrontOffice.BFF.Application/PackageCQ/Commands/DeletePackage/DeletePackageCommandHandler.cs new file mode 100644 index 0000000..f581411 --- /dev/null +++ b/src/FrontOffice.BFF.Application/PackageCQ/Commands/DeletePackage/DeletePackageCommandHandler.cs @@ -0,0 +1,16 @@ +namespace FrontOffice.BFF.Application.PackageCQ.Commands.DeletePackage; +public class DeletePackageCommandHandler : IRequestHandler +{ + private readonly IApplicationContractContext _context; + + public DeletePackageCommandHandler(IApplicationContractContext context) + { + _context = context; + } + + public async Task Handle(DeletePackageCommand request, CancellationToken cancellationToken) + { + //TODO: Implement your business logic + return new Unit(); + } +} diff --git a/src/FrontOffice.BFF.Application/PackageCQ/Commands/DeletePackage/DeletePackageCommandValidator.cs b/src/FrontOffice.BFF.Application/PackageCQ/Commands/DeletePackage/DeletePackageCommandValidator.cs new file mode 100644 index 0000000..dc3aa95 --- /dev/null +++ b/src/FrontOffice.BFF.Application/PackageCQ/Commands/DeletePackage/DeletePackageCommandValidator.cs @@ -0,0 +1,16 @@ +namespace FrontOffice.BFF.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/FrontOffice.BFF.Application/PackageCQ/Commands/UpdatePackage/UpdatePackageCommand.cs b/src/FrontOffice.BFF.Application/PackageCQ/Commands/UpdatePackage/UpdatePackageCommand.cs new file mode 100644 index 0000000..151a4af --- /dev/null +++ b/src/FrontOffice.BFF.Application/PackageCQ/Commands/UpdatePackage/UpdatePackageCommand.cs @@ -0,0 +1,15 @@ +namespace FrontOffice.BFF.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/FrontOffice.BFF.Application/PackageCQ/Commands/UpdatePackage/UpdatePackageCommandHandler.cs b/src/FrontOffice.BFF.Application/PackageCQ/Commands/UpdatePackage/UpdatePackageCommandHandler.cs new file mode 100644 index 0000000..5c73caa --- /dev/null +++ b/src/FrontOffice.BFF.Application/PackageCQ/Commands/UpdatePackage/UpdatePackageCommandHandler.cs @@ -0,0 +1,16 @@ +namespace FrontOffice.BFF.Application.PackageCQ.Commands.UpdatePackage; +public class UpdatePackageCommandHandler : IRequestHandler +{ + private readonly IApplicationContractContext _context; + + public UpdatePackageCommandHandler(IApplicationContractContext context) + { + _context = context; + } + + public async Task Handle(UpdatePackageCommand request, CancellationToken cancellationToken) + { + //TODO: Implement your business logic + return new Unit(); + } +} diff --git a/src/FrontOffice.BFF.Application/PackageCQ/Commands/UpdatePackage/UpdatePackageCommandValidator.cs b/src/FrontOffice.BFF.Application/PackageCQ/Commands/UpdatePackage/UpdatePackageCommandValidator.cs new file mode 100644 index 0000000..7ab1ac3 --- /dev/null +++ b/src/FrontOffice.BFF.Application/PackageCQ/Commands/UpdatePackage/UpdatePackageCommandValidator.cs @@ -0,0 +1,24 @@ +namespace FrontOffice.BFF.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/FrontOffice.BFF.Application/PackageCQ/Queries/GetAllPackageByFilter/GetAllPackageByFilterQuery.cs b/src/FrontOffice.BFF.Application/PackageCQ/Queries/GetAllPackageByFilter/GetAllPackageByFilterQuery.cs new file mode 100644 index 0000000..516a861 --- /dev/null +++ b/src/FrontOffice.BFF.Application/PackageCQ/Queries/GetAllPackageByFilter/GetAllPackageByFilterQuery.cs @@ -0,0 +1,23 @@ +namespace FrontOffice.BFF.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/FrontOffice.BFF.Application/PackageCQ/Queries/GetAllPackageByFilter/GetAllPackageByFilterQueryHandler.cs b/src/FrontOffice.BFF.Application/PackageCQ/Queries/GetAllPackageByFilter/GetAllPackageByFilterQueryHandler.cs new file mode 100644 index 0000000..955ec5c --- /dev/null +++ b/src/FrontOffice.BFF.Application/PackageCQ/Queries/GetAllPackageByFilter/GetAllPackageByFilterQueryHandler.cs @@ -0,0 +1,16 @@ +namespace FrontOffice.BFF.Application.PackageCQ.Queries.GetAllPackageByFilter; +public class GetAllPackageByFilterQueryHandler : IRequestHandler +{ + private readonly IApplicationContractContext _context; + + public GetAllPackageByFilterQueryHandler(IApplicationContractContext context) + { + _context = context; + } + + public async Task Handle(GetAllPackageByFilterQuery request, CancellationToken cancellationToken) + { + //TODO: Implement your business logic + return new GetAllPackageByFilterResponseDto(); + } +} diff --git a/src/FrontOffice.BFF.Application/PackageCQ/Queries/GetAllPackageByFilter/GetAllPackageByFilterQueryValidator.cs b/src/FrontOffice.BFF.Application/PackageCQ/Queries/GetAllPackageByFilter/GetAllPackageByFilterQueryValidator.cs new file mode 100644 index 0000000..cd5030b --- /dev/null +++ b/src/FrontOffice.BFF.Application/PackageCQ/Queries/GetAllPackageByFilter/GetAllPackageByFilterQueryValidator.cs @@ -0,0 +1,14 @@ +namespace FrontOffice.BFF.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/FrontOffice.BFF.Application/PackageCQ/Queries/GetAllPackageByFilter/GetAllPackageByFilterResponseDto.cs b/src/FrontOffice.BFF.Application/PackageCQ/Queries/GetAllPackageByFilter/GetAllPackageByFilterResponseDto.cs new file mode 100644 index 0000000..24b3b0f --- /dev/null +++ b/src/FrontOffice.BFF.Application/PackageCQ/Queries/GetAllPackageByFilter/GetAllPackageByFilterResponseDto.cs @@ -0,0 +1,21 @@ +namespace FrontOffice.BFF.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/FrontOffice.BFF.Application/PackageCQ/Queries/GetPackage/GetPackageQuery.cs b/src/FrontOffice.BFF.Application/PackageCQ/Queries/GetPackage/GetPackageQuery.cs new file mode 100644 index 0000000..1a2f534 --- /dev/null +++ b/src/FrontOffice.BFF.Application/PackageCQ/Queries/GetPackage/GetPackageQuery.cs @@ -0,0 +1,7 @@ +namespace FrontOffice.BFF.Application.PackageCQ.Queries.GetPackage; +public record GetPackageQuery : IRequest +{ + //شناسه + public long Id { get; init; } + +} \ No newline at end of file diff --git a/src/FrontOffice.BFF.Application/PackageCQ/Queries/GetPackage/GetPackageQueryHandler.cs b/src/FrontOffice.BFF.Application/PackageCQ/Queries/GetPackage/GetPackageQueryHandler.cs new file mode 100644 index 0000000..7a2f6b3 --- /dev/null +++ b/src/FrontOffice.BFF.Application/PackageCQ/Queries/GetPackage/GetPackageQueryHandler.cs @@ -0,0 +1,16 @@ +namespace FrontOffice.BFF.Application.PackageCQ.Queries.GetPackage; +public class GetPackageQueryHandler : IRequestHandler +{ + private readonly IApplicationContractContext _context; + + public GetPackageQueryHandler(IApplicationContractContext context) + { + _context = context; + } + + public async Task Handle(GetPackageQuery request, CancellationToken cancellationToken) + { + //TODO: Implement your business logic + return new GetPackageResponseDto(); + } +} diff --git a/src/FrontOffice.BFF.Application/PackageCQ/Queries/GetPackage/GetPackageQueryValidator.cs b/src/FrontOffice.BFF.Application/PackageCQ/Queries/GetPackage/GetPackageQueryValidator.cs new file mode 100644 index 0000000..08aee62 --- /dev/null +++ b/src/FrontOffice.BFF.Application/PackageCQ/Queries/GetPackage/GetPackageQueryValidator.cs @@ -0,0 +1,16 @@ +namespace FrontOffice.BFF.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/FrontOffice.BFF.Application/PackageCQ/Queries/GetPackage/GetPackageResponseDto.cs b/src/FrontOffice.BFF.Application/PackageCQ/Queries/GetPackage/GetPackageResponseDto.cs new file mode 100644 index 0000000..f1bccb9 --- /dev/null +++ b/src/FrontOffice.BFF.Application/PackageCQ/Queries/GetPackage/GetPackageResponseDto.cs @@ -0,0 +1,15 @@ +namespace FrontOffice.BFF.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/FrontOffice.BFF.Application/RoleCQ/Commands/CreateNewRole/CreateNewRoleCommand.cs b/src/FrontOffice.BFF.Application/RoleCQ/Commands/CreateNewRole/CreateNewRoleCommand.cs new file mode 100644 index 0000000..4487dbe --- /dev/null +++ b/src/FrontOffice.BFF.Application/RoleCQ/Commands/CreateNewRole/CreateNewRoleCommand.cs @@ -0,0 +1,9 @@ +namespace FrontOffice.BFF.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/FrontOffice.BFF.Application/RoleCQ/Commands/CreateNewRole/CreateNewRoleCommandHandler.cs b/src/FrontOffice.BFF.Application/RoleCQ/Commands/CreateNewRole/CreateNewRoleCommandHandler.cs new file mode 100644 index 0000000..7e1bd4f --- /dev/null +++ b/src/FrontOffice.BFF.Application/RoleCQ/Commands/CreateNewRole/CreateNewRoleCommandHandler.cs @@ -0,0 +1,16 @@ +namespace FrontOffice.BFF.Application.RoleCQ.Commands.CreateNewRole; +public class CreateNewRoleCommandHandler : IRequestHandler +{ + private readonly IApplicationContractContext _context; + + public CreateNewRoleCommandHandler(IApplicationContractContext context) + { + _context = context; + } + + public async Task Handle(CreateNewRoleCommand request, CancellationToken cancellationToken) + { + //TODO: Implement your business logic + return new CreateNewRoleResponseDto(); + } +} diff --git a/src/FrontOffice.BFF.Application/RoleCQ/Commands/CreateNewRole/CreateNewRoleCommandValidator.cs b/src/FrontOffice.BFF.Application/RoleCQ/Commands/CreateNewRole/CreateNewRoleCommandValidator.cs new file mode 100644 index 0000000..6efb675 --- /dev/null +++ b/src/FrontOffice.BFF.Application/RoleCQ/Commands/CreateNewRole/CreateNewRoleCommandValidator.cs @@ -0,0 +1,18 @@ +namespace FrontOffice.BFF.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/FrontOffice.BFF.Application/RoleCQ/Commands/CreateNewRole/CreateNewRoleResponseDto.cs b/src/FrontOffice.BFF.Application/RoleCQ/Commands/CreateNewRole/CreateNewRoleResponseDto.cs new file mode 100644 index 0000000..64e4bb3 --- /dev/null +++ b/src/FrontOffice.BFF.Application/RoleCQ/Commands/CreateNewRole/CreateNewRoleResponseDto.cs @@ -0,0 +1,7 @@ +namespace FrontOffice.BFF.Application.RoleCQ.Commands.CreateNewRole; +public class CreateNewRoleResponseDto +{ + //شناسه + public long Id { get; set; } + +} \ No newline at end of file diff --git a/src/FrontOffice.BFF.Application/RoleCQ/Commands/DeleteRole/DeleteRoleCommand.cs b/src/FrontOffice.BFF.Application/RoleCQ/Commands/DeleteRole/DeleteRoleCommand.cs new file mode 100644 index 0000000..6eda120 --- /dev/null +++ b/src/FrontOffice.BFF.Application/RoleCQ/Commands/DeleteRole/DeleteRoleCommand.cs @@ -0,0 +1,7 @@ +namespace FrontOffice.BFF.Application.RoleCQ.Commands.DeleteRole; +public record DeleteRoleCommand : IRequest +{ + //شناسه + public long Id { get; init; } + +} \ No newline at end of file diff --git a/src/FrontOffice.BFF.Application/RoleCQ/Commands/DeleteRole/DeleteRoleCommandHandler.cs b/src/FrontOffice.BFF.Application/RoleCQ/Commands/DeleteRole/DeleteRoleCommandHandler.cs new file mode 100644 index 0000000..d0bcbdf --- /dev/null +++ b/src/FrontOffice.BFF.Application/RoleCQ/Commands/DeleteRole/DeleteRoleCommandHandler.cs @@ -0,0 +1,16 @@ +namespace FrontOffice.BFF.Application.RoleCQ.Commands.DeleteRole; +public class DeleteRoleCommandHandler : IRequestHandler +{ + private readonly IApplicationContractContext _context; + + public DeleteRoleCommandHandler(IApplicationContractContext context) + { + _context = context; + } + + public async Task Handle(DeleteRoleCommand request, CancellationToken cancellationToken) + { + //TODO: Implement your business logic + return new Unit(); + } +} diff --git a/src/FrontOffice.BFF.Application/RoleCQ/Commands/DeleteRole/DeleteRoleCommandValidator.cs b/src/FrontOffice.BFF.Application/RoleCQ/Commands/DeleteRole/DeleteRoleCommandValidator.cs new file mode 100644 index 0000000..6db61f2 --- /dev/null +++ b/src/FrontOffice.BFF.Application/RoleCQ/Commands/DeleteRole/DeleteRoleCommandValidator.cs @@ -0,0 +1,16 @@ +namespace FrontOffice.BFF.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/FrontOffice.BFF.Application/RoleCQ/Commands/UpdateRole/UpdateRoleCommand.cs b/src/FrontOffice.BFF.Application/RoleCQ/Commands/UpdateRole/UpdateRoleCommand.cs new file mode 100644 index 0000000..ca8a8ac --- /dev/null +++ b/src/FrontOffice.BFF.Application/RoleCQ/Commands/UpdateRole/UpdateRoleCommand.cs @@ -0,0 +1,11 @@ +namespace FrontOffice.BFF.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/FrontOffice.BFF.Application/RoleCQ/Commands/UpdateRole/UpdateRoleCommandHandler.cs b/src/FrontOffice.BFF.Application/RoleCQ/Commands/UpdateRole/UpdateRoleCommandHandler.cs new file mode 100644 index 0000000..631b37e --- /dev/null +++ b/src/FrontOffice.BFF.Application/RoleCQ/Commands/UpdateRole/UpdateRoleCommandHandler.cs @@ -0,0 +1,16 @@ +namespace FrontOffice.BFF.Application.RoleCQ.Commands.UpdateRole; +public class UpdateRoleCommandHandler : IRequestHandler +{ + private readonly IApplicationContractContext _context; + + public UpdateRoleCommandHandler(IApplicationContractContext context) + { + _context = context; + } + + public async Task Handle(UpdateRoleCommand request, CancellationToken cancellationToken) + { + //TODO: Implement your business logic + return new Unit(); + } +} diff --git a/src/FrontOffice.BFF.Application/RoleCQ/Commands/UpdateRole/UpdateRoleCommandValidator.cs b/src/FrontOffice.BFF.Application/RoleCQ/Commands/UpdateRole/UpdateRoleCommandValidator.cs new file mode 100644 index 0000000..2bffcaf --- /dev/null +++ b/src/FrontOffice.BFF.Application/RoleCQ/Commands/UpdateRole/UpdateRoleCommandValidator.cs @@ -0,0 +1,20 @@ +namespace FrontOffice.BFF.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/FrontOffice.BFF.Application/RoleCQ/Queries/GetAllRoleByFilter/GetAllRoleByFilterQuery.cs b/src/FrontOffice.BFF.Application/RoleCQ/Queries/GetAllRoleByFilter/GetAllRoleByFilterQuery.cs new file mode 100644 index 0000000..7081e8a --- /dev/null +++ b/src/FrontOffice.BFF.Application/RoleCQ/Queries/GetAllRoleByFilter/GetAllRoleByFilterQuery.cs @@ -0,0 +1,19 @@ +namespace FrontOffice.BFF.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/FrontOffice.BFF.Application/RoleCQ/Queries/GetAllRoleByFilter/GetAllRoleByFilterQueryHandler.cs b/src/FrontOffice.BFF.Application/RoleCQ/Queries/GetAllRoleByFilter/GetAllRoleByFilterQueryHandler.cs new file mode 100644 index 0000000..aa83ea7 --- /dev/null +++ b/src/FrontOffice.BFF.Application/RoleCQ/Queries/GetAllRoleByFilter/GetAllRoleByFilterQueryHandler.cs @@ -0,0 +1,16 @@ +namespace FrontOffice.BFF.Application.RoleCQ.Queries.GetAllRoleByFilter; +public class GetAllRoleByFilterQueryHandler : IRequestHandler +{ + private readonly IApplicationContractContext _context; + + public GetAllRoleByFilterQueryHandler(IApplicationContractContext context) + { + _context = context; + } + + public async Task Handle(GetAllRoleByFilterQuery request, CancellationToken cancellationToken) + { + //TODO: Implement your business logic + return new GetAllRoleByFilterResponseDto(); + } +} diff --git a/src/FrontOffice.BFF.Application/RoleCQ/Queries/GetAllRoleByFilter/GetAllRoleByFilterQueryValidator.cs b/src/FrontOffice.BFF.Application/RoleCQ/Queries/GetAllRoleByFilter/GetAllRoleByFilterQueryValidator.cs new file mode 100644 index 0000000..e960deb --- /dev/null +++ b/src/FrontOffice.BFF.Application/RoleCQ/Queries/GetAllRoleByFilter/GetAllRoleByFilterQueryValidator.cs @@ -0,0 +1,14 @@ +namespace FrontOffice.BFF.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/FrontOffice.BFF.Application/RoleCQ/Queries/GetAllRoleByFilter/GetAllRoleByFilterResponseDto.cs b/src/FrontOffice.BFF.Application/RoleCQ/Queries/GetAllRoleByFilter/GetAllRoleByFilterResponseDto.cs new file mode 100644 index 0000000..25526bf --- /dev/null +++ b/src/FrontOffice.BFF.Application/RoleCQ/Queries/GetAllRoleByFilter/GetAllRoleByFilterResponseDto.cs @@ -0,0 +1,17 @@ +namespace FrontOffice.BFF.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/FrontOffice.BFF.Application/RoleCQ/Queries/GetRole/GetRoleQuery.cs b/src/FrontOffice.BFF.Application/RoleCQ/Queries/GetRole/GetRoleQuery.cs new file mode 100644 index 0000000..a4959a7 --- /dev/null +++ b/src/FrontOffice.BFF.Application/RoleCQ/Queries/GetRole/GetRoleQuery.cs @@ -0,0 +1,7 @@ +namespace FrontOffice.BFF.Application.RoleCQ.Queries.GetRole; +public record GetRoleQuery : IRequest +{ + //شناسه + public long Id { get; init; } + +} \ No newline at end of file diff --git a/src/FrontOffice.BFF.Application/RoleCQ/Queries/GetRole/GetRoleQueryHandler.cs b/src/FrontOffice.BFF.Application/RoleCQ/Queries/GetRole/GetRoleQueryHandler.cs new file mode 100644 index 0000000..d3aca8c --- /dev/null +++ b/src/FrontOffice.BFF.Application/RoleCQ/Queries/GetRole/GetRoleQueryHandler.cs @@ -0,0 +1,16 @@ +namespace FrontOffice.BFF.Application.RoleCQ.Queries.GetRole; +public class GetRoleQueryHandler : IRequestHandler +{ + private readonly IApplicationContractContext _context; + + public GetRoleQueryHandler(IApplicationContractContext context) + { + _context = context; + } + + public async Task Handle(GetRoleQuery request, CancellationToken cancellationToken) + { + //TODO: Implement your business logic + return new GetRoleResponseDto(); + } +} diff --git a/src/FrontOffice.BFF.Application/RoleCQ/Queries/GetRole/GetRoleQueryValidator.cs b/src/FrontOffice.BFF.Application/RoleCQ/Queries/GetRole/GetRoleQueryValidator.cs new file mode 100644 index 0000000..e472475 --- /dev/null +++ b/src/FrontOffice.BFF.Application/RoleCQ/Queries/GetRole/GetRoleQueryValidator.cs @@ -0,0 +1,16 @@ +namespace FrontOffice.BFF.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/FrontOffice.BFF.Application/RoleCQ/Queries/GetRole/GetRoleResponseDto.cs b/src/FrontOffice.BFF.Application/RoleCQ/Queries/GetRole/GetRoleResponseDto.cs new file mode 100644 index 0000000..1d949cb --- /dev/null +++ b/src/FrontOffice.BFF.Application/RoleCQ/Queries/GetRole/GetRoleResponseDto.cs @@ -0,0 +1,11 @@ +namespace FrontOffice.BFF.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/FrontOffice.BFF.Application/UserAddressCQ/Commands/CreateNewUserAddress/CreateNewUserAddressCommand.cs b/src/FrontOffice.BFF.Application/UserAddressCQ/Commands/CreateNewUserAddress/CreateNewUserAddressCommand.cs new file mode 100644 index 0000000..7706c93 --- /dev/null +++ b/src/FrontOffice.BFF.Application/UserAddressCQ/Commands/CreateNewUserAddress/CreateNewUserAddressCommand.cs @@ -0,0 +1,17 @@ +namespace FrontOffice.BFF.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/FrontOffice.BFF.Application/UserAddressCQ/Commands/CreateNewUserAddress/CreateNewUserAddressCommandHandler.cs b/src/FrontOffice.BFF.Application/UserAddressCQ/Commands/CreateNewUserAddress/CreateNewUserAddressCommandHandler.cs new file mode 100644 index 0000000..b6e0b19 --- /dev/null +++ b/src/FrontOffice.BFF.Application/UserAddressCQ/Commands/CreateNewUserAddress/CreateNewUserAddressCommandHandler.cs @@ -0,0 +1,16 @@ +namespace FrontOffice.BFF.Application.UserAddressCQ.Commands.CreateNewUserAddress; +public class CreateNewUserAddressCommandHandler : IRequestHandler +{ + private readonly IApplicationContractContext _context; + + public CreateNewUserAddressCommandHandler(IApplicationContractContext context) + { + _context = context; + } + + public async Task Handle(CreateNewUserAddressCommand request, CancellationToken cancellationToken) + { + //TODO: Implement your business logic + return new CreateNewUserAddressResponseDto(); + } +} diff --git a/src/FrontOffice.BFF.Application/UserAddressCQ/Commands/CreateNewUserAddress/CreateNewUserAddressCommandValidator.cs b/src/FrontOffice.BFF.Application/UserAddressCQ/Commands/CreateNewUserAddress/CreateNewUserAddressCommandValidator.cs new file mode 100644 index 0000000..381841a --- /dev/null +++ b/src/FrontOffice.BFF.Application/UserAddressCQ/Commands/CreateNewUserAddress/CreateNewUserAddressCommandValidator.cs @@ -0,0 +1,26 @@ +namespace FrontOffice.BFF.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/FrontOffice.BFF.Application/UserAddressCQ/Commands/CreateNewUserAddress/CreateNewUserAddressResponseDto.cs b/src/FrontOffice.BFF.Application/UserAddressCQ/Commands/CreateNewUserAddress/CreateNewUserAddressResponseDto.cs new file mode 100644 index 0000000..ba910b0 --- /dev/null +++ b/src/FrontOffice.BFF.Application/UserAddressCQ/Commands/CreateNewUserAddress/CreateNewUserAddressResponseDto.cs @@ -0,0 +1,7 @@ +namespace FrontOffice.BFF.Application.UserAddressCQ.Commands.CreateNewUserAddress; +public class CreateNewUserAddressResponseDto +{ + //شناسه + public long Id { get; set; } + +} \ No newline at end of file diff --git a/src/FrontOffice.BFF.Application/UserAddressCQ/Commands/DeleteUserAddress/DeleteUserAddressCommand.cs b/src/FrontOffice.BFF.Application/UserAddressCQ/Commands/DeleteUserAddress/DeleteUserAddressCommand.cs new file mode 100644 index 0000000..2e37342 --- /dev/null +++ b/src/FrontOffice.BFF.Application/UserAddressCQ/Commands/DeleteUserAddress/DeleteUserAddressCommand.cs @@ -0,0 +1,7 @@ +namespace FrontOffice.BFF.Application.UserAddressCQ.Commands.DeleteUserAddress; +public record DeleteUserAddressCommand : IRequest +{ + //شناسه + public long Id { get; init; } + +} \ No newline at end of file diff --git a/src/FrontOffice.BFF.Application/UserAddressCQ/Commands/DeleteUserAddress/DeleteUserAddressCommandHandler.cs b/src/FrontOffice.BFF.Application/UserAddressCQ/Commands/DeleteUserAddress/DeleteUserAddressCommandHandler.cs new file mode 100644 index 0000000..4a25bb0 --- /dev/null +++ b/src/FrontOffice.BFF.Application/UserAddressCQ/Commands/DeleteUserAddress/DeleteUserAddressCommandHandler.cs @@ -0,0 +1,16 @@ +namespace FrontOffice.BFF.Application.UserAddressCQ.Commands.DeleteUserAddress; +public class DeleteUserAddressCommandHandler : IRequestHandler +{ + private readonly IApplicationContractContext _context; + + public DeleteUserAddressCommandHandler(IApplicationContractContext context) + { + _context = context; + } + + public async Task Handle(DeleteUserAddressCommand request, CancellationToken cancellationToken) + { + //TODO: Implement your business logic + return new Unit(); + } +} diff --git a/src/FrontOffice.BFF.Application/UserAddressCQ/Commands/DeleteUserAddress/DeleteUserAddressCommandValidator.cs b/src/FrontOffice.BFF.Application/UserAddressCQ/Commands/DeleteUserAddress/DeleteUserAddressCommandValidator.cs new file mode 100644 index 0000000..9ef79a5 --- /dev/null +++ b/src/FrontOffice.BFF.Application/UserAddressCQ/Commands/DeleteUserAddress/DeleteUserAddressCommandValidator.cs @@ -0,0 +1,16 @@ +namespace FrontOffice.BFF.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/FrontOffice.BFF.Application/UserAddressCQ/Commands/UpdateUserAddress/UpdateUserAddressCommand.cs b/src/FrontOffice.BFF.Application/UserAddressCQ/Commands/UpdateUserAddress/UpdateUserAddressCommand.cs new file mode 100644 index 0000000..2b994d9 --- /dev/null +++ b/src/FrontOffice.BFF.Application/UserAddressCQ/Commands/UpdateUserAddress/UpdateUserAddressCommand.cs @@ -0,0 +1,19 @@ +namespace FrontOffice.BFF.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/FrontOffice.BFF.Application/UserAddressCQ/Commands/UpdateUserAddress/UpdateUserAddressCommandHandler.cs b/src/FrontOffice.BFF.Application/UserAddressCQ/Commands/UpdateUserAddress/UpdateUserAddressCommandHandler.cs new file mode 100644 index 0000000..7610ac6 --- /dev/null +++ b/src/FrontOffice.BFF.Application/UserAddressCQ/Commands/UpdateUserAddress/UpdateUserAddressCommandHandler.cs @@ -0,0 +1,16 @@ +namespace FrontOffice.BFF.Application.UserAddressCQ.Commands.UpdateUserAddress; +public class UpdateUserAddressCommandHandler : IRequestHandler +{ + private readonly IApplicationContractContext _context; + + public UpdateUserAddressCommandHandler(IApplicationContractContext context) + { + _context = context; + } + + public async Task Handle(UpdateUserAddressCommand request, CancellationToken cancellationToken) + { + //TODO: Implement your business logic + return new Unit(); + } +} diff --git a/src/FrontOffice.BFF.Application/UserAddressCQ/Commands/UpdateUserAddress/UpdateUserAddressCommandValidator.cs b/src/FrontOffice.BFF.Application/UserAddressCQ/Commands/UpdateUserAddress/UpdateUserAddressCommandValidator.cs new file mode 100644 index 0000000..a85b5b1 --- /dev/null +++ b/src/FrontOffice.BFF.Application/UserAddressCQ/Commands/UpdateUserAddress/UpdateUserAddressCommandValidator.cs @@ -0,0 +1,28 @@ +namespace FrontOffice.BFF.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/FrontOffice.BFF.Application/UserAddressCQ/Queries/GetAllUserAddressByFilter/GetAllUserAddressByFilterQuery.cs b/src/FrontOffice.BFF.Application/UserAddressCQ/Queries/GetAllUserAddressByFilter/GetAllUserAddressByFilterQuery.cs new file mode 100644 index 0000000..78d680a --- /dev/null +++ b/src/FrontOffice.BFF.Application/UserAddressCQ/Queries/GetAllUserAddressByFilter/GetAllUserAddressByFilterQuery.cs @@ -0,0 +1,27 @@ +namespace FrontOffice.BFF.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/FrontOffice.BFF.Application/UserAddressCQ/Queries/GetAllUserAddressByFilter/GetAllUserAddressByFilterQueryHandler.cs b/src/FrontOffice.BFF.Application/UserAddressCQ/Queries/GetAllUserAddressByFilter/GetAllUserAddressByFilterQueryHandler.cs new file mode 100644 index 0000000..db953fe --- /dev/null +++ b/src/FrontOffice.BFF.Application/UserAddressCQ/Queries/GetAllUserAddressByFilter/GetAllUserAddressByFilterQueryHandler.cs @@ -0,0 +1,16 @@ +namespace FrontOffice.BFF.Application.UserAddressCQ.Queries.GetAllUserAddressByFilter; +public class GetAllUserAddressByFilterQueryHandler : IRequestHandler +{ + private readonly IApplicationContractContext _context; + + public GetAllUserAddressByFilterQueryHandler(IApplicationContractContext context) + { + _context = context; + } + + public async Task Handle(GetAllUserAddressByFilterQuery request, CancellationToken cancellationToken) + { + //TODO: Implement your business logic + return new GetAllUserAddressByFilterResponseDto(); + } +} diff --git a/src/FrontOffice.BFF.Application/UserAddressCQ/Queries/GetAllUserAddressByFilter/GetAllUserAddressByFilterQueryValidator.cs b/src/FrontOffice.BFF.Application/UserAddressCQ/Queries/GetAllUserAddressByFilter/GetAllUserAddressByFilterQueryValidator.cs new file mode 100644 index 0000000..ad9521b --- /dev/null +++ b/src/FrontOffice.BFF.Application/UserAddressCQ/Queries/GetAllUserAddressByFilter/GetAllUserAddressByFilterQueryValidator.cs @@ -0,0 +1,14 @@ +namespace FrontOffice.BFF.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/FrontOffice.BFF.Application/UserAddressCQ/Queries/GetAllUserAddressByFilter/GetAllUserAddressByFilterResponseDto.cs b/src/FrontOffice.BFF.Application/UserAddressCQ/Queries/GetAllUserAddressByFilter/GetAllUserAddressByFilterResponseDto.cs new file mode 100644 index 0000000..d502f0d --- /dev/null +++ b/src/FrontOffice.BFF.Application/UserAddressCQ/Queries/GetAllUserAddressByFilter/GetAllUserAddressByFilterResponseDto.cs @@ -0,0 +1,25 @@ +namespace FrontOffice.BFF.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/FrontOffice.BFF.Application/UserAddressCQ/Queries/GetUserAddress/GetUserAddressQuery.cs b/src/FrontOffice.BFF.Application/UserAddressCQ/Queries/GetUserAddress/GetUserAddressQuery.cs new file mode 100644 index 0000000..4890bb1 --- /dev/null +++ b/src/FrontOffice.BFF.Application/UserAddressCQ/Queries/GetUserAddress/GetUserAddressQuery.cs @@ -0,0 +1,7 @@ +namespace FrontOffice.BFF.Application.UserAddressCQ.Queries.GetUserAddress; +public record GetUserAddressQuery : IRequest +{ + //شناسه + public long Id { get; init; } + +} \ No newline at end of file diff --git a/src/FrontOffice.BFF.Application/UserAddressCQ/Queries/GetUserAddress/GetUserAddressQueryHandler.cs b/src/FrontOffice.BFF.Application/UserAddressCQ/Queries/GetUserAddress/GetUserAddressQueryHandler.cs new file mode 100644 index 0000000..9b602a1 --- /dev/null +++ b/src/FrontOffice.BFF.Application/UserAddressCQ/Queries/GetUserAddress/GetUserAddressQueryHandler.cs @@ -0,0 +1,16 @@ +namespace FrontOffice.BFF.Application.UserAddressCQ.Queries.GetUserAddress; +public class GetUserAddressQueryHandler : IRequestHandler +{ + private readonly IApplicationContractContext _context; + + public GetUserAddressQueryHandler(IApplicationContractContext context) + { + _context = context; + } + + public async Task Handle(GetUserAddressQuery request, CancellationToken cancellationToken) + { + //TODO: Implement your business logic + return new GetUserAddressResponseDto(); + } +} diff --git a/src/FrontOffice.BFF.Application/UserAddressCQ/Queries/GetUserAddress/GetUserAddressQueryValidator.cs b/src/FrontOffice.BFF.Application/UserAddressCQ/Queries/GetUserAddress/GetUserAddressQueryValidator.cs new file mode 100644 index 0000000..26fd6c9 --- /dev/null +++ b/src/FrontOffice.BFF.Application/UserAddressCQ/Queries/GetUserAddress/GetUserAddressQueryValidator.cs @@ -0,0 +1,16 @@ +namespace FrontOffice.BFF.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/FrontOffice.BFF.Application/UserAddressCQ/Queries/GetUserAddress/GetUserAddressResponseDto.cs b/src/FrontOffice.BFF.Application/UserAddressCQ/Queries/GetUserAddress/GetUserAddressResponseDto.cs new file mode 100644 index 0000000..04faafe --- /dev/null +++ b/src/FrontOffice.BFF.Application/UserAddressCQ/Queries/GetUserAddress/GetUserAddressResponseDto.cs @@ -0,0 +1,19 @@ +namespace FrontOffice.BFF.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/FrontOffice.BFF.Application/UserCQ/Commands/CreateNewUser/CreateNewUserCommand.cs b/src/FrontOffice.BFF.Application/UserCQ/Commands/CreateNewUser/CreateNewUserCommand.cs new file mode 100644 index 0000000..ac2d13b --- /dev/null +++ b/src/FrontOffice.BFF.Application/UserCQ/Commands/CreateNewUser/CreateNewUserCommand.cs @@ -0,0 +1,17 @@ +namespace FrontOffice.BFF.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/FrontOffice.BFF.Application/UserCQ/Commands/CreateNewUser/CreateNewUserCommandHandler.cs b/src/FrontOffice.BFF.Application/UserCQ/Commands/CreateNewUser/CreateNewUserCommandHandler.cs new file mode 100644 index 0000000..fc81c98 --- /dev/null +++ b/src/FrontOffice.BFF.Application/UserCQ/Commands/CreateNewUser/CreateNewUserCommandHandler.cs @@ -0,0 +1,16 @@ +namespace FrontOffice.BFF.Application.UserCQ.Commands.CreateNewUser; +public class CreateNewUserCommandHandler : IRequestHandler +{ + private readonly IApplicationContractContext _context; + + public CreateNewUserCommandHandler(IApplicationContractContext context) + { + _context = context; + } + + public async Task Handle(CreateNewUserCommand request, CancellationToken cancellationToken) + { + //TODO: Implement your business logic + return new CreateNewUserResponseDto(); + } +} diff --git a/src/FrontOffice.BFF.Application/UserCQ/Commands/CreateNewUser/CreateNewUserCommandValidator.cs b/src/FrontOffice.BFF.Application/UserCQ/Commands/CreateNewUser/CreateNewUserCommandValidator.cs new file mode 100644 index 0000000..f2ab0c8 --- /dev/null +++ b/src/FrontOffice.BFF.Application/UserCQ/Commands/CreateNewUser/CreateNewUserCommandValidator.cs @@ -0,0 +1,16 @@ +namespace FrontOffice.BFF.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/FrontOffice.BFF.Application/UserCQ/Commands/CreateNewUser/CreateNewUserResponseDto.cs b/src/FrontOffice.BFF.Application/UserCQ/Commands/CreateNewUser/CreateNewUserResponseDto.cs new file mode 100644 index 0000000..8a91aa1 --- /dev/null +++ b/src/FrontOffice.BFF.Application/UserCQ/Commands/CreateNewUser/CreateNewUserResponseDto.cs @@ -0,0 +1,7 @@ +namespace FrontOffice.BFF.Application.UserCQ.Commands.CreateNewUser; +public class CreateNewUserResponseDto +{ + //شناسه + public long Id { get; set; } + +} \ No newline at end of file diff --git a/src/FrontOffice.BFF.Application/UserCQ/Commands/DeleteUser/DeleteUserCommand.cs b/src/FrontOffice.BFF.Application/UserCQ/Commands/DeleteUser/DeleteUserCommand.cs new file mode 100644 index 0000000..51dfc81 --- /dev/null +++ b/src/FrontOffice.BFF.Application/UserCQ/Commands/DeleteUser/DeleteUserCommand.cs @@ -0,0 +1,7 @@ +namespace FrontOffice.BFF.Application.UserCQ.Commands.DeleteUser; +public record DeleteUserCommand : IRequest +{ + //شناسه + public long Id { get; init; } + +} \ No newline at end of file diff --git a/src/FrontOffice.BFF.Application/UserCQ/Commands/DeleteUser/DeleteUserCommandHandler.cs b/src/FrontOffice.BFF.Application/UserCQ/Commands/DeleteUser/DeleteUserCommandHandler.cs new file mode 100644 index 0000000..5b9b2ad --- /dev/null +++ b/src/FrontOffice.BFF.Application/UserCQ/Commands/DeleteUser/DeleteUserCommandHandler.cs @@ -0,0 +1,16 @@ +namespace FrontOffice.BFF.Application.UserCQ.Commands.DeleteUser; +public class DeleteUserCommandHandler : IRequestHandler +{ + private readonly IApplicationContractContext _context; + + public DeleteUserCommandHandler(IApplicationContractContext context) + { + _context = context; + } + + public async Task Handle(DeleteUserCommand request, CancellationToken cancellationToken) + { + //TODO: Implement your business logic + return new Unit(); + } +} diff --git a/src/FrontOffice.BFF.Application/UserCQ/Commands/DeleteUser/DeleteUserCommandValidator.cs b/src/FrontOffice.BFF.Application/UserCQ/Commands/DeleteUser/DeleteUserCommandValidator.cs new file mode 100644 index 0000000..2dfc351 --- /dev/null +++ b/src/FrontOffice.BFF.Application/UserCQ/Commands/DeleteUser/DeleteUserCommandValidator.cs @@ -0,0 +1,16 @@ +namespace FrontOffice.BFF.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/FrontOffice.BFF.Application/UserCQ/Commands/UpdateUser/UpdateUserCommand.cs b/src/FrontOffice.BFF.Application/UserCQ/Commands/UpdateUser/UpdateUserCommand.cs new file mode 100644 index 0000000..bcd67c5 --- /dev/null +++ b/src/FrontOffice.BFF.Application/UserCQ/Commands/UpdateUser/UpdateUserCommand.cs @@ -0,0 +1,19 @@ +namespace FrontOffice.BFF.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/FrontOffice.BFF.Application/UserCQ/Commands/UpdateUser/UpdateUserCommandHandler.cs b/src/FrontOffice.BFF.Application/UserCQ/Commands/UpdateUser/UpdateUserCommandHandler.cs new file mode 100644 index 0000000..1618dc2 --- /dev/null +++ b/src/FrontOffice.BFF.Application/UserCQ/Commands/UpdateUser/UpdateUserCommandHandler.cs @@ -0,0 +1,16 @@ +namespace FrontOffice.BFF.Application.UserCQ.Commands.UpdateUser; +public class UpdateUserCommandHandler : IRequestHandler +{ + private readonly IApplicationContractContext _context; + + public UpdateUserCommandHandler(IApplicationContractContext context) + { + _context = context; + } + + public async Task Handle(UpdateUserCommand request, CancellationToken cancellationToken) + { + //TODO: Implement your business logic + return new Unit(); + } +} diff --git a/src/FrontOffice.BFF.Application/UserCQ/Commands/UpdateUser/UpdateUserCommandValidator.cs b/src/FrontOffice.BFF.Application/UserCQ/Commands/UpdateUser/UpdateUserCommandValidator.cs new file mode 100644 index 0000000..e368b87 --- /dev/null +++ b/src/FrontOffice.BFF.Application/UserCQ/Commands/UpdateUser/UpdateUserCommandValidator.cs @@ -0,0 +1,18 @@ +namespace FrontOffice.BFF.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/FrontOffice.BFF.Application/UserCQ/Queries/GetAllUserByFilter/GetAllUserByFilterQuery.cs b/src/FrontOffice.BFF.Application/UserCQ/Queries/GetAllUserByFilter/GetAllUserByFilterQuery.cs new file mode 100644 index 0000000..90ef227 --- /dev/null +++ b/src/FrontOffice.BFF.Application/UserCQ/Queries/GetAllUserByFilter/GetAllUserByFilterQuery.cs @@ -0,0 +1,27 @@ +namespace FrontOffice.BFF.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/FrontOffice.BFF.Application/UserCQ/Queries/GetAllUserByFilter/GetAllUserByFilterQueryHandler.cs b/src/FrontOffice.BFF.Application/UserCQ/Queries/GetAllUserByFilter/GetAllUserByFilterQueryHandler.cs new file mode 100644 index 0000000..22ca629 --- /dev/null +++ b/src/FrontOffice.BFF.Application/UserCQ/Queries/GetAllUserByFilter/GetAllUserByFilterQueryHandler.cs @@ -0,0 +1,16 @@ +namespace FrontOffice.BFF.Application.UserCQ.Queries.GetAllUserByFilter; +public class GetAllUserByFilterQueryHandler : IRequestHandler +{ + private readonly IApplicationContractContext _context; + + public GetAllUserByFilterQueryHandler(IApplicationContractContext context) + { + _context = context; + } + + public async Task Handle(GetAllUserByFilterQuery request, CancellationToken cancellationToken) + { + //TODO: Implement your business logic + return new GetAllUserByFilterResponseDto(); + } +} diff --git a/src/FrontOffice.BFF.Application/UserCQ/Queries/GetAllUserByFilter/GetAllUserByFilterQueryValidator.cs b/src/FrontOffice.BFF.Application/UserCQ/Queries/GetAllUserByFilter/GetAllUserByFilterQueryValidator.cs new file mode 100644 index 0000000..ab250cd --- /dev/null +++ b/src/FrontOffice.BFF.Application/UserCQ/Queries/GetAllUserByFilter/GetAllUserByFilterQueryValidator.cs @@ -0,0 +1,14 @@ +namespace FrontOffice.BFF.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/FrontOffice.BFF.Application/UserCQ/Queries/GetAllUserByFilter/GetAllUserByFilterResponseDto.cs b/src/FrontOffice.BFF.Application/UserCQ/Queries/GetAllUserByFilter/GetAllUserByFilterResponseDto.cs new file mode 100644 index 0000000..eed90b0 --- /dev/null +++ b/src/FrontOffice.BFF.Application/UserCQ/Queries/GetAllUserByFilter/GetAllUserByFilterResponseDto.cs @@ -0,0 +1,25 @@ +namespace FrontOffice.BFF.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/FrontOffice.BFF.Application/UserCQ/Queries/GetUser/GetUserQuery.cs b/src/FrontOffice.BFF.Application/UserCQ/Queries/GetUser/GetUserQuery.cs new file mode 100644 index 0000000..566617e --- /dev/null +++ b/src/FrontOffice.BFF.Application/UserCQ/Queries/GetUser/GetUserQuery.cs @@ -0,0 +1,7 @@ +namespace FrontOffice.BFF.Application.UserCQ.Queries.GetUser; +public record GetUserQuery : IRequest +{ + //شناسه + public long Id { get; init; } + +} \ No newline at end of file diff --git a/src/FrontOffice.BFF.Application/UserCQ/Queries/GetUser/GetUserQueryHandler.cs b/src/FrontOffice.BFF.Application/UserCQ/Queries/GetUser/GetUserQueryHandler.cs new file mode 100644 index 0000000..feb8a40 --- /dev/null +++ b/src/FrontOffice.BFF.Application/UserCQ/Queries/GetUser/GetUserQueryHandler.cs @@ -0,0 +1,16 @@ +namespace FrontOffice.BFF.Application.UserCQ.Queries.GetUser; +public class GetUserQueryHandler : IRequestHandler +{ + private readonly IApplicationContractContext _context; + + public GetUserQueryHandler(IApplicationContractContext context) + { + _context = context; + } + + public async Task Handle(GetUserQuery request, CancellationToken cancellationToken) + { + //TODO: Implement your business logic + return new GetUserResponseDto(); + } +} diff --git a/src/FrontOffice.BFF.Application/UserCQ/Queries/GetUser/GetUserQueryValidator.cs b/src/FrontOffice.BFF.Application/UserCQ/Queries/GetUser/GetUserQueryValidator.cs new file mode 100644 index 0000000..bd05504 --- /dev/null +++ b/src/FrontOffice.BFF.Application/UserCQ/Queries/GetUser/GetUserQueryValidator.cs @@ -0,0 +1,16 @@ +namespace FrontOffice.BFF.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/FrontOffice.BFF.Application/UserCQ/Queries/GetUser/GetUserResponseDto.cs b/src/FrontOffice.BFF.Application/UserCQ/Queries/GetUser/GetUserResponseDto.cs new file mode 100644 index 0000000..db70bb6 --- /dev/null +++ b/src/FrontOffice.BFF.Application/UserCQ/Queries/GetUser/GetUserResponseDto.cs @@ -0,0 +1,19 @@ +namespace FrontOffice.BFF.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/FrontOffice.BFF.Application/UserOrderCQ/Commands/CreateNewUserOrder/CreateNewUserOrderCommand.cs b/src/FrontOffice.BFF.Application/UserOrderCQ/Commands/CreateNewUserOrder/CreateNewUserOrderCommand.cs new file mode 100644 index 0000000..85f887a --- /dev/null +++ b/src/FrontOffice.BFF.Application/UserOrderCQ/Commands/CreateNewUserOrder/CreateNewUserOrderCommand.cs @@ -0,0 +1,17 @@ +namespace FrontOffice.BFF.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/FrontOffice.BFF.Application/UserOrderCQ/Commands/CreateNewUserOrder/CreateNewUserOrderCommandHandler.cs b/src/FrontOffice.BFF.Application/UserOrderCQ/Commands/CreateNewUserOrder/CreateNewUserOrderCommandHandler.cs new file mode 100644 index 0000000..47432dd --- /dev/null +++ b/src/FrontOffice.BFF.Application/UserOrderCQ/Commands/CreateNewUserOrder/CreateNewUserOrderCommandHandler.cs @@ -0,0 +1,16 @@ +namespace FrontOffice.BFF.Application.UserOrderCQ.Commands.CreateNewUserOrder; +public class CreateNewUserOrderCommandHandler : IRequestHandler +{ + private readonly IApplicationContractContext _context; + + public CreateNewUserOrderCommandHandler(IApplicationContractContext context) + { + _context = context; + } + + public async Task Handle(CreateNewUserOrderCommand request, CancellationToken cancellationToken) + { + //TODO: Implement your business logic + return new CreateNewUserOrderResponseDto(); + } +} diff --git a/src/FrontOffice.BFF.Application/UserOrderCQ/Commands/CreateNewUserOrder/CreateNewUserOrderCommandValidator.cs b/src/FrontOffice.BFF.Application/UserOrderCQ/Commands/CreateNewUserOrder/CreateNewUserOrderCommandValidator.cs new file mode 100644 index 0000000..3e26f90 --- /dev/null +++ b/src/FrontOffice.BFF.Application/UserOrderCQ/Commands/CreateNewUserOrder/CreateNewUserOrderCommandValidator.cs @@ -0,0 +1,22 @@ +namespace FrontOffice.BFF.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/FrontOffice.BFF.Application/UserOrderCQ/Commands/CreateNewUserOrder/CreateNewUserOrderResponseDto.cs b/src/FrontOffice.BFF.Application/UserOrderCQ/Commands/CreateNewUserOrder/CreateNewUserOrderResponseDto.cs new file mode 100644 index 0000000..bafdc2b --- /dev/null +++ b/src/FrontOffice.BFF.Application/UserOrderCQ/Commands/CreateNewUserOrder/CreateNewUserOrderResponseDto.cs @@ -0,0 +1,7 @@ +namespace FrontOffice.BFF.Application.UserOrderCQ.Commands.CreateNewUserOrder; +public class CreateNewUserOrderResponseDto +{ + //شناسه + public long Id { get; set; } + +} \ No newline at end of file diff --git a/src/FrontOffice.BFF.Application/UserOrderCQ/Commands/DeleteUserOrder/DeleteUserOrderCommand.cs b/src/FrontOffice.BFF.Application/UserOrderCQ/Commands/DeleteUserOrder/DeleteUserOrderCommand.cs new file mode 100644 index 0000000..e8bf9f5 --- /dev/null +++ b/src/FrontOffice.BFF.Application/UserOrderCQ/Commands/DeleteUserOrder/DeleteUserOrderCommand.cs @@ -0,0 +1,7 @@ +namespace FrontOffice.BFF.Application.UserOrderCQ.Commands.DeleteUserOrder; +public record DeleteUserOrderCommand : IRequest +{ + //شناسه + public long Id { get; init; } + +} \ No newline at end of file diff --git a/src/FrontOffice.BFF.Application/UserOrderCQ/Commands/DeleteUserOrder/DeleteUserOrderCommandHandler.cs b/src/FrontOffice.BFF.Application/UserOrderCQ/Commands/DeleteUserOrder/DeleteUserOrderCommandHandler.cs new file mode 100644 index 0000000..9d6f8bd --- /dev/null +++ b/src/FrontOffice.BFF.Application/UserOrderCQ/Commands/DeleteUserOrder/DeleteUserOrderCommandHandler.cs @@ -0,0 +1,16 @@ +namespace FrontOffice.BFF.Application.UserOrderCQ.Commands.DeleteUserOrder; +public class DeleteUserOrderCommandHandler : IRequestHandler +{ + private readonly IApplicationContractContext _context; + + public DeleteUserOrderCommandHandler(IApplicationContractContext context) + { + _context = context; + } + + public async Task Handle(DeleteUserOrderCommand request, CancellationToken cancellationToken) + { + //TODO: Implement your business logic + return new Unit(); + } +} diff --git a/src/FrontOffice.BFF.Application/UserOrderCQ/Commands/DeleteUserOrder/DeleteUserOrderCommandValidator.cs b/src/FrontOffice.BFF.Application/UserOrderCQ/Commands/DeleteUserOrder/DeleteUserOrderCommandValidator.cs new file mode 100644 index 0000000..b1f0fdc --- /dev/null +++ b/src/FrontOffice.BFF.Application/UserOrderCQ/Commands/DeleteUserOrder/DeleteUserOrderCommandValidator.cs @@ -0,0 +1,16 @@ +namespace FrontOffice.BFF.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/FrontOffice.BFF.Application/UserOrderCQ/Commands/UpdateUserOrder/UpdateUserOrderCommand.cs b/src/FrontOffice.BFF.Application/UserOrderCQ/Commands/UpdateUserOrder/UpdateUserOrderCommand.cs new file mode 100644 index 0000000..cae5a1d --- /dev/null +++ b/src/FrontOffice.BFF.Application/UserOrderCQ/Commands/UpdateUserOrder/UpdateUserOrderCommand.cs @@ -0,0 +1,19 @@ +namespace FrontOffice.BFF.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/FrontOffice.BFF.Application/UserOrderCQ/Commands/UpdateUserOrder/UpdateUserOrderCommandHandler.cs b/src/FrontOffice.BFF.Application/UserOrderCQ/Commands/UpdateUserOrder/UpdateUserOrderCommandHandler.cs new file mode 100644 index 0000000..3fd6b87 --- /dev/null +++ b/src/FrontOffice.BFF.Application/UserOrderCQ/Commands/UpdateUserOrder/UpdateUserOrderCommandHandler.cs @@ -0,0 +1,16 @@ +namespace FrontOffice.BFF.Application.UserOrderCQ.Commands.UpdateUserOrder; +public class UpdateUserOrderCommandHandler : IRequestHandler +{ + private readonly IApplicationContractContext _context; + + public UpdateUserOrderCommandHandler(IApplicationContractContext context) + { + _context = context; + } + + public async Task Handle(UpdateUserOrderCommand request, CancellationToken cancellationToken) + { + //TODO: Implement your business logic + return new Unit(); + } +} diff --git a/src/FrontOffice.BFF.Application/UserOrderCQ/Commands/UpdateUserOrder/UpdateUserOrderCommandValidator.cs b/src/FrontOffice.BFF.Application/UserOrderCQ/Commands/UpdateUserOrder/UpdateUserOrderCommandValidator.cs new file mode 100644 index 0000000..7d77150 --- /dev/null +++ b/src/FrontOffice.BFF.Application/UserOrderCQ/Commands/UpdateUserOrder/UpdateUserOrderCommandValidator.cs @@ -0,0 +1,24 @@ +namespace FrontOffice.BFF.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/FrontOffice.BFF.Application/UserOrderCQ/Queries/GetAllUserOrderByFilter/GetAllUserOrderByFilterQuery.cs b/src/FrontOffice.BFF.Application/UserOrderCQ/Queries/GetAllUserOrderByFilter/GetAllUserOrderByFilterQuery.cs new file mode 100644 index 0000000..1bb4a76 --- /dev/null +++ b/src/FrontOffice.BFF.Application/UserOrderCQ/Queries/GetAllUserOrderByFilter/GetAllUserOrderByFilterQuery.cs @@ -0,0 +1,27 @@ +namespace FrontOffice.BFF.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/FrontOffice.BFF.Application/UserOrderCQ/Queries/GetAllUserOrderByFilter/GetAllUserOrderByFilterQueryHandler.cs b/src/FrontOffice.BFF.Application/UserOrderCQ/Queries/GetAllUserOrderByFilter/GetAllUserOrderByFilterQueryHandler.cs new file mode 100644 index 0000000..32f6077 --- /dev/null +++ b/src/FrontOffice.BFF.Application/UserOrderCQ/Queries/GetAllUserOrderByFilter/GetAllUserOrderByFilterQueryHandler.cs @@ -0,0 +1,16 @@ +namespace FrontOffice.BFF.Application.UserOrderCQ.Queries.GetAllUserOrderByFilter; +public class GetAllUserOrderByFilterQueryHandler : IRequestHandler +{ + private readonly IApplicationContractContext _context; + + public GetAllUserOrderByFilterQueryHandler(IApplicationContractContext context) + { + _context = context; + } + + public async Task Handle(GetAllUserOrderByFilterQuery request, CancellationToken cancellationToken) + { + //TODO: Implement your business logic + return new GetAllUserOrderByFilterResponseDto(); + } +} diff --git a/src/FrontOffice.BFF.Application/UserOrderCQ/Queries/GetAllUserOrderByFilter/GetAllUserOrderByFilterQueryValidator.cs b/src/FrontOffice.BFF.Application/UserOrderCQ/Queries/GetAllUserOrderByFilter/GetAllUserOrderByFilterQueryValidator.cs new file mode 100644 index 0000000..a745c1a --- /dev/null +++ b/src/FrontOffice.BFF.Application/UserOrderCQ/Queries/GetAllUserOrderByFilter/GetAllUserOrderByFilterQueryValidator.cs @@ -0,0 +1,14 @@ +namespace FrontOffice.BFF.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/FrontOffice.BFF.Application/UserOrderCQ/Queries/GetAllUserOrderByFilter/GetAllUserOrderByFilterResponseDto.cs b/src/FrontOffice.BFF.Application/UserOrderCQ/Queries/GetAllUserOrderByFilter/GetAllUserOrderByFilterResponseDto.cs new file mode 100644 index 0000000..e933f60 --- /dev/null +++ b/src/FrontOffice.BFF.Application/UserOrderCQ/Queries/GetAllUserOrderByFilter/GetAllUserOrderByFilterResponseDto.cs @@ -0,0 +1,25 @@ +namespace FrontOffice.BFF.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/FrontOffice.BFF.Application/UserOrderCQ/Queries/GetUserOrder/GetUserOrderQuery.cs b/src/FrontOffice.BFF.Application/UserOrderCQ/Queries/GetUserOrder/GetUserOrderQuery.cs new file mode 100644 index 0000000..24549cf --- /dev/null +++ b/src/FrontOffice.BFF.Application/UserOrderCQ/Queries/GetUserOrder/GetUserOrderQuery.cs @@ -0,0 +1,7 @@ +namespace FrontOffice.BFF.Application.UserOrderCQ.Queries.GetUserOrder; +public record GetUserOrderQuery : IRequest +{ + //شناسه + public long Id { get; init; } + +} \ No newline at end of file diff --git a/src/FrontOffice.BFF.Application/UserOrderCQ/Queries/GetUserOrder/GetUserOrderQueryHandler.cs b/src/FrontOffice.BFF.Application/UserOrderCQ/Queries/GetUserOrder/GetUserOrderQueryHandler.cs new file mode 100644 index 0000000..30b3abc --- /dev/null +++ b/src/FrontOffice.BFF.Application/UserOrderCQ/Queries/GetUserOrder/GetUserOrderQueryHandler.cs @@ -0,0 +1,16 @@ +namespace FrontOffice.BFF.Application.UserOrderCQ.Queries.GetUserOrder; +public class GetUserOrderQueryHandler : IRequestHandler +{ + private readonly IApplicationContractContext _context; + + public GetUserOrderQueryHandler(IApplicationContractContext context) + { + _context = context; + } + + public async Task Handle(GetUserOrderQuery request, CancellationToken cancellationToken) + { + //TODO: Implement your business logic + return new GetUserOrderResponseDto(); + } +} diff --git a/src/FrontOffice.BFF.Application/UserOrderCQ/Queries/GetUserOrder/GetUserOrderQueryValidator.cs b/src/FrontOffice.BFF.Application/UserOrderCQ/Queries/GetUserOrder/GetUserOrderQueryValidator.cs new file mode 100644 index 0000000..2ea7efa --- /dev/null +++ b/src/FrontOffice.BFF.Application/UserOrderCQ/Queries/GetUserOrder/GetUserOrderQueryValidator.cs @@ -0,0 +1,16 @@ +namespace FrontOffice.BFF.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/FrontOffice.BFF.Application/UserOrderCQ/Queries/GetUserOrder/GetUserOrderResponseDto.cs b/src/FrontOffice.BFF.Application/UserOrderCQ/Queries/GetUserOrder/GetUserOrderResponseDto.cs new file mode 100644 index 0000000..6dd1a77 --- /dev/null +++ b/src/FrontOffice.BFF.Application/UserOrderCQ/Queries/GetUserOrder/GetUserOrderResponseDto.cs @@ -0,0 +1,19 @@ +namespace FrontOffice.BFF.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/FrontOffice.BFF.Application/UserRoleCQ/Commands/CreateNewUserRole/CreateNewUserRoleCommand.cs b/src/FrontOffice.BFF.Application/UserRoleCQ/Commands/CreateNewUserRole/CreateNewUserRoleCommand.cs new file mode 100644 index 0000000..9ae5c60 --- /dev/null +++ b/src/FrontOffice.BFF.Application/UserRoleCQ/Commands/CreateNewUserRole/CreateNewUserRoleCommand.cs @@ -0,0 +1,9 @@ +namespace FrontOffice.BFF.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/FrontOffice.BFF.Application/UserRoleCQ/Commands/CreateNewUserRole/CreateNewUserRoleCommandHandler.cs b/src/FrontOffice.BFF.Application/UserRoleCQ/Commands/CreateNewUserRole/CreateNewUserRoleCommandHandler.cs new file mode 100644 index 0000000..efe2afc --- /dev/null +++ b/src/FrontOffice.BFF.Application/UserRoleCQ/Commands/CreateNewUserRole/CreateNewUserRoleCommandHandler.cs @@ -0,0 +1,16 @@ +namespace FrontOffice.BFF.Application.UserRoleCQ.Commands.CreateNewUserRole; +public class CreateNewUserRoleCommandHandler : IRequestHandler +{ + private readonly IApplicationContractContext _context; + + public CreateNewUserRoleCommandHandler(IApplicationContractContext context) + { + _context = context; + } + + public async Task Handle(CreateNewUserRoleCommand request, CancellationToken cancellationToken) + { + //TODO: Implement your business logic + return new CreateNewUserRoleResponseDto(); + } +} diff --git a/src/FrontOffice.BFF.Application/UserRoleCQ/Commands/CreateNewUserRole/CreateNewUserRoleCommandValidator.cs b/src/FrontOffice.BFF.Application/UserRoleCQ/Commands/CreateNewUserRole/CreateNewUserRoleCommandValidator.cs new file mode 100644 index 0000000..f061946 --- /dev/null +++ b/src/FrontOffice.BFF.Application/UserRoleCQ/Commands/CreateNewUserRole/CreateNewUserRoleCommandValidator.cs @@ -0,0 +1,18 @@ +namespace FrontOffice.BFF.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/FrontOffice.BFF.Application/UserRoleCQ/Commands/CreateNewUserRole/CreateNewUserRoleResponseDto.cs b/src/FrontOffice.BFF.Application/UserRoleCQ/Commands/CreateNewUserRole/CreateNewUserRoleResponseDto.cs new file mode 100644 index 0000000..a39888d --- /dev/null +++ b/src/FrontOffice.BFF.Application/UserRoleCQ/Commands/CreateNewUserRole/CreateNewUserRoleResponseDto.cs @@ -0,0 +1,7 @@ +namespace FrontOffice.BFF.Application.UserRoleCQ.Commands.CreateNewUserRole; +public class CreateNewUserRoleResponseDto +{ + //شناسه + public long Id { get; set; } + +} \ No newline at end of file diff --git a/src/FrontOffice.BFF.Application/UserRoleCQ/Commands/DeleteUserRole/DeleteUserRoleCommand.cs b/src/FrontOffice.BFF.Application/UserRoleCQ/Commands/DeleteUserRole/DeleteUserRoleCommand.cs new file mode 100644 index 0000000..8850934 --- /dev/null +++ b/src/FrontOffice.BFF.Application/UserRoleCQ/Commands/DeleteUserRole/DeleteUserRoleCommand.cs @@ -0,0 +1,7 @@ +namespace FrontOffice.BFF.Application.UserRoleCQ.Commands.DeleteUserRole; +public record DeleteUserRoleCommand : IRequest +{ + //شناسه + public long Id { get; init; } + +} \ No newline at end of file diff --git a/src/FrontOffice.BFF.Application/UserRoleCQ/Commands/DeleteUserRole/DeleteUserRoleCommandHandler.cs b/src/FrontOffice.BFF.Application/UserRoleCQ/Commands/DeleteUserRole/DeleteUserRoleCommandHandler.cs new file mode 100644 index 0000000..974cb92 --- /dev/null +++ b/src/FrontOffice.BFF.Application/UserRoleCQ/Commands/DeleteUserRole/DeleteUserRoleCommandHandler.cs @@ -0,0 +1,16 @@ +namespace FrontOffice.BFF.Application.UserRoleCQ.Commands.DeleteUserRole; +public class DeleteUserRoleCommandHandler : IRequestHandler +{ + private readonly IApplicationContractContext _context; + + public DeleteUserRoleCommandHandler(IApplicationContractContext context) + { + _context = context; + } + + public async Task Handle(DeleteUserRoleCommand request, CancellationToken cancellationToken) + { + //TODO: Implement your business logic + return new Unit(); + } +} diff --git a/src/FrontOffice.BFF.Application/UserRoleCQ/Commands/DeleteUserRole/DeleteUserRoleCommandValidator.cs b/src/FrontOffice.BFF.Application/UserRoleCQ/Commands/DeleteUserRole/DeleteUserRoleCommandValidator.cs new file mode 100644 index 0000000..94ba9af --- /dev/null +++ b/src/FrontOffice.BFF.Application/UserRoleCQ/Commands/DeleteUserRole/DeleteUserRoleCommandValidator.cs @@ -0,0 +1,16 @@ +namespace FrontOffice.BFF.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/FrontOffice.BFF.Application/UserRoleCQ/Commands/UpdateUserRole/UpdateUserRoleCommand.cs b/src/FrontOffice.BFF.Application/UserRoleCQ/Commands/UpdateUserRole/UpdateUserRoleCommand.cs new file mode 100644 index 0000000..341dd11 --- /dev/null +++ b/src/FrontOffice.BFF.Application/UserRoleCQ/Commands/UpdateUserRole/UpdateUserRoleCommand.cs @@ -0,0 +1,11 @@ +namespace FrontOffice.BFF.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/FrontOffice.BFF.Application/UserRoleCQ/Commands/UpdateUserRole/UpdateUserRoleCommandHandler.cs b/src/FrontOffice.BFF.Application/UserRoleCQ/Commands/UpdateUserRole/UpdateUserRoleCommandHandler.cs new file mode 100644 index 0000000..b35dbaa --- /dev/null +++ b/src/FrontOffice.BFF.Application/UserRoleCQ/Commands/UpdateUserRole/UpdateUserRoleCommandHandler.cs @@ -0,0 +1,16 @@ +namespace FrontOffice.BFF.Application.UserRoleCQ.Commands.UpdateUserRole; +public class UpdateUserRoleCommandHandler : IRequestHandler +{ + private readonly IApplicationContractContext _context; + + public UpdateUserRoleCommandHandler(IApplicationContractContext context) + { + _context = context; + } + + public async Task Handle(UpdateUserRoleCommand request, CancellationToken cancellationToken) + { + //TODO: Implement your business logic + return new Unit(); + } +} diff --git a/src/FrontOffice.BFF.Application/UserRoleCQ/Commands/UpdateUserRole/UpdateUserRoleCommandValidator.cs b/src/FrontOffice.BFF.Application/UserRoleCQ/Commands/UpdateUserRole/UpdateUserRoleCommandValidator.cs new file mode 100644 index 0000000..bb316a5 --- /dev/null +++ b/src/FrontOffice.BFF.Application/UserRoleCQ/Commands/UpdateUserRole/UpdateUserRoleCommandValidator.cs @@ -0,0 +1,20 @@ +namespace FrontOffice.BFF.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/FrontOffice.BFF.Application/UserRoleCQ/Queries/GetAllUserRoleByFilter/GetAllUserRoleByFilterQuery.cs b/src/FrontOffice.BFF.Application/UserRoleCQ/Queries/GetAllUserRoleByFilter/GetAllUserRoleByFilterQuery.cs new file mode 100644 index 0000000..bb5673e --- /dev/null +++ b/src/FrontOffice.BFF.Application/UserRoleCQ/Queries/GetAllUserRoleByFilter/GetAllUserRoleByFilterQuery.cs @@ -0,0 +1,19 @@ +namespace FrontOffice.BFF.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/FrontOffice.BFF.Application/UserRoleCQ/Queries/GetAllUserRoleByFilter/GetAllUserRoleByFilterQueryHandler.cs b/src/FrontOffice.BFF.Application/UserRoleCQ/Queries/GetAllUserRoleByFilter/GetAllUserRoleByFilterQueryHandler.cs new file mode 100644 index 0000000..42eb473 --- /dev/null +++ b/src/FrontOffice.BFF.Application/UserRoleCQ/Queries/GetAllUserRoleByFilter/GetAllUserRoleByFilterQueryHandler.cs @@ -0,0 +1,16 @@ +namespace FrontOffice.BFF.Application.UserRoleCQ.Queries.GetAllUserRoleByFilter; +public class GetAllUserRoleByFilterQueryHandler : IRequestHandler +{ + private readonly IApplicationContractContext _context; + + public GetAllUserRoleByFilterQueryHandler(IApplicationContractContext context) + { + _context = context; + } + + public async Task Handle(GetAllUserRoleByFilterQuery request, CancellationToken cancellationToken) + { + //TODO: Implement your business logic + return new GetAllUserRoleByFilterResponseDto(); + } +} diff --git a/src/FrontOffice.BFF.Application/UserRoleCQ/Queries/GetAllUserRoleByFilter/GetAllUserRoleByFilterQueryValidator.cs b/src/FrontOffice.BFF.Application/UserRoleCQ/Queries/GetAllUserRoleByFilter/GetAllUserRoleByFilterQueryValidator.cs new file mode 100644 index 0000000..6b5ba03 --- /dev/null +++ b/src/FrontOffice.BFF.Application/UserRoleCQ/Queries/GetAllUserRoleByFilter/GetAllUserRoleByFilterQueryValidator.cs @@ -0,0 +1,14 @@ +namespace FrontOffice.BFF.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/FrontOffice.BFF.Application/UserRoleCQ/Queries/GetAllUserRoleByFilter/GetAllUserRoleByFilterResponseDto.cs b/src/FrontOffice.BFF.Application/UserRoleCQ/Queries/GetAllUserRoleByFilter/GetAllUserRoleByFilterResponseDto.cs new file mode 100644 index 0000000..c0fe4a4 --- /dev/null +++ b/src/FrontOffice.BFF.Application/UserRoleCQ/Queries/GetAllUserRoleByFilter/GetAllUserRoleByFilterResponseDto.cs @@ -0,0 +1,17 @@ +namespace FrontOffice.BFF.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/FrontOffice.BFF.Application/UserRoleCQ/Queries/GetUserRole/GetUserRoleQuery.cs b/src/FrontOffice.BFF.Application/UserRoleCQ/Queries/GetUserRole/GetUserRoleQuery.cs new file mode 100644 index 0000000..8c52541 --- /dev/null +++ b/src/FrontOffice.BFF.Application/UserRoleCQ/Queries/GetUserRole/GetUserRoleQuery.cs @@ -0,0 +1,7 @@ +namespace FrontOffice.BFF.Application.UserRoleCQ.Queries.GetUserRole; +public record GetUserRoleQuery : IRequest +{ + //شناسه + public long Id { get; init; } + +} \ No newline at end of file diff --git a/src/FrontOffice.BFF.Application/UserRoleCQ/Queries/GetUserRole/GetUserRoleQueryHandler.cs b/src/FrontOffice.BFF.Application/UserRoleCQ/Queries/GetUserRole/GetUserRoleQueryHandler.cs new file mode 100644 index 0000000..36ae41b --- /dev/null +++ b/src/FrontOffice.BFF.Application/UserRoleCQ/Queries/GetUserRole/GetUserRoleQueryHandler.cs @@ -0,0 +1,16 @@ +namespace FrontOffice.BFF.Application.UserRoleCQ.Queries.GetUserRole; +public class GetUserRoleQueryHandler : IRequestHandler +{ + private readonly IApplicationContractContext _context; + + public GetUserRoleQueryHandler(IApplicationContractContext context) + { + _context = context; + } + + public async Task Handle(GetUserRoleQuery request, CancellationToken cancellationToken) + { + //TODO: Implement your business logic + return new GetUserRoleResponseDto(); + } +} diff --git a/src/FrontOffice.BFF.Application/UserRoleCQ/Queries/GetUserRole/GetUserRoleQueryValidator.cs b/src/FrontOffice.BFF.Application/UserRoleCQ/Queries/GetUserRole/GetUserRoleQueryValidator.cs new file mode 100644 index 0000000..b1e96b9 --- /dev/null +++ b/src/FrontOffice.BFF.Application/UserRoleCQ/Queries/GetUserRole/GetUserRoleQueryValidator.cs @@ -0,0 +1,16 @@ +namespace FrontOffice.BFF.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/FrontOffice.BFF.Application/UserRoleCQ/Queries/GetUserRole/GetUserRoleResponseDto.cs b/src/FrontOffice.BFF.Application/UserRoleCQ/Queries/GetUserRole/GetUserRoleResponseDto.cs new file mode 100644 index 0000000..8587d4e --- /dev/null +++ b/src/FrontOffice.BFF.Application/UserRoleCQ/Queries/GetUserRole/GetUserRoleResponseDto.cs @@ -0,0 +1,11 @@ +namespace FrontOffice.BFF.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/FrontOffice.BFF.Domain/FrontOffice.BFF.Domain.csproj b/src/FrontOffice.BFF.Domain/FrontOffice.BFF.Domain.csproj new file mode 100644 index 0000000..b72d8bb --- /dev/null +++ b/src/FrontOffice.BFF.Domain/FrontOffice.BFF.Domain.csproj @@ -0,0 +1,17 @@ + + + + net7.0 + enable + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + diff --git a/src/FrontOffice.BFF.Infrastructure/ConfigureGrpcServices.cs b/src/FrontOffice.BFF.Infrastructure/ConfigureGrpcServices.cs new file mode 100644 index 0000000..e4ce656 --- /dev/null +++ b/src/FrontOffice.BFF.Infrastructure/ConfigureGrpcServices.cs @@ -0,0 +1,101 @@ +using System.Diagnostics; +using System.Reflection; +using FrontOffice.BFF.Application.Common.Interfaces; +using Grpc.Core; +using System.Net.Http; +using Grpc.Net.ClientFactory; +using Microsoft.Extensions.Configuration; + +namespace Microsoft.Extensions.DependencyInjection; + +public static class ConfigureGrpcServices +{ + public static IServiceCollection BatchRegisterGrpcClients(this IServiceCollection services, + IConfiguration configuration) + { + Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); + var grpcClients = assemblies + .Where(x => + x.FullName != null && + x.FullName.Contains("Microservice.Protobuf") && + x.GetTypes().Any(type => type.BaseType != null && type.BaseType.Name == "ClientBase`1" && type.BaseType.Namespace == "Grpc.Core") + ) + .SelectMany(x => x + .GetTypes() + .Where(type => type.BaseType != null && type.BaseType.Name == "ClientBase`1" && type.BaseType.Namespace == "Grpc.Core").ToList() + ).ToList(); + + // get configuration as dictionary + var clientAddress = configuration.GetSection("GrpcChannelOptions") + .GetChildren().ToDictionary(x => x.Key, x => x.Value); + + // get register method + var method = typeof(GrpcClientServiceExtensions).GetMethod("AddGrpcClient", + new[] { typeof(IServiceCollection), typeof(string), typeof(Action) }); + + var httpHandler = new HttpClientHandler(); + //TODO: چک شود + // Return `true` to allow certificates that are untrusted/invalid + httpHandler.ServerCertificateCustomValidationCallback = + HttpClientHandler.DangerousAcceptAnyServerCertificateValidator; + + // register clients + foreach (var (key, address) in clientAddress) + { + var msName = key.Replace("MSAddress", ""); + // loop over clients + foreach (var grpcClient in grpcClients.Where(t => + t.AssemblyQualifiedName != null && + t.AssemblyQualifiedName.StartsWith($"{msName}Microservice")) + .ToList()) + { + // make generic method with parameter + var generic = method?.MakeGenericMethod(grpcClient); + + Console.WriteLine($"Registering {grpcClient.Name} of {msName} to {address}"); + //if (grpcClient.Name == "PublicMessageContractClient") + // continue; + + // invoke method with parameters + var callResult = generic?.Invoke(null, + new object[] + { + services,$"{grpcClient.Namespace}",(GrpcClientFactoryOptions o) => { o.Address = new Uri(address); } + }); + + if (callResult == null) + { + Console.WriteLine($"Error registering {grpcClient.Name} of {msName} to {address}"); + continue; + } + + ((IHttpClientBuilder)callResult) + .AddCallCredentials(CallCredentials) + .ConfigureChannel(o => + { + o.HttpHandler = httpHandler; + o.UnsafeUseInsecureChannelCallCredentials = true; + o.MaxReceiveMessageSize = 1000 * 1024 * 1024; // 1 GB + o.MaxSendMessageSize = 1000 * 1024 * 1024; // 1 GB + }); + } + } + + return services; + } + + public static IServiceCollection AddInfrastructureGrpcServices(this IServiceCollection services, + IConfiguration configuration) + { + services.BatchRegisterGrpcClients(configuration); + return services; + } + + private static async Task CallCredentials(AuthInterceptorContext context, Metadata metadata, + IServiceProvider serviceProvider) + { + var provider = serviceProvider.GetRequiredService(); + var token = await provider.GetTokenAsync(); + metadata.Add("Authorization", $"Bearer {token}"); + } +} \ No newline at end of file diff --git a/src/FrontOffice.BFF.Infrastructure/ConfigureServices.cs b/src/FrontOffice.BFF.Infrastructure/ConfigureServices.cs new file mode 100644 index 0000000..4c6014a --- /dev/null +++ b/src/FrontOffice.BFF.Infrastructure/ConfigureServices.cs @@ -0,0 +1,77 @@ +using System.Diagnostics; +using FrontOffice.BFF.Application.Common.Interfaces; +using FrontOffice.BFF.Infrastructure.Services; +using Microsoft.AspNetCore.Authentication.JwtBearer; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Configuration; + +namespace Microsoft.Extensions.DependencyInjection; + +public static class ConfigureServices +{ + public static IServiceCollection AddInfrastructureServices(this IServiceCollection services, IConfiguration configuration) + { + services.AddSingleton(); + services.AddInfrastructureGrpcServices(configuration); + #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/FrontOffice.BFF.Infrastructure/FrontOffice.BFF.Infrastructure.csproj b/src/FrontOffice.BFF.Infrastructure/FrontOffice.BFF.Infrastructure.csproj new file mode 100644 index 0000000..cbacbe6 --- /dev/null +++ b/src/FrontOffice.BFF.Infrastructure/FrontOffice.BFF.Infrastructure.csproj @@ -0,0 +1,16 @@ + + + + net7.0 + enable + + + + + + + + + + + \ No newline at end of file diff --git a/src/FrontOffice.BFF.Infrastructure/GlobalUsings.cs b/src/FrontOffice.BFF.Infrastructure/GlobalUsings.cs new file mode 100644 index 0000000..549d4e4 --- /dev/null +++ b/src/FrontOffice.BFF.Infrastructure/GlobalUsings.cs @@ -0,0 +1,5 @@ +global using System; +global using System.Collections.Generic; +global using System.Linq; +global using System.Text; +global using System.Threading.Tasks; \ No newline at end of file diff --git a/src/FrontOffice.BFF.Infrastructure/Services/ApplicationContractContext.cs b/src/FrontOffice.BFF.Infrastructure/Services/ApplicationContractContext.cs new file mode 100644 index 0000000..0105996 --- /dev/null +++ b/src/FrontOffice.BFF.Infrastructure/Services/ApplicationContractContext.cs @@ -0,0 +1,36 @@ +using FrontOffice.BFF.Application.Common.Interfaces; +using Microsoft.Extensions.DependencyInjection; + +namespace FrontOffice.BFF.Infrastructure.Services; + +public class ApplicationContractContext : IApplicationContractContext +{ + #region members + + private readonly IServiceProvider _serviceProvider; + + #endregion + + + #region utilities + + private T GetService() where T : Grpc.Core.ClientBase + { + return _serviceProvider.GetService() ?? + throw new Exception($"requested service not registered: {typeof(T).FullName}"); + } + + #endregion + + public ApplicationContractContext(IServiceProvider serviceProvider) + { + _serviceProvider = serviceProvider; + } + + #region FM + + //public FileLogContract.FileLogContractClient FileManagements => GetService(); + + #endregion + +} \ No newline at end of file diff --git a/src/FrontOffice.BFF.WebApi/Common/Mappings/GeneralMapping.cs b/src/FrontOffice.BFF.WebApi/Common/Mappings/GeneralMapping.cs new file mode 100644 index 0000000..c70e564 --- /dev/null +++ b/src/FrontOffice.BFF.WebApi/Common/Mappings/GeneralMapping.cs @@ -0,0 +1,64 @@ +using System.Globalization; +namespace FrontOffice.BFF.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/FrontOffice.BFF.WebApi/Common/Mappings/PackageProfile.cs b/src/FrontOffice.BFF.WebApi/Common/Mappings/PackageProfile.cs new file mode 100644 index 0000000..c081cf7 --- /dev/null +++ b/src/FrontOffice.BFF.WebApi/Common/Mappings/PackageProfile.cs @@ -0,0 +1,10 @@ +namespace FrontOffice.BFF.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/FrontOffice.BFF.WebApi/Common/Mappings/RoleProfile.cs b/src/FrontOffice.BFF.WebApi/Common/Mappings/RoleProfile.cs new file mode 100644 index 0000000..200c955 --- /dev/null +++ b/src/FrontOffice.BFF.WebApi/Common/Mappings/RoleProfile.cs @@ -0,0 +1,10 @@ +namespace FrontOffice.BFF.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/FrontOffice.BFF.WebApi/Common/Mappings/UserAddressProfile.cs b/src/FrontOffice.BFF.WebApi/Common/Mappings/UserAddressProfile.cs new file mode 100644 index 0000000..12adbeb --- /dev/null +++ b/src/FrontOffice.BFF.WebApi/Common/Mappings/UserAddressProfile.cs @@ -0,0 +1,10 @@ +namespace FrontOffice.BFF.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/FrontOffice.BFF.WebApi/Common/Mappings/UserOrderProfile.cs b/src/FrontOffice.BFF.WebApi/Common/Mappings/UserOrderProfile.cs new file mode 100644 index 0000000..300371a --- /dev/null +++ b/src/FrontOffice.BFF.WebApi/Common/Mappings/UserOrderProfile.cs @@ -0,0 +1,10 @@ +namespace FrontOffice.BFF.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/FrontOffice.BFF.WebApi/Common/Mappings/UserProfile.cs b/src/FrontOffice.BFF.WebApi/Common/Mappings/UserProfile.cs new file mode 100644 index 0000000..6a3732f --- /dev/null +++ b/src/FrontOffice.BFF.WebApi/Common/Mappings/UserProfile.cs @@ -0,0 +1,10 @@ +namespace FrontOffice.BFF.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/FrontOffice.BFF.WebApi/Common/Mappings/UserRoleProfile.cs b/src/FrontOffice.BFF.WebApi/Common/Mappings/UserRoleProfile.cs new file mode 100644 index 0000000..6243a26 --- /dev/null +++ b/src/FrontOffice.BFF.WebApi/Common/Mappings/UserRoleProfile.cs @@ -0,0 +1,10 @@ +namespace FrontOffice.BFF.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/FrontOffice.BFF.WebApi/Common/Services/AppTokenProvider.cs b/src/FrontOffice.BFF.WebApi/Common/Services/AppTokenProvider.cs new file mode 100644 index 0000000..2bff616 --- /dev/null +++ b/src/FrontOffice.BFF.WebApi/Common/Services/AppTokenProvider.cs @@ -0,0 +1,49 @@ +using FrontOffice.BFF.Application.Common.Interfaces; +using Microsoft.Net.Http.Headers; + +namespace FrontOffice.BFF.WebApi.Common.Services; + +public class AppTokenProvider : ITokenProvider +{ + private readonly IHttpContextAccessor _httpContextAccessor; + private string? _token; + + public AppTokenProvider(IHttpContextAccessor httpContextAccessor) + { + _httpContextAccessor = httpContextAccessor; + } + + public async Task GetTokenAsync() + { + if (_token != null) + { + return _token; + } + + // get token string + var authorizationToken = _httpContextAccessor.HttpContext?.Request.Headers[HeaderNames.Authorization]; + + if (!string.IsNullOrEmpty(authorizationToken)) + _token = authorizationToken.ToString().Replace("Bearer ", ""); + + return _token; + + // return await Task.FromResult(GetToken()) ?? string.Empty; + } + + private string? GetToken() + { + if (_token != null) return _token; + + // get token string + var authorizationToken = _httpContextAccessor.HttpContext?.Request.Headers[HeaderNames.Authorization]; + if (authorizationToken is null) return _token; + + var token = authorizationToken.Value.ToString(); + if (string.IsNullOrEmpty(token)) return _token; + + _token = token; + + return _token; + } +} diff --git a/src/FrontOffice.BFF.WebApi/Common/Services/CurrentUserService.cs b/src/FrontOffice.BFF.WebApi/Common/Services/CurrentUserService.cs new file mode 100644 index 0000000..1a2de5f --- /dev/null +++ b/src/FrontOffice.BFF.WebApi/Common/Services/CurrentUserService.cs @@ -0,0 +1,17 @@ +using System.Security.Claims; +using FrontOffice.BFF.Application.Common.Interfaces; +using Microsoft.AspNetCore.Http; + +namespace FrontOffice.BFF.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/FrontOffice.BFF.WebApi/Common/Services/DispatchRequestToCQRS.cs b/src/FrontOffice.BFF.WebApi/Common/Services/DispatchRequestToCQRS.cs new file mode 100644 index 0000000..7e906f7 --- /dev/null +++ b/src/FrontOffice.BFF.WebApi/Common/Services/DispatchRequestToCQRS.cs @@ -0,0 +1,87 @@ +namespace FrontOffice.BFF.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/FrontOffice.BFF.WebApi/ConfigureServices.cs b/src/FrontOffice.BFF.WebApi/ConfigureServices.cs new file mode 100644 index 0000000..0275139 --- /dev/null +++ b/src/FrontOffice.BFF.WebApi/ConfigureServices.cs @@ -0,0 +1,68 @@ +using FrontOffice.BFF.Application.Common.Interfaces; +using FrontOffice.BFF.WebApi.Common.Services; +using MapsterMapper; +using System.Reflection; + +namespace Microsoft.Extensions.DependencyInjection; + +public static class ConfigureServices +{ + public static IServiceCollection AddPresentationServices(this IServiceCollection services, IConfiguration configuration) + { + services.AddMapping(); + services.AddHttpContextAccessor(); + services.AddTransient(); + services.AddTransient(); + services.AddScoped(); + 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/FrontOffice.BFF.WebApi/FrontOffice.BFF.WebApi.csproj b/src/FrontOffice.BFF.WebApi/FrontOffice.BFF.WebApi.csproj new file mode 100644 index 0000000..fc19056 --- /dev/null +++ b/src/FrontOffice.BFF.WebApi/FrontOffice.BFF.WebApi.csproj @@ -0,0 +1,32 @@ + + + + net7.0 + enable + Linux + ..\..\.. + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/FrontOffice.BFF.WebApi/GlobalUsings.cs b/src/FrontOffice.BFF.WebApi/GlobalUsings.cs new file mode 100644 index 0000000..f566ed2 --- /dev/null +++ b/src/FrontOffice.BFF.WebApi/GlobalUsings.cs @@ -0,0 +1,11 @@ +global using Google.Protobuf.WellKnownTypes; +global using Grpc.Core; +global using Mapster; +global using MediatR; +global using Microsoft.AspNetCore.Authorization; +global using Microsoft.AspNetCore.Http; +global using System.Threading.Tasks; +global using Microsoft.AspNetCore.Builder; +global using System; +global using Microsoft.AspNetCore.Routing; +global using System.Linq; diff --git a/src/FrontOffice.BFF.WebApi/Program.cs b/src/FrontOffice.BFF.WebApi/Program.cs new file mode 100644 index 0000000..44dbde4 --- /dev/null +++ b/src/FrontOffice.BFF.WebApi/Program.cs @@ -0,0 +1,109 @@ +using System.Reflection; +using System.Runtime.InteropServices; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.AspNetCore.Server.Kestrel.Core; +using Serilog; +using Serilog.Core; +using Serilog.Sinks.MSSqlServer; +using Microsoft.OpenApi.Models; + +var builder = WebApplication.CreateBuilder(args); +if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) +{ + builder.WebHost.ConfigureKestrel(options => + { + // Setup a HTTP/2 endpoint without TLS. + options.ListenLocalhost(5000, o => o.Protocols = + HttpProtocols.Http2); + }); +} + +var levelSwitch = new LoggingLevelSwitch(); +var logger = new LoggerConfiguration() + //.WriteTo.Console() + .WriteTo.MSSqlServer(builder.Configuration.GetConnectionString("LogConnection"), + sinkOptions: new MSSqlServerSinkOptions + { + TableName = "Log_FrontOffice_BFF_WebApi_Events", + 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.EnableDetailedErrors = true; + options.MaxReceiveMessageSize = 1000 * 1024 * 1024; // 1 GB + options.MaxSendMessageSize = 1000 * 1024 * 1024; // 1 GB +}).AddJsonTranscoding(); +builder.Services.AddInfrastructureServices(builder.Configuration); +builder.Services.AddApplicationServices(); +builder.Services.AddPresentationServices(builder.Configuration); + +#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(); + +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/FrontOffice.BFF.WebApi/Services/PackageService.cs b/src/FrontOffice.BFF.WebApi/Services/PackageService.cs new file mode 100644 index 0000000..206e568 --- /dev/null +++ b/src/FrontOffice.BFF.WebApi/Services/PackageService.cs @@ -0,0 +1,37 @@ +using FrontOffice.BFF.Package.Protobuf.Protos.Package; +using FrontOffice.BFF.WebApi.Common.Services; +using FrontOffice.BFF.Application.PackageCQ.Commands.CreateNewPackage; +using FrontOffice.BFF.Application.PackageCQ.Commands.UpdatePackage; +using FrontOffice.BFF.Application.PackageCQ.Commands.DeletePackage; +using FrontOffice.BFF.Application.PackageCQ.Queries.GetPackage; +using FrontOffice.BFF.Application.PackageCQ.Queries.GetAllPackageByFilter; +namespace FrontOffice.BFF.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/FrontOffice.BFF.WebApi/Services/RoleService.cs b/src/FrontOffice.BFF.WebApi/Services/RoleService.cs new file mode 100644 index 0000000..ad08b58 --- /dev/null +++ b/src/FrontOffice.BFF.WebApi/Services/RoleService.cs @@ -0,0 +1,37 @@ +using FrontOffice.BFF.Role.Protobuf.Protos.Role; +using FrontOffice.BFF.WebApi.Common.Services; +using FrontOffice.BFF.Application.RoleCQ.Commands.CreateNewRole; +using FrontOffice.BFF.Application.RoleCQ.Commands.UpdateRole; +using FrontOffice.BFF.Application.RoleCQ.Commands.DeleteRole; +using FrontOffice.BFF.Application.RoleCQ.Queries.GetRole; +using FrontOffice.BFF.Application.RoleCQ.Queries.GetAllRoleByFilter; +namespace FrontOffice.BFF.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/FrontOffice.BFF.WebApi/Services/UserAddressService.cs b/src/FrontOffice.BFF.WebApi/Services/UserAddressService.cs new file mode 100644 index 0000000..7858653 --- /dev/null +++ b/src/FrontOffice.BFF.WebApi/Services/UserAddressService.cs @@ -0,0 +1,37 @@ +using FrontOffice.BFF.UserAddress.Protobuf.Protos.UserAddress; +using FrontOffice.BFF.WebApi.Common.Services; +using FrontOffice.BFF.Application.UserAddressCQ.Commands.CreateNewUserAddress; +using FrontOffice.BFF.Application.UserAddressCQ.Commands.UpdateUserAddress; +using FrontOffice.BFF.Application.UserAddressCQ.Commands.DeleteUserAddress; +using FrontOffice.BFF.Application.UserAddressCQ.Queries.GetUserAddress; +using FrontOffice.BFF.Application.UserAddressCQ.Queries.GetAllUserAddressByFilter; +namespace FrontOffice.BFF.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/FrontOffice.BFF.WebApi/Services/UserOrderService.cs b/src/FrontOffice.BFF.WebApi/Services/UserOrderService.cs new file mode 100644 index 0000000..f5a306b --- /dev/null +++ b/src/FrontOffice.BFF.WebApi/Services/UserOrderService.cs @@ -0,0 +1,37 @@ +using FrontOffice.BFF.UserOrder.Protobuf.Protos.UserOrder; +using FrontOffice.BFF.WebApi.Common.Services; +using FrontOffice.BFF.Application.UserOrderCQ.Commands.CreateNewUserOrder; +using FrontOffice.BFF.Application.UserOrderCQ.Commands.UpdateUserOrder; +using FrontOffice.BFF.Application.UserOrderCQ.Commands.DeleteUserOrder; +using FrontOffice.BFF.Application.UserOrderCQ.Queries.GetUserOrder; +using FrontOffice.BFF.Application.UserOrderCQ.Queries.GetAllUserOrderByFilter; +namespace FrontOffice.BFF.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/FrontOffice.BFF.WebApi/Services/UserRoleService.cs b/src/FrontOffice.BFF.WebApi/Services/UserRoleService.cs new file mode 100644 index 0000000..3dc04a9 --- /dev/null +++ b/src/FrontOffice.BFF.WebApi/Services/UserRoleService.cs @@ -0,0 +1,37 @@ +using FrontOffice.BFF.UserRole.Protobuf.Protos.UserRole; +using FrontOffice.BFF.WebApi.Common.Services; +using FrontOffice.BFF.Application.UserRoleCQ.Commands.CreateNewUserRole; +using FrontOffice.BFF.Application.UserRoleCQ.Commands.UpdateUserRole; +using FrontOffice.BFF.Application.UserRoleCQ.Commands.DeleteUserRole; +using FrontOffice.BFF.Application.UserRoleCQ.Queries.GetUserRole; +using FrontOffice.BFF.Application.UserRoleCQ.Queries.GetAllUserRoleByFilter; +namespace FrontOffice.BFF.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/FrontOffice.BFF.WebApi/Services/UserService.cs b/src/FrontOffice.BFF.WebApi/Services/UserService.cs new file mode 100644 index 0000000..6f346af --- /dev/null +++ b/src/FrontOffice.BFF.WebApi/Services/UserService.cs @@ -0,0 +1,37 @@ +using FrontOffice.BFF.User.Protobuf.Protos.User; +using FrontOffice.BFF.WebApi.Common.Services; +using FrontOffice.BFF.Application.UserCQ.Commands.CreateNewUser; +using FrontOffice.BFF.Application.UserCQ.Commands.UpdateUser; +using FrontOffice.BFF.Application.UserCQ.Commands.DeleteUser; +using FrontOffice.BFF.Application.UserCQ.Queries.GetUser; +using FrontOffice.BFF.Application.UserCQ.Queries.GetAllUserByFilter; +namespace FrontOffice.BFF.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/FrontOffice.BFF.WebApi/appsettings.Development.json b/src/FrontOffice.BFF.WebApi/appsettings.Development.json new file mode 100644 index 0000000..fe20c40 --- /dev/null +++ b/src/FrontOffice.BFF.WebApi/appsettings.Development.json @@ -0,0 +1,10 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Debug", + "System": "Information", + "Grpc": "Information", + "Microsoft": "Information" + } + } +} diff --git a/src/FrontOffice.BFF.WebApi/appsettings.json b/src/FrontOffice.BFF.WebApi/appsettings.json new file mode 100644 index 0000000..c64cea5 --- /dev/null +++ b/src/FrontOffice.BFF.WebApi/appsettings.json @@ -0,0 +1,19 @@ +{ + "AllowedHosts": "*", + "Kestrel": { + "EndpointDefaults": { + "Protocols": "Http2" + } + }, + "ConnectionStrings": { + "LogConnection": "Data Source=.,2019; Initial Catalog=DBName;User ID=dbuser;Password=dbpassword;Connection Timeout=300000;MultipleActiveResultSets=True;Encrypt=False", + "providerName": "System.Data.SqlClient" + }, + "GrpcChannelOptions": { + //"FileManagementMSAddress": "https://localhost:31307" + }, + "Authentication": { + "Authority": "https://ids.domain.com/", + "Audience": "domain_api" + } +} diff --git a/src/FrontOffice.BFF.sln b/src/FrontOffice.BFF.sln new file mode 100644 index 0000000..1856e19 --- /dev/null +++ b/src/FrontOffice.BFF.sln @@ -0,0 +1,39 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.31903.59 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{4C09820E-CA4E-4261-AA24-79DF2143BF48}") = "FrontOffice.BFF.Domain", "FrontOffice.BFF.Domain\FrontOffice.BFF.Domain.csproj", "{7E733B83-275C-4639-AA10-4A59B681B904}" +EndProject +Project("{4C09820E-CA4E-4261-AA24-79DF2143BF48}") = "FrontOffice.BFF.Application", "FrontOffice.BFF.Application\FrontOffice.BFF.Application.csproj", "{56107B61-262D-413A-A9B6-4F3730220415}" +EndProject +Project("{4C09820E-CA4E-4261-AA24-79DF2143BF48}") = "FrontOffice.BFF.Infrastructure", "FrontOffice.BFF.Infrastructure\FrontOffice.BFF.Infrastructure.csproj", "{41CA2D15-9289-4A24-A519-EFB1F7CEB633}" +EndProject +Project("{4C09820E-CA4E-4261-AA24-79DF2143BF48}") = "FrontOffice.BFF.WebApi", "FrontOffice.BFF.WebApi\FrontOffice.BFF.WebApi.csproj", "{1E7A5065-4B24-4B12-A0F2-7B0564989C95}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {7E733B83-275C-4639-AA10-4A59B681B904}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7E733B83-275C-4639-AA10-4A59B681B904}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7E733B83-275C-4639-AA10-4A59B681B904}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7E733B83-275C-4639-AA10-4A59B681B904}.Release|Any CPU.Build.0 = Release|Any CPU + {56107B61-262D-413A-A9B6-4F3730220415}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {56107B61-262D-413A-A9B6-4F3730220415}.Debug|Any CPU.Build.0 = Debug|Any CPU + {56107B61-262D-413A-A9B6-4F3730220415}.Release|Any CPU.ActiveCfg = Release|Any CPU + {56107B61-262D-413A-A9B6-4F3730220415}.Release|Any CPU.Build.0 = Release|Any CPU + {41CA2D15-9289-4A24-A519-EFB1F7CEB633}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {41CA2D15-9289-4A24-A519-EFB1F7CEB633}.Debug|Any CPU.Build.0 = Debug|Any CPU + {41CA2D15-9289-4A24-A519-EFB1F7CEB633}.Release|Any CPU.ActiveCfg = Release|Any CPU + {41CA2D15-9289-4A24-A519-EFB1F7CEB633}.Release|Any CPU.Build.0 = Release|Any CPU + {1E7A5065-4B24-4B12-A0F2-7B0564989C95}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1E7A5065-4B24-4B12-A0F2-7B0564989C95}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1E7A5065-4B24-4B12-A0F2-7B0564989C95}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1E7A5065-4B24-4B12-A0F2-7B0564989C95}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/src/Protobufs/FrontOffice.BFF.Package.Protobuf/ConfigureServices.cs b/src/Protobufs/FrontOffice.BFF.Package.Protobuf/ConfigureServices.cs new file mode 100644 index 0000000..9b39014 --- /dev/null +++ b/src/Protobufs/FrontOffice.BFF.Package.Protobuf/ConfigureServices.cs @@ -0,0 +1,14 @@ +using FluentValidation; +using System.Reflection; + +namespace Microsoft.Extensions.DependencyInjection; + +public static class ConfigureServices +{ + public static IServiceCollection AddPackageProtobufServices(this IServiceCollection services) + { + services.AddValidatorsFromAssembly(Assembly.GetExecutingAssembly()); + return services; + } +} + diff --git a/src/Protobufs/FrontOffice.BFF.Package.Protobuf/FrontOffice.BFF.Package.Protobuf.csproj b/src/Protobufs/FrontOffice.BFF.Package.Protobuf/FrontOffice.BFF.Package.Protobuf.csproj new file mode 100644 index 0000000..0a42626 --- /dev/null +++ b/src/Protobufs/FrontOffice.BFF.Package.Protobuf/FrontOffice.BFF.Package.Protobuf.csproj @@ -0,0 +1,27 @@ + + + + net7.0 + enable + enable + 1.0.0 + None + False + False + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + + diff --git a/src/Protobufs/FrontOffice.BFF.Package.Protobuf/Protos/google/api/annotations.proto b/src/Protobufs/FrontOffice.BFF.Package.Protobuf/Protos/google/api/annotations.proto new file mode 100644 index 0000000..85c361b --- /dev/null +++ b/src/Protobufs/FrontOffice.BFF.Package.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/Protobufs/FrontOffice.BFF.Package.Protobuf/Protos/google/api/http.proto b/src/Protobufs/FrontOffice.BFF.Package.Protobuf/Protos/google/api/http.proto new file mode 100644 index 0000000..b8426ba --- /dev/null +++ b/src/Protobufs/FrontOffice.BFF.Package.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/Protobufs/FrontOffice.BFF.Package.Protobuf/Protos/package.proto b/src/Protobufs/FrontOffice.BFF.Package.Protobuf/Protos/package.proto new file mode 100644 index 0000000..7d55c1c --- /dev/null +++ b/src/Protobufs/FrontOffice.BFF.Package.Protobuf/Protos/package.proto @@ -0,0 +1,135 @@ +syntax = "proto3"; + +package package; + +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 = "FrontOffice.BFF.Package.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 +{ + 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 +{ + 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; +} + +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/Protobufs/FrontOffice.BFF.Package.Protobuf/Validator/CreateNewPackageRequestValidator.cs b/src/Protobufs/FrontOffice.BFF.Package.Protobuf/Validator/CreateNewPackageRequestValidator.cs new file mode 100644 index 0000000..48ec793 --- /dev/null +++ b/src/Protobufs/FrontOffice.BFF.Package.Protobuf/Validator/CreateNewPackageRequestValidator.cs @@ -0,0 +1,25 @@ +using FluentValidation; +using FrontOffice.BFF.Package.Protobuf.Protos.Package; +namespace FrontOffice.BFF.Package.Protobuf.Validator; + +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/Protobufs/FrontOffice.BFF.Package.Protobuf/Validator/DeletePackageRequestValidator.cs b/src/Protobufs/FrontOffice.BFF.Package.Protobuf/Validator/DeletePackageRequestValidator.cs new file mode 100644 index 0000000..aec8c30 --- /dev/null +++ b/src/Protobufs/FrontOffice.BFF.Package.Protobuf/Validator/DeletePackageRequestValidator.cs @@ -0,0 +1,19 @@ +using FluentValidation; +using FrontOffice.BFF.Package.Protobuf.Protos.Package; +namespace FrontOffice.BFF.Package.Protobuf.Validator; + +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/Protobufs/FrontOffice.BFF.Package.Protobuf/Validator/GetAllPackageByFilterRequestValidator.cs b/src/Protobufs/FrontOffice.BFF.Package.Protobuf/Validator/GetAllPackageByFilterRequestValidator.cs new file mode 100644 index 0000000..e98ccc2 --- /dev/null +++ b/src/Protobufs/FrontOffice.BFF.Package.Protobuf/Validator/GetAllPackageByFilterRequestValidator.cs @@ -0,0 +1,17 @@ +using FluentValidation; +using FrontOffice.BFF.Package.Protobuf.Protos.Package; +namespace FrontOffice.BFF.Package.Protobuf.Validator; + +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/Protobufs/FrontOffice.BFF.Package.Protobuf/Validator/GetPackageRequestValidator.cs b/src/Protobufs/FrontOffice.BFF.Package.Protobuf/Validator/GetPackageRequestValidator.cs new file mode 100644 index 0000000..72ebeae --- /dev/null +++ b/src/Protobufs/FrontOffice.BFF.Package.Protobuf/Validator/GetPackageRequestValidator.cs @@ -0,0 +1,19 @@ +using FluentValidation; +using FrontOffice.BFF.Package.Protobuf.Protos.Package; +namespace FrontOffice.BFF.Package.Protobuf.Validator; + +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/Protobufs/FrontOffice.BFF.Package.Protobuf/Validator/UpdatePackageRequestValidator.cs b/src/Protobufs/FrontOffice.BFF.Package.Protobuf/Validator/UpdatePackageRequestValidator.cs new file mode 100644 index 0000000..9041ae9 --- /dev/null +++ b/src/Protobufs/FrontOffice.BFF.Package.Protobuf/Validator/UpdatePackageRequestValidator.cs @@ -0,0 +1,27 @@ +using FluentValidation; +using FrontOffice.BFF.Package.Protobuf.Protos.Package; +namespace FrontOffice.BFF.Package.Protobuf.Validator; + +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/Protobufs/FrontOffice.BFF.Role.Protobuf/ConfigureServices.cs b/src/Protobufs/FrontOffice.BFF.Role.Protobuf/ConfigureServices.cs new file mode 100644 index 0000000..7c7ff2a --- /dev/null +++ b/src/Protobufs/FrontOffice.BFF.Role.Protobuf/ConfigureServices.cs @@ -0,0 +1,14 @@ +using FluentValidation; +using System.Reflection; + +namespace Microsoft.Extensions.DependencyInjection; + +public static class ConfigureServices +{ + public static IServiceCollection AddRoleProtobufServices(this IServiceCollection services) + { + services.AddValidatorsFromAssembly(Assembly.GetExecutingAssembly()); + return services; + } +} + diff --git a/src/Protobufs/FrontOffice.BFF.Role.Protobuf/FrontOffice.BFF.Role.Protobuf.csproj b/src/Protobufs/FrontOffice.BFF.Role.Protobuf/FrontOffice.BFF.Role.Protobuf.csproj new file mode 100644 index 0000000..e21b5c2 --- /dev/null +++ b/src/Protobufs/FrontOffice.BFF.Role.Protobuf/FrontOffice.BFF.Role.Protobuf.csproj @@ -0,0 +1,27 @@ + + + + net7.0 + enable + enable + 1.0.0 + None + False + False + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + + diff --git a/src/Protobufs/FrontOffice.BFF.Role.Protobuf/Protos/google/api/annotations.proto b/src/Protobufs/FrontOffice.BFF.Role.Protobuf/Protos/google/api/annotations.proto new file mode 100644 index 0000000..85c361b --- /dev/null +++ b/src/Protobufs/FrontOffice.BFF.Role.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/Protobufs/FrontOffice.BFF.Role.Protobuf/Protos/google/api/http.proto b/src/Protobufs/FrontOffice.BFF.Role.Protobuf/Protos/google/api/http.proto new file mode 100644 index 0000000..b8426ba --- /dev/null +++ b/src/Protobufs/FrontOffice.BFF.Role.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/Protobufs/FrontOffice.BFF.Role.Protobuf/Protos/role.proto b/src/Protobufs/FrontOffice.BFF.Role.Protobuf/Protos/role.proto new file mode 100644 index 0000000..03902dd --- /dev/null +++ b/src/Protobufs/FrontOffice.BFF.Role.Protobuf/Protos/role.proto @@ -0,0 +1,125 @@ +syntax = "proto3"; + +package role; + +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 = "FrontOffice.BFF.Role.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 +{ + 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 +{ + MetaData meta_data = 1; + repeated GetAllRoleByFilterResponseModel models = 2; +} +message GetAllRoleByFilterResponseModel +{ + int64 id = 1; + string name = 2; + string title = 3; +} + +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/Protobufs/FrontOffice.BFF.Role.Protobuf/Validator/CreateNewRoleRequestValidator.cs b/src/Protobufs/FrontOffice.BFF.Role.Protobuf/Validator/CreateNewRoleRequestValidator.cs new file mode 100644 index 0000000..33ffbb0 --- /dev/null +++ b/src/Protobufs/FrontOffice.BFF.Role.Protobuf/Validator/CreateNewRoleRequestValidator.cs @@ -0,0 +1,21 @@ +using FluentValidation; +using FrontOffice.BFF.Role.Protobuf.Protos.Role; +namespace FrontOffice.BFF.Role.Protobuf.Validator; + +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/Protobufs/FrontOffice.BFF.Role.Protobuf/Validator/DeleteRoleRequestValidator.cs b/src/Protobufs/FrontOffice.BFF.Role.Protobuf/Validator/DeleteRoleRequestValidator.cs new file mode 100644 index 0000000..921a14b --- /dev/null +++ b/src/Protobufs/FrontOffice.BFF.Role.Protobuf/Validator/DeleteRoleRequestValidator.cs @@ -0,0 +1,19 @@ +using FluentValidation; +using FrontOffice.BFF.Role.Protobuf.Protos.Role; +namespace FrontOffice.BFF.Role.Protobuf.Validator; + +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/Protobufs/FrontOffice.BFF.Role.Protobuf/Validator/GetAllRoleByFilterRequestValidator.cs b/src/Protobufs/FrontOffice.BFF.Role.Protobuf/Validator/GetAllRoleByFilterRequestValidator.cs new file mode 100644 index 0000000..247fb47 --- /dev/null +++ b/src/Protobufs/FrontOffice.BFF.Role.Protobuf/Validator/GetAllRoleByFilterRequestValidator.cs @@ -0,0 +1,17 @@ +using FluentValidation; +using FrontOffice.BFF.Role.Protobuf.Protos.Role; +namespace FrontOffice.BFF.Role.Protobuf.Validator; + +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/Protobufs/FrontOffice.BFF.Role.Protobuf/Validator/GetRoleRequestValidator.cs b/src/Protobufs/FrontOffice.BFF.Role.Protobuf/Validator/GetRoleRequestValidator.cs new file mode 100644 index 0000000..47c5386 --- /dev/null +++ b/src/Protobufs/FrontOffice.BFF.Role.Protobuf/Validator/GetRoleRequestValidator.cs @@ -0,0 +1,19 @@ +using FluentValidation; +using FrontOffice.BFF.Role.Protobuf.Protos.Role; +namespace FrontOffice.BFF.Role.Protobuf.Validator; + +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/Protobufs/FrontOffice.BFF.Role.Protobuf/Validator/UpdateRoleRequestValidator.cs b/src/Protobufs/FrontOffice.BFF.Role.Protobuf/Validator/UpdateRoleRequestValidator.cs new file mode 100644 index 0000000..12f2537 --- /dev/null +++ b/src/Protobufs/FrontOffice.BFF.Role.Protobuf/Validator/UpdateRoleRequestValidator.cs @@ -0,0 +1,23 @@ +using FluentValidation; +using FrontOffice.BFF.Role.Protobuf.Protos.Role; +namespace FrontOffice.BFF.Role.Protobuf.Validator; + +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/Protobufs/FrontOffice.BFF.User.Protobuf/ConfigureServices.cs b/src/Protobufs/FrontOffice.BFF.User.Protobuf/ConfigureServices.cs new file mode 100644 index 0000000..c39ed80 --- /dev/null +++ b/src/Protobufs/FrontOffice.BFF.User.Protobuf/ConfigureServices.cs @@ -0,0 +1,14 @@ +using FluentValidation; +using System.Reflection; + +namespace Microsoft.Extensions.DependencyInjection; + +public static class ConfigureServices +{ + public static IServiceCollection AddUserProtobufServices(this IServiceCollection services) + { + services.AddValidatorsFromAssembly(Assembly.GetExecutingAssembly()); + return services; + } +} + diff --git a/src/Protobufs/FrontOffice.BFF.User.Protobuf/FrontOffice.BFF.User.Protobuf.csproj b/src/Protobufs/FrontOffice.BFF.User.Protobuf/FrontOffice.BFF.User.Protobuf.csproj new file mode 100644 index 0000000..40788ee --- /dev/null +++ b/src/Protobufs/FrontOffice.BFF.User.Protobuf/FrontOffice.BFF.User.Protobuf.csproj @@ -0,0 +1,27 @@ + + + + net7.0 + enable + enable + 1.0.0 + None + False + False + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + + diff --git a/src/Protobufs/FrontOffice.BFF.User.Protobuf/Protos/google/api/annotations.proto b/src/Protobufs/FrontOffice.BFF.User.Protobuf/Protos/google/api/annotations.proto new file mode 100644 index 0000000..85c361b --- /dev/null +++ b/src/Protobufs/FrontOffice.BFF.User.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/Protobufs/FrontOffice.BFF.User.Protobuf/Protos/google/api/http.proto b/src/Protobufs/FrontOffice.BFF.User.Protobuf/Protos/google/api/http.proto new file mode 100644 index 0000000..b8426ba --- /dev/null +++ b/src/Protobufs/FrontOffice.BFF.User.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/Protobufs/FrontOffice.BFF.User.Protobuf/Protos/user.proto b/src/Protobufs/FrontOffice.BFF.User.Protobuf/Protos/user.proto new file mode 100644 index 0000000..ceb1335 --- /dev/null +++ b/src/Protobufs/FrontOffice.BFF.User.Protobuf/Protos/user.proto @@ -0,0 +1,145 @@ +syntax = "proto3"; + +package user; + +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 = "FrontOffice.BFF.User.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 +{ + 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 +{ + 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; +} + +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/Protobufs/FrontOffice.BFF.User.Protobuf/Validator/CreateNewUserRequestValidator.cs b/src/Protobufs/FrontOffice.BFF.User.Protobuf/Validator/CreateNewUserRequestValidator.cs new file mode 100644 index 0000000..c1f0fff --- /dev/null +++ b/src/Protobufs/FrontOffice.BFF.User.Protobuf/Validator/CreateNewUserRequestValidator.cs @@ -0,0 +1,19 @@ +using FluentValidation; +using FrontOffice.BFF.User.Protobuf.Protos.User; +namespace FrontOffice.BFF.User.Protobuf.Validator; + +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/Protobufs/FrontOffice.BFF.User.Protobuf/Validator/DeleteUserRequestValidator.cs b/src/Protobufs/FrontOffice.BFF.User.Protobuf/Validator/DeleteUserRequestValidator.cs new file mode 100644 index 0000000..341fb82 --- /dev/null +++ b/src/Protobufs/FrontOffice.BFF.User.Protobuf/Validator/DeleteUserRequestValidator.cs @@ -0,0 +1,19 @@ +using FluentValidation; +using FrontOffice.BFF.User.Protobuf.Protos.User; +namespace FrontOffice.BFF.User.Protobuf.Validator; + +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/Protobufs/FrontOffice.BFF.User.Protobuf/Validator/GetAllUserByFilterRequestValidator.cs b/src/Protobufs/FrontOffice.BFF.User.Protobuf/Validator/GetAllUserByFilterRequestValidator.cs new file mode 100644 index 0000000..d6c5dc7 --- /dev/null +++ b/src/Protobufs/FrontOffice.BFF.User.Protobuf/Validator/GetAllUserByFilterRequestValidator.cs @@ -0,0 +1,17 @@ +using FluentValidation; +using FrontOffice.BFF.User.Protobuf.Protos.User; +namespace FrontOffice.BFF.User.Protobuf.Validator; + +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/Protobufs/FrontOffice.BFF.User.Protobuf/Validator/GetUserRequestValidator.cs b/src/Protobufs/FrontOffice.BFF.User.Protobuf/Validator/GetUserRequestValidator.cs new file mode 100644 index 0000000..81d3ca8 --- /dev/null +++ b/src/Protobufs/FrontOffice.BFF.User.Protobuf/Validator/GetUserRequestValidator.cs @@ -0,0 +1,19 @@ +using FluentValidation; +using FrontOffice.BFF.User.Protobuf.Protos.User; +namespace FrontOffice.BFF.User.Protobuf.Validator; + +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/Protobufs/FrontOffice.BFF.User.Protobuf/Validator/UpdateUserRequestValidator.cs b/src/Protobufs/FrontOffice.BFF.User.Protobuf/Validator/UpdateUserRequestValidator.cs new file mode 100644 index 0000000..9ae5eba --- /dev/null +++ b/src/Protobufs/FrontOffice.BFF.User.Protobuf/Validator/UpdateUserRequestValidator.cs @@ -0,0 +1,21 @@ +using FluentValidation; +using FrontOffice.BFF.User.Protobuf.Protos.User; +namespace FrontOffice.BFF.User.Protobuf.Validator; + +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/Protobufs/FrontOffice.BFF.UserAddress.Protobuf/ConfigureServices.cs b/src/Protobufs/FrontOffice.BFF.UserAddress.Protobuf/ConfigureServices.cs new file mode 100644 index 0000000..eee4faf --- /dev/null +++ b/src/Protobufs/FrontOffice.BFF.UserAddress.Protobuf/ConfigureServices.cs @@ -0,0 +1,14 @@ +using FluentValidation; +using System.Reflection; + +namespace Microsoft.Extensions.DependencyInjection; + +public static class ConfigureServices +{ + public static IServiceCollection AddUserAddressProtobufServices(this IServiceCollection services) + { + services.AddValidatorsFromAssembly(Assembly.GetExecutingAssembly()); + return services; + } +} + diff --git a/src/Protobufs/FrontOffice.BFF.UserAddress.Protobuf/FrontOffice.BFF.UserAddress.Protobuf.csproj b/src/Protobufs/FrontOffice.BFF.UserAddress.Protobuf/FrontOffice.BFF.UserAddress.Protobuf.csproj new file mode 100644 index 0000000..9b7dc6b --- /dev/null +++ b/src/Protobufs/FrontOffice.BFF.UserAddress.Protobuf/FrontOffice.BFF.UserAddress.Protobuf.csproj @@ -0,0 +1,27 @@ + + + + net7.0 + enable + enable + 1.0.0 + None + False + False + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + + diff --git a/src/Protobufs/FrontOffice.BFF.UserAddress.Protobuf/Protos/google/api/annotations.proto b/src/Protobufs/FrontOffice.BFF.UserAddress.Protobuf/Protos/google/api/annotations.proto new file mode 100644 index 0000000..85c361b --- /dev/null +++ b/src/Protobufs/FrontOffice.BFF.UserAddress.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/Protobufs/FrontOffice.BFF.UserAddress.Protobuf/Protos/google/api/http.proto b/src/Protobufs/FrontOffice.BFF.UserAddress.Protobuf/Protos/google/api/http.proto new file mode 100644 index 0000000..b8426ba --- /dev/null +++ b/src/Protobufs/FrontOffice.BFF.UserAddress.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/Protobufs/FrontOffice.BFF.UserAddress.Protobuf/Protos/useraddress.proto b/src/Protobufs/FrontOffice.BFF.UserAddress.Protobuf/Protos/useraddress.proto new file mode 100644 index 0000000..a2e6531 --- /dev/null +++ b/src/Protobufs/FrontOffice.BFF.UserAddress.Protobuf/Protos/useraddress.proto @@ -0,0 +1,145 @@ +syntax = "proto3"; + +package useraddress; + +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 = "FrontOffice.BFF.UserAddress.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 +{ + 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 +{ + 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; +} + +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/Protobufs/FrontOffice.BFF.UserAddress.Protobuf/Validator/CreateNewUserAddressRequestValidator.cs b/src/Protobufs/FrontOffice.BFF.UserAddress.Protobuf/Validator/CreateNewUserAddressRequestValidator.cs new file mode 100644 index 0000000..5ff7dff --- /dev/null +++ b/src/Protobufs/FrontOffice.BFF.UserAddress.Protobuf/Validator/CreateNewUserAddressRequestValidator.cs @@ -0,0 +1,29 @@ +using FluentValidation; +using FrontOffice.BFF.UserAddress.Protobuf.Protos.UserAddress; +namespace FrontOffice.BFF.UserAddress.Protobuf.Validator; + +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/Protobufs/FrontOffice.BFF.UserAddress.Protobuf/Validator/DeleteUserAddressRequestValidator.cs b/src/Protobufs/FrontOffice.BFF.UserAddress.Protobuf/Validator/DeleteUserAddressRequestValidator.cs new file mode 100644 index 0000000..5805034 --- /dev/null +++ b/src/Protobufs/FrontOffice.BFF.UserAddress.Protobuf/Validator/DeleteUserAddressRequestValidator.cs @@ -0,0 +1,19 @@ +using FluentValidation; +using FrontOffice.BFF.UserAddress.Protobuf.Protos.UserAddress; +namespace FrontOffice.BFF.UserAddress.Protobuf.Validator; + +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/Protobufs/FrontOffice.BFF.UserAddress.Protobuf/Validator/GetAllUserAddressByFilterRequestValidator.cs b/src/Protobufs/FrontOffice.BFF.UserAddress.Protobuf/Validator/GetAllUserAddressByFilterRequestValidator.cs new file mode 100644 index 0000000..c21d01e --- /dev/null +++ b/src/Protobufs/FrontOffice.BFF.UserAddress.Protobuf/Validator/GetAllUserAddressByFilterRequestValidator.cs @@ -0,0 +1,17 @@ +using FluentValidation; +using FrontOffice.BFF.UserAddress.Protobuf.Protos.UserAddress; +namespace FrontOffice.BFF.UserAddress.Protobuf.Validator; + +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/Protobufs/FrontOffice.BFF.UserAddress.Protobuf/Validator/GetUserAddressRequestValidator.cs b/src/Protobufs/FrontOffice.BFF.UserAddress.Protobuf/Validator/GetUserAddressRequestValidator.cs new file mode 100644 index 0000000..ad371af --- /dev/null +++ b/src/Protobufs/FrontOffice.BFF.UserAddress.Protobuf/Validator/GetUserAddressRequestValidator.cs @@ -0,0 +1,19 @@ +using FluentValidation; +using FrontOffice.BFF.UserAddress.Protobuf.Protos.UserAddress; +namespace FrontOffice.BFF.UserAddress.Protobuf.Validator; + +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/Protobufs/FrontOffice.BFF.UserAddress.Protobuf/Validator/UpdateUserAddressRequestValidator.cs b/src/Protobufs/FrontOffice.BFF.UserAddress.Protobuf/Validator/UpdateUserAddressRequestValidator.cs new file mode 100644 index 0000000..9487fe0 --- /dev/null +++ b/src/Protobufs/FrontOffice.BFF.UserAddress.Protobuf/Validator/UpdateUserAddressRequestValidator.cs @@ -0,0 +1,31 @@ +using FluentValidation; +using FrontOffice.BFF.UserAddress.Protobuf.Protos.UserAddress; +namespace FrontOffice.BFF.UserAddress.Protobuf.Validator; + +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/Protobufs/FrontOffice.BFF.UserOrder.Protobuf/ConfigureServices.cs b/src/Protobufs/FrontOffice.BFF.UserOrder.Protobuf/ConfigureServices.cs new file mode 100644 index 0000000..976b460 --- /dev/null +++ b/src/Protobufs/FrontOffice.BFF.UserOrder.Protobuf/ConfigureServices.cs @@ -0,0 +1,14 @@ +using FluentValidation; +using System.Reflection; + +namespace Microsoft.Extensions.DependencyInjection; + +public static class ConfigureServices +{ + public static IServiceCollection AddUserOrderProtobufServices(this IServiceCollection services) + { + services.AddValidatorsFromAssembly(Assembly.GetExecutingAssembly()); + return services; + } +} + diff --git a/src/Protobufs/FrontOffice.BFF.UserOrder.Protobuf/FrontOffice.BFF.UserOrder.Protobuf.csproj b/src/Protobufs/FrontOffice.BFF.UserOrder.Protobuf/FrontOffice.BFF.UserOrder.Protobuf.csproj new file mode 100644 index 0000000..6e1b96c --- /dev/null +++ b/src/Protobufs/FrontOffice.BFF.UserOrder.Protobuf/FrontOffice.BFF.UserOrder.Protobuf.csproj @@ -0,0 +1,27 @@ + + + + net7.0 + enable + enable + 1.0.0 + None + False + False + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + + diff --git a/src/Protobufs/FrontOffice.BFF.UserOrder.Protobuf/Protos/google/api/annotations.proto b/src/Protobufs/FrontOffice.BFF.UserOrder.Protobuf/Protos/google/api/annotations.proto new file mode 100644 index 0000000..85c361b --- /dev/null +++ b/src/Protobufs/FrontOffice.BFF.UserOrder.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/Protobufs/FrontOffice.BFF.UserOrder.Protobuf/Protos/google/api/http.proto b/src/Protobufs/FrontOffice.BFF.UserOrder.Protobuf/Protos/google/api/http.proto new file mode 100644 index 0000000..b8426ba --- /dev/null +++ b/src/Protobufs/FrontOffice.BFF.UserOrder.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/Protobufs/FrontOffice.BFF.UserOrder.Protobuf/Protos/userorder.proto b/src/Protobufs/FrontOffice.BFF.UserOrder.Protobuf/Protos/userorder.proto new file mode 100644 index 0000000..d2601a4 --- /dev/null +++ b/src/Protobufs/FrontOffice.BFF.UserOrder.Protobuf/Protos/userorder.proto @@ -0,0 +1,145 @@ +syntax = "proto3"; + +package userorder; + +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 = "FrontOffice.BFF.UserOrder.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 +{ + 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 +{ + 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; +} + +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/Protobufs/FrontOffice.BFF.UserOrder.Protobuf/Validator/CreateNewUserOrderRequestValidator.cs b/src/Protobufs/FrontOffice.BFF.UserOrder.Protobuf/Validator/CreateNewUserOrderRequestValidator.cs new file mode 100644 index 0000000..4d15836 --- /dev/null +++ b/src/Protobufs/FrontOffice.BFF.UserOrder.Protobuf/Validator/CreateNewUserOrderRequestValidator.cs @@ -0,0 +1,25 @@ +using FluentValidation; +using FrontOffice.BFF.UserOrder.Protobuf.Protos.UserOrder; +namespace FrontOffice.BFF.UserOrder.Protobuf.Validator; + +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/Protobufs/FrontOffice.BFF.UserOrder.Protobuf/Validator/DeleteUserOrderRequestValidator.cs b/src/Protobufs/FrontOffice.BFF.UserOrder.Protobuf/Validator/DeleteUserOrderRequestValidator.cs new file mode 100644 index 0000000..96fb2d5 --- /dev/null +++ b/src/Protobufs/FrontOffice.BFF.UserOrder.Protobuf/Validator/DeleteUserOrderRequestValidator.cs @@ -0,0 +1,19 @@ +using FluentValidation; +using FrontOffice.BFF.UserOrder.Protobuf.Protos.UserOrder; +namespace FrontOffice.BFF.UserOrder.Protobuf.Validator; + +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/Protobufs/FrontOffice.BFF.UserOrder.Protobuf/Validator/GetAllUserOrderByFilterRequestValidator.cs b/src/Protobufs/FrontOffice.BFF.UserOrder.Protobuf/Validator/GetAllUserOrderByFilterRequestValidator.cs new file mode 100644 index 0000000..1e6013b --- /dev/null +++ b/src/Protobufs/FrontOffice.BFF.UserOrder.Protobuf/Validator/GetAllUserOrderByFilterRequestValidator.cs @@ -0,0 +1,17 @@ +using FluentValidation; +using FrontOffice.BFF.UserOrder.Protobuf.Protos.UserOrder; +namespace FrontOffice.BFF.UserOrder.Protobuf.Validator; + +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/Protobufs/FrontOffice.BFF.UserOrder.Protobuf/Validator/GetUserOrderRequestValidator.cs b/src/Protobufs/FrontOffice.BFF.UserOrder.Protobuf/Validator/GetUserOrderRequestValidator.cs new file mode 100644 index 0000000..90764e0 --- /dev/null +++ b/src/Protobufs/FrontOffice.BFF.UserOrder.Protobuf/Validator/GetUserOrderRequestValidator.cs @@ -0,0 +1,19 @@ +using FluentValidation; +using FrontOffice.BFF.UserOrder.Protobuf.Protos.UserOrder; +namespace FrontOffice.BFF.UserOrder.Protobuf.Validator; + +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/Protobufs/FrontOffice.BFF.UserOrder.Protobuf/Validator/UpdateUserOrderRequestValidator.cs b/src/Protobufs/FrontOffice.BFF.UserOrder.Protobuf/Validator/UpdateUserOrderRequestValidator.cs new file mode 100644 index 0000000..63541ea --- /dev/null +++ b/src/Protobufs/FrontOffice.BFF.UserOrder.Protobuf/Validator/UpdateUserOrderRequestValidator.cs @@ -0,0 +1,27 @@ +using FluentValidation; +using FrontOffice.BFF.UserOrder.Protobuf.Protos.UserOrder; +namespace FrontOffice.BFF.UserOrder.Protobuf.Validator; + +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/Protobufs/FrontOffice.BFF.UserRole.Protobuf/ConfigureServices.cs b/src/Protobufs/FrontOffice.BFF.UserRole.Protobuf/ConfigureServices.cs new file mode 100644 index 0000000..5331f03 --- /dev/null +++ b/src/Protobufs/FrontOffice.BFF.UserRole.Protobuf/ConfigureServices.cs @@ -0,0 +1,14 @@ +using FluentValidation; +using System.Reflection; + +namespace Microsoft.Extensions.DependencyInjection; + +public static class ConfigureServices +{ + public static IServiceCollection AddUserRoleProtobufServices(this IServiceCollection services) + { + services.AddValidatorsFromAssembly(Assembly.GetExecutingAssembly()); + return services; + } +} + diff --git a/src/Protobufs/FrontOffice.BFF.UserRole.Protobuf/FrontOffice.BFF.UserRole.Protobuf.csproj b/src/Protobufs/FrontOffice.BFF.UserRole.Protobuf/FrontOffice.BFF.UserRole.Protobuf.csproj new file mode 100644 index 0000000..4504d13 --- /dev/null +++ b/src/Protobufs/FrontOffice.BFF.UserRole.Protobuf/FrontOffice.BFF.UserRole.Protobuf.csproj @@ -0,0 +1,27 @@ + + + + net7.0 + enable + enable + 1.0.0 + None + False + False + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + + diff --git a/src/Protobufs/FrontOffice.BFF.UserRole.Protobuf/Protos/google/api/annotations.proto b/src/Protobufs/FrontOffice.BFF.UserRole.Protobuf/Protos/google/api/annotations.proto new file mode 100644 index 0000000..85c361b --- /dev/null +++ b/src/Protobufs/FrontOffice.BFF.UserRole.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/Protobufs/FrontOffice.BFF.UserRole.Protobuf/Protos/google/api/http.proto b/src/Protobufs/FrontOffice.BFF.UserRole.Protobuf/Protos/google/api/http.proto new file mode 100644 index 0000000..b8426ba --- /dev/null +++ b/src/Protobufs/FrontOffice.BFF.UserRole.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/Protobufs/FrontOffice.BFF.UserRole.Protobuf/Protos/userrole.proto b/src/Protobufs/FrontOffice.BFF.UserRole.Protobuf/Protos/userrole.proto new file mode 100644 index 0000000..bbf6400 --- /dev/null +++ b/src/Protobufs/FrontOffice.BFF.UserRole.Protobuf/Protos/userrole.proto @@ -0,0 +1,125 @@ +syntax = "proto3"; + +package userrole; + +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 = "FrontOffice.BFF.UserRole.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 +{ + 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 +{ + MetaData meta_data = 1; + repeated GetAllUserRoleByFilterResponseModel models = 2; +} +message GetAllUserRoleByFilterResponseModel +{ + int64 id = 1; + int64 role_id = 2; + int64 user_id = 3; +} + +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/Protobufs/FrontOffice.BFF.UserRole.Protobuf/Validator/CreateNewUserRoleRequestValidator.cs b/src/Protobufs/FrontOffice.BFF.UserRole.Protobuf/Validator/CreateNewUserRoleRequestValidator.cs new file mode 100644 index 0000000..5535bf3 --- /dev/null +++ b/src/Protobufs/FrontOffice.BFF.UserRole.Protobuf/Validator/CreateNewUserRoleRequestValidator.cs @@ -0,0 +1,21 @@ +using FluentValidation; +using FrontOffice.BFF.UserRole.Protobuf.Protos.UserRole; +namespace FrontOffice.BFF.UserRole.Protobuf.Validator; + +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/Protobufs/FrontOffice.BFF.UserRole.Protobuf/Validator/DeleteUserRoleRequestValidator.cs b/src/Protobufs/FrontOffice.BFF.UserRole.Protobuf/Validator/DeleteUserRoleRequestValidator.cs new file mode 100644 index 0000000..b7fddb5 --- /dev/null +++ b/src/Protobufs/FrontOffice.BFF.UserRole.Protobuf/Validator/DeleteUserRoleRequestValidator.cs @@ -0,0 +1,19 @@ +using FluentValidation; +using FrontOffice.BFF.UserRole.Protobuf.Protos.UserRole; +namespace FrontOffice.BFF.UserRole.Protobuf.Validator; + +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/Protobufs/FrontOffice.BFF.UserRole.Protobuf/Validator/GetAllUserRoleByFilterRequestValidator.cs b/src/Protobufs/FrontOffice.BFF.UserRole.Protobuf/Validator/GetAllUserRoleByFilterRequestValidator.cs new file mode 100644 index 0000000..0fc1ab2 --- /dev/null +++ b/src/Protobufs/FrontOffice.BFF.UserRole.Protobuf/Validator/GetAllUserRoleByFilterRequestValidator.cs @@ -0,0 +1,17 @@ +using FluentValidation; +using FrontOffice.BFF.UserRole.Protobuf.Protos.UserRole; +namespace FrontOffice.BFF.UserRole.Protobuf.Validator; + +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/Protobufs/FrontOffice.BFF.UserRole.Protobuf/Validator/GetUserRoleRequestValidator.cs b/src/Protobufs/FrontOffice.BFF.UserRole.Protobuf/Validator/GetUserRoleRequestValidator.cs new file mode 100644 index 0000000..8fee00a --- /dev/null +++ b/src/Protobufs/FrontOffice.BFF.UserRole.Protobuf/Validator/GetUserRoleRequestValidator.cs @@ -0,0 +1,19 @@ +using FluentValidation; +using FrontOffice.BFF.UserRole.Protobuf.Protos.UserRole; +namespace FrontOffice.BFF.UserRole.Protobuf.Validator; + +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/Protobufs/FrontOffice.BFF.UserRole.Protobuf/Validator/UpdateUserRoleRequestValidator.cs b/src/Protobufs/FrontOffice.BFF.UserRole.Protobuf/Validator/UpdateUserRoleRequestValidator.cs new file mode 100644 index 0000000..8c62116 --- /dev/null +++ b/src/Protobufs/FrontOffice.BFF.UserRole.Protobuf/Validator/UpdateUserRoleRequestValidator.cs @@ -0,0 +1,23 @@ +using FluentValidation; +using FrontOffice.BFF.UserRole.Protobuf.Protos.UserRole; +namespace FrontOffice.BFF.UserRole.Protobuf.Validator; + +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); + }; +}