From 042f93b910c851081a68ecfd0872b2be87c2bfbb Mon Sep 17 00:00:00 2001 From: hjanoti Date: Fri, 8 Dec 2023 11:23:27 +0530 Subject: [PATCH] Initial Checkin --- DealerSelectionAPI.sln | 98 ++ .../DealerSelection.Api.Models/AuthModel.cs | 14 + .../AuthValidateModel.cs | 14 + .../CustomerDealerInfoRequest.cs | 48 + .../DealerSelection.Api.Models.csproj | 28 + .../DealerSelectionJobStatus.cs | 10 + .../MulesoftResponse.cs | 21 + .../MulesoftToken.cs | 8 + .../DealerSelection.Api.Models/Procedure.cs | 15 + Source/DealerSelection.Api.Models/Response.cs | 31 + .../TokenValidProperty.cs | 10 + .../UnexpectedDataException.cs | 9 + .../WebEngageEvent.cs | 70 ++ Source/DealerSelection.Api/AssignDealerApi.cs | 190 +++ .../CommonUtil/AESEncryption.cs | 151 +++ .../CommonUtil/CustomConfig.cs | 132 +++ .../CommonUtil/GenerateRandomString.cs | 28 + .../CommonUtil/MuleSoftTokenGenerate.cs | 86 ++ .../DealerSelection.Api.csproj | 42 + .../InfoBipSmsServiceApi.cs | 143 +++ Source/DealerSelection.Api/JwtTokenApi.cs | 112 ++ Source/DealerSelection.Api/MulesoftApi.cs | 722 +++++++++++ .../DealerSelection.Api/MulesoftTokenApi.cs | 68 ++ Source/DealerSelection.Api/YellowAIApi.cs | 77 ++ .../CommonBaseClass/ExceptionBase.cs | 9 + .../CommonBaseClass/ExceptionFilterBase.cs | 92 ++ .../CommonBaseClass/StartupBase.cs | 235 ++++ .../WebApiConfigurationCfgBase.cs | 6 + .../Configuration/ConfigurationHelper.cs | 102 ++ .../Data/ConnectionHelper.cs | 36 + .../Data/Dapper/RepositoryBaseDapperAsync.cs | 25 + .../Data/Dapper/RepositoryBaseDapperSync.cs | 25 + .../Data/Dapper/TypeMapHelper.cs | 30 + .../Data/RepositoryBaseDIAsync.cs | 35 + .../Data/RepositoryBaseDISync.cs | 35 + .../Data/RepositoryDIBase.cs | 11 + .../DealerSelection.Common.csproj | 56 + .../Entity/FieldMapAttribute.cs | 24 + .../Exceptions/AuthorizationException.cs | 8 + .../Exceptions/DataNotFoundException.cs | 8 + .../Exceptions/DbConnectionException.cs | 15 + .../Exceptions/DuplicateException.cs | 8 + .../Exceptions/NullValueException.cs | 8 + .../Exceptions/PartialSuccessException.cs | 8 + .../Exceptions/ValidationException.cs | 8 + .../Helpers/SwaggerCfg.cs | 8 + .../Helpers/SwashbuckleSchemaHelper.cs | 38 + .../HttpClient/MyHttpClientHandler.cs | 21 + .../Interfaces/Data/IRepositoryDIAsync.cs | 9 + .../Interfaces/Data/IRepositoryDISync.cs | 9 + .../HttpClient/IHttpClientHandler.cs | 8 + .../DealerSelection.Common/Logging/ApiInfo.cs | 24 + .../Logging/AzureLogHelper.cs | 82 ++ .../Logging/HttpHeaderHelper.cs | 28 + .../Logging/LoggingMiddleware.cs | 127 ++ .../Logging/RequestInfo.cs | 42 + .../Logging/ResponseInfo.cs | 37 + .../SwaggerRootRoutingMiddleware.cs | 34 + .../Profiler/PerformanceProfiler.cs | 31 + .../Profiler/Profiler.cs | 19 + .../ApiRegistry.cs | 35 + ...DealerSelection.DependencyInjection.csproj | 29 + .../DependencyInjectionBootStrapper.cs | 11 + .../InfrastructureRegistry.cs | 37 + .../AssignDealer/IAssignDealerRepository.cs | 7 + .../AssignDealer/Repository.cs | 17 + .../CustomerDetail/CustomerInfoDto.cs | 26 + .../CustomerDetail/IRepository.cs | 13 + .../CustomerDetail/Repository.cs | 116 ++ .../DealerSelection.Api.Infrastructure.csproj | 37 + .../InfoBip/IRepository.cs | 6 + .../InfoBip/Repository.cs | 45 + .../Jwt/AuthValidateModelDto.cs | 14 + .../Jwt/IJwtRepository.cs | 9 + .../Jwt/JwtRepository.cs | 23 + .../Mulesoft/DealerDetailDto.cs | 26 + .../Mulesoft/IRepository.cs | 10 + .../Mulesoft/MulesoftCustomerInfoDto.cs | 46 + .../Mulesoft/Repository.cs | 134 +++ .../DealerSelection.Api.Interface.csproj | 27 + .../IAssignDealerApi.cs | 7 + .../IInfoBipSmsServiceApi.cs | 9 + .../DealerSelection.Interface/IJwtTokenApi.cs | 9 + .../DealerSelection.Interface/IMulesoftApi.cs | 20 + .../IMulesoftTokenApi.cs | 7 + .../DealerSelection.Interface/IYellowAIApi.cs | 10 + .../BikeResponse.cs | 14 + .../BookingConfirmationRequest.cs | 14 + .../CityResponse.cs | 9 + .../CustomerInfoMappingResponse.cs | 26 + .../CustomerInfoRequest.cs | 17 + .../DealerSelection.WebApi.Models.csproj | 20 + .../MulesoftResponse.cs | 34 + .../PaymentLinkResponse.cs | 7 + .../RegisterInterestSuccessfulResponse.cs | 16 + .../DealerSelection.WebApi.Models/Response.cs | 12 + .../ReviewPayCustomerInfoResponse.cs | 24 + .../StateResponse.cs | 8 + .../.config/dotnet-tools.json | 12 + .../App_Start/Mapper.cs | 36 + .../App_Start/Startup.cs | 21 + .../App_Start/WebApiConfig.cs | 26 + .../Controllers/DealerSelectionController.cs | 34 + .../Controllers/JWTAuthController.cs | 48 + .../Controllers/JWTAuthController.cs.bak | 43 + .../Controllers/MulesoftController.cs | 87 ++ .../Controllers/TestController.cs | 22 + .../Controllers/YellowController.cs | 34 + .../DealerSelection.WebApi.csproj | 171 +++ Source/DealerSelection.WebApi/Program.cs | 11 + .../Properties/launchSettings.json | 31 + .../appsettings-PreProd.Development.json | 8 + .../appsettings-PreProd.json | 134 +++ .../appsettings-Prod.Development.json | 8 + .../appsettings-Prod.json | 139 +++ .../appsettings.Development.json | 8 + .../DealerSelection.WebApi/appsettings.json | 78 ++ .../connectionString-PreProd.json | 8 + .../connectionString-Prod.json | 9 + .../connectionString.json | 8 + .../wwwroot/CustomContent/SwaggerHeader.css | 32 + .../wwwroot/CustomContent/logo.png | Bin 0 -> 965 bytes ...erSelection.WebApi.IntegrationTests.csproj | 31 + .../BookingConfirmationTest.cs | 90 ++ .../GivenRoot.cs | 0 Source/WebJobService/IService.cs | 15 + Source/WebJobService/Program.cs | 35 + Source/WebJobService/Service.cs | 160 +++ Source/WebJobService/WebJobService.csproj | 31 + Source/WebJobService/app.config | 10 + Source/WebJobService/connectionString.json | 8 + Web.config | 1052 +++++++++++++++++ 132 files changed, 6799 insertions(+) create mode 100644 DealerSelectionAPI.sln create mode 100644 Source/DealerSelection.Api.Models/AuthModel.cs create mode 100644 Source/DealerSelection.Api.Models/AuthValidateModel.cs create mode 100644 Source/DealerSelection.Api.Models/CustomerDealerInfoRequest.cs create mode 100644 Source/DealerSelection.Api.Models/DealerSelection.Api.Models.csproj create mode 100644 Source/DealerSelection.Api.Models/DealerSelectionJobStatus.cs create mode 100644 Source/DealerSelection.Api.Models/MulesoftResponse.cs create mode 100644 Source/DealerSelection.Api.Models/MulesoftToken.cs create mode 100644 Source/DealerSelection.Api.Models/Procedure.cs create mode 100644 Source/DealerSelection.Api.Models/Response.cs create mode 100644 Source/DealerSelection.Api.Models/TokenValidProperty.cs create mode 100644 Source/DealerSelection.Api.Models/UnexpectedDataException.cs create mode 100644 Source/DealerSelection.Api.Models/WebEngageEvent.cs create mode 100644 Source/DealerSelection.Api/AssignDealerApi.cs create mode 100644 Source/DealerSelection.Api/CommonUtil/AESEncryption.cs create mode 100644 Source/DealerSelection.Api/CommonUtil/CustomConfig.cs create mode 100644 Source/DealerSelection.Api/CommonUtil/GenerateRandomString.cs create mode 100644 Source/DealerSelection.Api/CommonUtil/MuleSoftTokenGenerate.cs create mode 100644 Source/DealerSelection.Api/DealerSelection.Api.csproj create mode 100644 Source/DealerSelection.Api/InfoBipSmsServiceApi.cs create mode 100644 Source/DealerSelection.Api/JwtTokenApi.cs create mode 100644 Source/DealerSelection.Api/MulesoftApi.cs create mode 100644 Source/DealerSelection.Api/MulesoftTokenApi.cs create mode 100644 Source/DealerSelection.Api/YellowAIApi.cs create mode 100644 Source/DealerSelection.Common/CommonBaseClass/ExceptionBase.cs create mode 100644 Source/DealerSelection.Common/CommonBaseClass/ExceptionFilterBase.cs create mode 100644 Source/DealerSelection.Common/CommonBaseClass/StartupBase.cs create mode 100644 Source/DealerSelection.Common/CommonBaseClass/WebApiConfigurationCfgBase.cs create mode 100644 Source/DealerSelection.Common/Configuration/ConfigurationHelper.cs create mode 100644 Source/DealerSelection.Common/Data/ConnectionHelper.cs create mode 100644 Source/DealerSelection.Common/Data/Dapper/RepositoryBaseDapperAsync.cs create mode 100644 Source/DealerSelection.Common/Data/Dapper/RepositoryBaseDapperSync.cs create mode 100644 Source/DealerSelection.Common/Data/Dapper/TypeMapHelper.cs create mode 100644 Source/DealerSelection.Common/Data/RepositoryBaseDIAsync.cs create mode 100644 Source/DealerSelection.Common/Data/RepositoryBaseDISync.cs create mode 100644 Source/DealerSelection.Common/Data/RepositoryDIBase.cs create mode 100644 Source/DealerSelection.Common/DealerSelection.Common.csproj create mode 100644 Source/DealerSelection.Common/Entity/FieldMapAttribute.cs create mode 100644 Source/DealerSelection.Common/Exceptions/AuthorizationException.cs create mode 100644 Source/DealerSelection.Common/Exceptions/DataNotFoundException.cs create mode 100644 Source/DealerSelection.Common/Exceptions/DbConnectionException.cs create mode 100644 Source/DealerSelection.Common/Exceptions/DuplicateException.cs create mode 100644 Source/DealerSelection.Common/Exceptions/NullValueException.cs create mode 100644 Source/DealerSelection.Common/Exceptions/PartialSuccessException.cs create mode 100644 Source/DealerSelection.Common/Exceptions/ValidationException.cs create mode 100644 Source/DealerSelection.Common/Helpers/SwaggerCfg.cs create mode 100644 Source/DealerSelection.Common/Helpers/SwashbuckleSchemaHelper.cs create mode 100644 Source/DealerSelection.Common/HttpClient/MyHttpClientHandler.cs create mode 100644 Source/DealerSelection.Common/Interfaces/Data/IRepositoryDIAsync.cs create mode 100644 Source/DealerSelection.Common/Interfaces/Data/IRepositoryDISync.cs create mode 100644 Source/DealerSelection.Common/Interfaces/HttpClient/IHttpClientHandler.cs create mode 100644 Source/DealerSelection.Common/Logging/ApiInfo.cs create mode 100644 Source/DealerSelection.Common/Logging/AzureLogHelper.cs create mode 100644 Source/DealerSelection.Common/Logging/HttpHeaderHelper.cs create mode 100644 Source/DealerSelection.Common/Logging/LoggingMiddleware.cs create mode 100644 Source/DealerSelection.Common/Logging/RequestInfo.cs create mode 100644 Source/DealerSelection.Common/Logging/ResponseInfo.cs create mode 100644 Source/DealerSelection.Common/Middleware/SwaggerRootRoutingMiddleware.cs create mode 100644 Source/DealerSelection.Common/Profiler/PerformanceProfiler.cs create mode 100644 Source/DealerSelection.Common/Profiler/Profiler.cs create mode 100644 Source/DealerSelection.DependencyInjection/ApiRegistry.cs create mode 100644 Source/DealerSelection.DependencyInjection/DealerSelection.DependencyInjection.csproj create mode 100644 Source/DealerSelection.DependencyInjection/DependencyInjectionBootStrapper.cs create mode 100644 Source/DealerSelection.DependencyInjection/InfrastructureRegistry.cs create mode 100644 Source/DealerSelection.Infrastructure/AssignDealer/IAssignDealerRepository.cs create mode 100644 Source/DealerSelection.Infrastructure/AssignDealer/Repository.cs create mode 100644 Source/DealerSelection.Infrastructure/CustomerDetail/CustomerInfoDto.cs create mode 100644 Source/DealerSelection.Infrastructure/CustomerDetail/IRepository.cs create mode 100644 Source/DealerSelection.Infrastructure/CustomerDetail/Repository.cs create mode 100644 Source/DealerSelection.Infrastructure/DealerSelection.Api.Infrastructure.csproj create mode 100644 Source/DealerSelection.Infrastructure/InfoBip/IRepository.cs create mode 100644 Source/DealerSelection.Infrastructure/InfoBip/Repository.cs create mode 100644 Source/DealerSelection.Infrastructure/Jwt/AuthValidateModelDto.cs create mode 100644 Source/DealerSelection.Infrastructure/Jwt/IJwtRepository.cs create mode 100644 Source/DealerSelection.Infrastructure/Jwt/JwtRepository.cs create mode 100644 Source/DealerSelection.Infrastructure/Mulesoft/DealerDetailDto.cs create mode 100644 Source/DealerSelection.Infrastructure/Mulesoft/IRepository.cs create mode 100644 Source/DealerSelection.Infrastructure/Mulesoft/MulesoftCustomerInfoDto.cs create mode 100644 Source/DealerSelection.Infrastructure/Mulesoft/Repository.cs create mode 100644 Source/DealerSelection.Interface/DealerSelection.Api.Interface.csproj create mode 100644 Source/DealerSelection.Interface/IAssignDealerApi.cs create mode 100644 Source/DealerSelection.Interface/IInfoBipSmsServiceApi.cs create mode 100644 Source/DealerSelection.Interface/IJwtTokenApi.cs create mode 100644 Source/DealerSelection.Interface/IMulesoftApi.cs create mode 100644 Source/DealerSelection.Interface/IMulesoftTokenApi.cs create mode 100644 Source/DealerSelection.Interface/IYellowAIApi.cs create mode 100644 Source/DealerSelection.WebApi.Models/BikeResponse.cs create mode 100644 Source/DealerSelection.WebApi.Models/BookingConfirmationRequest.cs create mode 100644 Source/DealerSelection.WebApi.Models/CityResponse.cs create mode 100644 Source/DealerSelection.WebApi.Models/CustomerInfoMappingResponse.cs create mode 100644 Source/DealerSelection.WebApi.Models/CustomerInfoRequest.cs create mode 100644 Source/DealerSelection.WebApi.Models/DealerSelection.WebApi.Models.csproj create mode 100644 Source/DealerSelection.WebApi.Models/MulesoftResponse.cs create mode 100644 Source/DealerSelection.WebApi.Models/PaymentLinkResponse.cs create mode 100644 Source/DealerSelection.WebApi.Models/RegisterInterestSuccessfulResponse.cs create mode 100644 Source/DealerSelection.WebApi.Models/Response.cs create mode 100644 Source/DealerSelection.WebApi.Models/ReviewPayCustomerInfoResponse.cs create mode 100644 Source/DealerSelection.WebApi.Models/StateResponse.cs create mode 100644 Source/DealerSelection.WebApi/.config/dotnet-tools.json create mode 100644 Source/DealerSelection.WebApi/App_Start/Mapper.cs create mode 100644 Source/DealerSelection.WebApi/App_Start/Startup.cs create mode 100644 Source/DealerSelection.WebApi/App_Start/WebApiConfig.cs create mode 100644 Source/DealerSelection.WebApi/Controllers/DealerSelectionController.cs create mode 100644 Source/DealerSelection.WebApi/Controllers/JWTAuthController.cs create mode 100644 Source/DealerSelection.WebApi/Controllers/JWTAuthController.cs.bak create mode 100644 Source/DealerSelection.WebApi/Controllers/MulesoftController.cs create mode 100644 Source/DealerSelection.WebApi/Controllers/TestController.cs create mode 100644 Source/DealerSelection.WebApi/Controllers/YellowController.cs create mode 100644 Source/DealerSelection.WebApi/DealerSelection.WebApi.csproj create mode 100644 Source/DealerSelection.WebApi/Program.cs create mode 100644 Source/DealerSelection.WebApi/Properties/launchSettings.json create mode 100644 Source/DealerSelection.WebApi/appsettings-PreProd.Development.json create mode 100644 Source/DealerSelection.WebApi/appsettings-PreProd.json create mode 100644 Source/DealerSelection.WebApi/appsettings-Prod.Development.json create mode 100644 Source/DealerSelection.WebApi/appsettings-Prod.json create mode 100644 Source/DealerSelection.WebApi/appsettings.Development.json create mode 100644 Source/DealerSelection.WebApi/appsettings.json create mode 100644 Source/DealerSelection.WebApi/connectionString-PreProd.json create mode 100644 Source/DealerSelection.WebApi/connectionString-Prod.json create mode 100644 Source/DealerSelection.WebApi/connectionString.json create mode 100644 Source/DealerSelection.WebApi/wwwroot/CustomContent/SwaggerHeader.css create mode 100644 Source/DealerSelection.WebApi/wwwroot/CustomContent/logo.png create mode 100644 Source/Tests/DealerSelection.WebApi.IntegrationTests/DealerSelection.WebApi.IntegrationTests.csproj create mode 100644 Source/Tests/DealerSelection.WebApi.IntegrationTests/DetailsRequestController/BookingConfirmation/BookingConfirmationTest.cs create mode 100644 Source/Tests/DealerSelection.WebApi.IntegrationTests/GivenRoot.cs create mode 100644 Source/WebJobService/IService.cs create mode 100644 Source/WebJobService/Program.cs create mode 100644 Source/WebJobService/Service.cs create mode 100644 Source/WebJobService/WebJobService.csproj create mode 100644 Source/WebJobService/app.config create mode 100644 Source/WebJobService/connectionString.json create mode 100644 Web.config diff --git a/DealerSelectionAPI.sln b/DealerSelectionAPI.sln new file mode 100644 index 0000000..4b798c8 --- /dev/null +++ b/DealerSelectionAPI.sln @@ -0,0 +1,98 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.6.33829.357 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DealerSelection.WebApi", "Source\DealerSelection.WebApi\DealerSelection.WebApi.csproj", "{C65D4378-AC83-4B22-A896-E2B47B7CB841}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "WebApi", "WebApi", "{73409D39-9D85-4EE7-B870-129129E11448}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Repo", "Repo", "{2E11D0F3-B91E-49E3-8040-EB3195B75738}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DealerSelection.Api", "Source\DealerSelection.Api\DealerSelection.Api.csproj", "{1368CA19-D9A9-4EB9-8553-0D44DAB22FA2}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DealerSelection.Api.Infrastructure", "Source\DealerSelection.Infrastructure\DealerSelection.Api.Infrastructure.csproj", "{BC5A9A1D-AE12-4E81-B80E-588A14D0FD2E}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DealerSelection.Api.Interface", "Source\DealerSelection.Interface\DealerSelection.Api.Interface.csproj", "{0F9BC8AF-A572-4423-A1BD-C0DF4694E613}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DealerSelection.Api.Models", "Source\DealerSelection.Api.Models\DealerSelection.Api.Models.csproj", "{027412DC-BDA1-4CC4-B3CE-B0B555B3A0AB}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DealerSelection.WebApi.Models", "Source\DealerSelection.WebApi.Models\DealerSelection.WebApi.Models.csproj", "{29FCE055-C131-474C-B398-0855E803905E}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DealerSelection.DependencyInjection", "Source\DealerSelection.DependencyInjection\DealerSelection.DependencyInjection.csproj", "{5FC735F8-39BF-41C5-8896-9EA2ED173CDE}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Common", "Common", "{AA19DD64-E46D-476E-9999-2C6F20007DEE}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DealerSelection.Common", "Source\DealerSelection.Common\DealerSelection.Common.csproj", "{CA12113A-A11B-4EB0-AA56-E80062962D18}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{42B510F1-8DE3-4944-9395-4945B565C614}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DealerSelection.WebApi.IntegrationTests", "Source\Tests\DealerSelection.WebApi.IntegrationTests\DealerSelection.WebApi.IntegrationTests.csproj", "{EFD6DA2D-906C-44E5-A95F-60B31353DEB7}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebJobService", "Source\WebJobService\WebJobService.csproj", "{583C09D6-5582-483E-A54F-89EB414F617C}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {C65D4378-AC83-4B22-A896-E2B47B7CB841}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C65D4378-AC83-4B22-A896-E2B47B7CB841}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C65D4378-AC83-4B22-A896-E2B47B7CB841}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C65D4378-AC83-4B22-A896-E2B47B7CB841}.Release|Any CPU.Build.0 = Release|Any CPU + {1368CA19-D9A9-4EB9-8553-0D44DAB22FA2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1368CA19-D9A9-4EB9-8553-0D44DAB22FA2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1368CA19-D9A9-4EB9-8553-0D44DAB22FA2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1368CA19-D9A9-4EB9-8553-0D44DAB22FA2}.Release|Any CPU.Build.0 = Release|Any CPU + {BC5A9A1D-AE12-4E81-B80E-588A14D0FD2E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BC5A9A1D-AE12-4E81-B80E-588A14D0FD2E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BC5A9A1D-AE12-4E81-B80E-588A14D0FD2E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BC5A9A1D-AE12-4E81-B80E-588A14D0FD2E}.Release|Any CPU.Build.0 = Release|Any CPU + {0F9BC8AF-A572-4423-A1BD-C0DF4694E613}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0F9BC8AF-A572-4423-A1BD-C0DF4694E613}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0F9BC8AF-A572-4423-A1BD-C0DF4694E613}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0F9BC8AF-A572-4423-A1BD-C0DF4694E613}.Release|Any CPU.Build.0 = Release|Any CPU + {027412DC-BDA1-4CC4-B3CE-B0B555B3A0AB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {027412DC-BDA1-4CC4-B3CE-B0B555B3A0AB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {027412DC-BDA1-4CC4-B3CE-B0B555B3A0AB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {027412DC-BDA1-4CC4-B3CE-B0B555B3A0AB}.Release|Any CPU.Build.0 = Release|Any CPU + {29FCE055-C131-474C-B398-0855E803905E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {29FCE055-C131-474C-B398-0855E803905E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {29FCE055-C131-474C-B398-0855E803905E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {29FCE055-C131-474C-B398-0855E803905E}.Release|Any CPU.Build.0 = Release|Any CPU + {5FC735F8-39BF-41C5-8896-9EA2ED173CDE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5FC735F8-39BF-41C5-8896-9EA2ED173CDE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5FC735F8-39BF-41C5-8896-9EA2ED173CDE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5FC735F8-39BF-41C5-8896-9EA2ED173CDE}.Release|Any CPU.Build.0 = Release|Any CPU + {CA12113A-A11B-4EB0-AA56-E80062962D18}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CA12113A-A11B-4EB0-AA56-E80062962D18}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CA12113A-A11B-4EB0-AA56-E80062962D18}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CA12113A-A11B-4EB0-AA56-E80062962D18}.Release|Any CPU.Build.0 = Release|Any CPU + {EFD6DA2D-906C-44E5-A95F-60B31353DEB7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EFD6DA2D-906C-44E5-A95F-60B31353DEB7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EFD6DA2D-906C-44E5-A95F-60B31353DEB7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EFD6DA2D-906C-44E5-A95F-60B31353DEB7}.Release|Any CPU.Build.0 = Release|Any CPU + {583C09D6-5582-483E-A54F-89EB414F617C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {583C09D6-5582-483E-A54F-89EB414F617C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {583C09D6-5582-483E-A54F-89EB414F617C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {583C09D6-5582-483E-A54F-89EB414F617C}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {C65D4378-AC83-4B22-A896-E2B47B7CB841} = {73409D39-9D85-4EE7-B870-129129E11448} + {1368CA19-D9A9-4EB9-8553-0D44DAB22FA2} = {2E11D0F3-B91E-49E3-8040-EB3195B75738} + {BC5A9A1D-AE12-4E81-B80E-588A14D0FD2E} = {2E11D0F3-B91E-49E3-8040-EB3195B75738} + {0F9BC8AF-A572-4423-A1BD-C0DF4694E613} = {2E11D0F3-B91E-49E3-8040-EB3195B75738} + {027412DC-BDA1-4CC4-B3CE-B0B555B3A0AB} = {2E11D0F3-B91E-49E3-8040-EB3195B75738} + {29FCE055-C131-474C-B398-0855E803905E} = {73409D39-9D85-4EE7-B870-129129E11448} + {5FC735F8-39BF-41C5-8896-9EA2ED173CDE} = {73409D39-9D85-4EE7-B870-129129E11448} + {CA12113A-A11B-4EB0-AA56-E80062962D18} = {AA19DD64-E46D-476E-9999-2C6F20007DEE} + {EFD6DA2D-906C-44E5-A95F-60B31353DEB7} = {42B510F1-8DE3-4944-9395-4945B565C614} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {114CDF7F-ED0A-416A-8B06-0056936D24EE} + EndGlobalSection +EndGlobal diff --git a/Source/DealerSelection.Api.Models/AuthModel.cs b/Source/DealerSelection.Api.Models/AuthModel.cs new file mode 100644 index 0000000..530af24 --- /dev/null +++ b/Source/DealerSelection.Api.Models/AuthModel.cs @@ -0,0 +1,14 @@ +namespace DealerSelection.Api.Models +{ + public class AuthModel + { + public string Role { get; set; } + + public string ClientId { get; set; } + + public string SecretId { get; set; } + + public string KeyName { get; set; } + public int BuId { get; set; } + } +} diff --git a/Source/DealerSelection.Api.Models/AuthValidateModel.cs b/Source/DealerSelection.Api.Models/AuthValidateModel.cs new file mode 100644 index 0000000..f1c85fc --- /dev/null +++ b/Source/DealerSelection.Api.Models/AuthValidateModel.cs @@ -0,0 +1,14 @@ +namespace DealerSelection.Api.Models +{ + public class AuthValidateModel + { + public string ClientId { get; set; } + public string SecretId { get; set; } + public int BuId { get; set; } + } + + public class TokenModel + { + public string Token { get; set; } + } +} diff --git a/Source/DealerSelection.Api.Models/CustomerDealerInfoRequest.cs b/Source/DealerSelection.Api.Models/CustomerDealerInfoRequest.cs new file mode 100644 index 0000000..36719d6 --- /dev/null +++ b/Source/DealerSelection.Api.Models/CustomerDealerInfoRequest.cs @@ -0,0 +1,48 @@ +namespace DealerSelection.Api.Models; + +public class CustomerDealerInfoRequest +{ + public CustomerDealerInfoRequest(int buId, int recordId, int mobileNumber, string modelCode, string modelName, + string modelVariant, string dealerName, string dealerCode, string pinCode, string latitude, string longitude, + DealerSelectionJobStatus dealerSelectionJobStatus) + { + BuId = buId; + RecordId = recordId; + MobileNumber = mobileNumber; + ModelCode = modelCode; + ModelName = modelName; + ModelVariant = modelVariant; + DealerName = dealerName; + DealerCode = dealerCode; + PinCode = pinCode; + Latitude = latitude; + Longitude = longitude; + DealerSelectionJobStatus = dealerSelectionJobStatus; + } + + public int BuId { get; } + public int RecordId { get; } + public int MobileNumber { get; } + public string ModelCode { get; } + public string ModelName { get; } + public string ModelVariant { get; } + public string DealerName { get; } + public string DealerCode { get; } + public string PinCode { get; } + public string Latitude { get; } + public string Longitude { get; } + public DealerSelectionJobStatus DealerSelectionJobStatus { get; } + + public override string? ToString() + { + return base.ToString(); + } + + public string RequestDetail() + { + return $"BuId: {BuId}, RecordId: {RecordId}, MobileNumber: {MobileNumber}, ModelCode: {ModelCode}, " + + $"ModelName:{ModelName}, ModelVariant:{ModelVariant}, DealerName: {DealerName}, DealerCode: {DealerCode}, " + + $"PinCode: {PinCode}, Latitude: {Latitude}, Longitude: {Longitude}, DealerSelectionJobStatus: {DealerSelectionJobStatus}"; + } + +} diff --git a/Source/DealerSelection.Api.Models/DealerSelection.Api.Models.csproj b/Source/DealerSelection.Api.Models/DealerSelection.Api.Models.csproj new file mode 100644 index 0000000..78af948 --- /dev/null +++ b/Source/DealerSelection.Api.Models/DealerSelection.Api.Models.csproj @@ -0,0 +1,28 @@ + + + + net6.0 + enable + enable + + + + 1701;1702;8618 + + + + 1701;1702;8618 + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + diff --git a/Source/DealerSelection.Api.Models/DealerSelectionJobStatus.cs b/Source/DealerSelection.Api.Models/DealerSelectionJobStatus.cs new file mode 100644 index 0000000..2f1550f --- /dev/null +++ b/Source/DealerSelection.Api.Models/DealerSelectionJobStatus.cs @@ -0,0 +1,10 @@ +namespace DealerSelection.Api.Models; + +public enum DealerSelectionJobStatus +{ + OldData = -1, + ReadyForJob = 0, + Picked = 1, + SentToBot = 2, + Complete = 3, +} diff --git a/Source/DealerSelection.Api.Models/MulesoftResponse.cs b/Source/DealerSelection.Api.Models/MulesoftResponse.cs new file mode 100644 index 0000000..679379d --- /dev/null +++ b/Source/DealerSelection.Api.Models/MulesoftResponse.cs @@ -0,0 +1,21 @@ + +namespace DealerSelection.Api.Models; +public class MulesoftResponse +{ + public MulesoftResponse(int buId, int bookingId, bool isRequestSuccessfull, string result, string message, string errorCode) + { + BuId = buId; + BookingId = bookingId; + IsRequestSuccessfull = isRequestSuccessfull; + Result = result; + Message = message; + ErrorField = errorCode; + } + public int BuId { get; set; } + public int BookingId { get; set; } + public bool IsRequestSuccessfull { get; } + public string Result { get; } + public string Message { get; } + public string ErrorField { get; } + +} diff --git a/Source/DealerSelection.Api.Models/MulesoftToken.cs b/Source/DealerSelection.Api.Models/MulesoftToken.cs new file mode 100644 index 0000000..e61887c --- /dev/null +++ b/Source/DealerSelection.Api.Models/MulesoftToken.cs @@ -0,0 +1,8 @@ + +namespace DealerSelection.Api.Models; + +public class MulesoftToken +{ + public string Value { get; set; } + public int ExpiresIn { get; set; } +} diff --git a/Source/DealerSelection.Api.Models/Procedure.cs b/Source/DealerSelection.Api.Models/Procedure.cs new file mode 100644 index 0000000..49205da --- /dev/null +++ b/Source/DealerSelection.Api.Models/Procedure.cs @@ -0,0 +1,15 @@ + +namespace DealerSelection.Api.Infrastructure; + +public class Procedure +{ + public const string UpdateDealerDetails = "usp_update_dealer_details"; + public const string GetCustomerBookingInfo = "usp_get_customer_booking_info"; + public const string InsertUpdateDealerDetail = "usp_Insert_Update_Dealer_Details"; + public const string InsertLSQDetail = "usp_insert_lsq_data"; + public const string GetDataForLsqPush = "usp_get_data_for_lsq_push"; + public const string GetCustomerInfoOnBookingId = "usp_get_customer_Info_on_BookingId"; + public const string GetCustomerDataForJob = "usp_get_CustomerDataForJob"; //TO BE ADDED IN DB + public const string IsDuplicateMobileNumber = "usp_isDuplicateMobileNumber"; //TO BE ADDED IN DB + public const string UpdateDealerSelectionJobStatus = "usp_update_DealerSelectionJobStatus"; //TO BE ADDED IN DB +} diff --git a/Source/DealerSelection.Api.Models/Response.cs b/Source/DealerSelection.Api.Models/Response.cs new file mode 100644 index 0000000..9dda97e --- /dev/null +++ b/Source/DealerSelection.Api.Models/Response.cs @@ -0,0 +1,31 @@ + +namespace DealerSelection.Api.Models; +public class Response +{ + public Response(int buId,int recordId, bool isRequestSuccessfull, string result, string message, string errorCode) + { + BuId = buId; + RecordId = recordId; + IsRequestSuccessfull = isRequestSuccessfull; + Result = result; + Message = message; + ErrorCode = errorCode; + } + public bool IsRequestSuccessfull { get; } + public string Result { get; } + public string Message { get; } + public string ErrorCode { get; } + public int RecordId { get; } + public int BuId { get; } + +} +public enum ErrorCode +{ + successErrorCode = 01, + successWithLookupErrorCode = 02, + awaitedErrorCode = 03, + noRecordFound = 04 + +} + + diff --git a/Source/DealerSelection.Api.Models/TokenValidProperty.cs b/Source/DealerSelection.Api.Models/TokenValidProperty.cs new file mode 100644 index 0000000..c715f5e --- /dev/null +++ b/Source/DealerSelection.Api.Models/TokenValidProperty.cs @@ -0,0 +1,10 @@ +namespace DealerSelection.Api.Models +{ + public class TokenValidProperty + { + public bool isValid { get; set; } + + public double Ttl { get; set; } + + } +} diff --git a/Source/DealerSelection.Api.Models/UnexpectedDataException.cs b/Source/DealerSelection.Api.Models/UnexpectedDataException.cs new file mode 100644 index 0000000..8429f1d --- /dev/null +++ b/Source/DealerSelection.Api.Models/UnexpectedDataException.cs @@ -0,0 +1,9 @@ +namespace DealerSelection.Api.Models +{ + public class UnexpectedDataException : Exception + { + public UnexpectedDataException(string message, Exception innerException) : base(message, innerException) + { + } + } +} \ No newline at end of file diff --git a/Source/DealerSelection.Api.Models/WebEngageEvent.cs b/Source/DealerSelection.Api.Models/WebEngageEvent.cs new file mode 100644 index 0000000..2eb319a --- /dev/null +++ b/Source/DealerSelection.Api.Models/WebEngageEvent.cs @@ -0,0 +1,70 @@ +using Newtonsoft.Json; + +namespace DealerSelection.Api.Models; + +public class WebEngageEventData +{ + public WebEngageEventData( string phoneNumber) + { + + PhoneNumber = phoneNumber; + + } + + + [JsonProperty("Booking ID")] + public string BookingID { get; } + + [JsonProperty("Booking Status")] + public string BookingStatus { get; } + + [JsonProperty("Booking Amount")] + public string BookingAmount { get; } + + [JsonProperty("Full Name")] + public string FullName { get; } + + [JsonProperty("Phone Number")] + public string PhoneNumber { get; } + + [JsonProperty("Motorcycle Name")] + public string MotorcycleName { get; } + + [JsonProperty("Motorcycle Code")] + public string MotorcycleCode { get; } + + [JsonProperty("Location")] + public string Location { get; } + + [JsonProperty("Dealer Name")] + public string DealerName { get; } + + [JsonProperty("Dealer Phone Number")] + public string DealerPhoneNumber { get; } + + [JsonProperty("Booking Receipt Link")] + public string BookingReceiptLink { get; } + + [JsonProperty("Landing page URL")] + public string LandingPageURL { get; } + + + +} +public class WebEngageEvent +{ + public WebEngageEvent(string userId, string eventName, WebEngageEventData data) + { + UserId = userId; + EventName = eventName; + EventData = data; + } + [JsonProperty("userId")] + public string UserId { get; } + + [JsonProperty("eventName")] + public string EventName { get; } + + [JsonProperty("eventData")] + public WebEngageEventData EventData { get; } +} \ No newline at end of file diff --git a/Source/DealerSelection.Api/AssignDealerApi.cs b/Source/DealerSelection.Api/AssignDealerApi.cs new file mode 100644 index 0000000..ddfc59e --- /dev/null +++ b/Source/DealerSelection.Api/AssignDealerApi.cs @@ -0,0 +1,190 @@ +using DealerSelection.Api.CommonUtil; +using DealerSelection.Api.Infrastructure.AssignDealer; +using DealerSelection.Api.Infrastructure.CustomerDetail; +using DealerSelection.Api.Infrastructure.Mulesoft; +using DealerSelection.Api.Interface; +using DealerSelection.Api.Models; +using DealerSelection.Common.Configuration; +using DealerSelection.Common.Interfaces.HttpClient; +using Microsoft.Extensions.Caching.Memory; +using Microsoft.Extensions.Logging; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using Org.BouncyCastle.Asn1.Tsp; +using RestSharp; + +public class AssignDealerApi : IAssignDealerApi +{ + + #region MuleSoft + + public static string baseApiUrl = ConfigurationHelper.GetSetting("muleSoftAPIDomain", true); + public static string dealerDetailApiUrl = ConfigurationHelper.GetSetting("muleSoftDealerDetail", true); + public static string bookingApiUrl = ConfigurationHelper.GetSetting("muleSoftBookingAPILeadSquareDomain", true); + public static string masterSchemaId = ConfigurationHelper.GetSetting("masterSchemaId", true); + public static string masterDealerDetailSchemaId = ConfigurationHelper.GetSetting("masterDealerDetailSchemaId", true); + public static string muleSoftStateWisePrice = ConfigurationHelper.GetSetting("muleSoftStateWisePrice", true); + public static string muleSoftBrandWiseModel = ConfigurationHelper.GetSetting("muleSoftBrandWiseModel", true); + public static string muleSoftPricemasterSchemaId = ConfigurationHelper.GetSetting("muleSoftStateWisePricemasterSchemaId", true); + public static string muleSoftModelmasterSchemaId = ConfigurationHelper.GetSetting("muleSoftBrandWiseModelmasterSchemaId", true); + + public static string muleSoftStateMasterSchemaId = ConfigurationHelper.GetSetting("muleSoftStateMasterSchemaId", true); + public static string muleSoftStateMasterSchemaApi = ConfigurationHelper.GetSetting("muleSoftStateMasterSchemaApi", true); + public static string muleSoftCityMasterSchemaId = ConfigurationHelper.GetSetting("muleSoftCityMasterSchemaId", true); + public static string muleSoftCityMasterSchemaApi = ConfigurationHelper.GetSetting("muleSoftCityMasterSchemaApi", true); + public static string muleSoftModelMasterSchemaItemId = ConfigurationHelper.GetSetting("muleSoftModelMasterSchemaItemId", true); + public static string muleSoftModelMasterSchemaItemApi = ConfigurationHelper.GetSetting("muleSoftModelMasterSchemaItemApi", true); + + #endregion + + + #region Caching + + public static string CacheGetDealersDetail = ConfigurationHelper.GetSetting("MuleSoftCacheGetDealersDetail", true); + private int _cacheGetDealersDetail = !string.IsNullOrEmpty(CacheGetDealersDetail) ? int.Parse(CacheGetDealersDetail) : 10; + + public static string CacheGetPriceOnState = ConfigurationHelper.GetSetting("MuleSoftCacheGetPriceOnState", true); + private int _cacheGetPriceOnState = !string.IsNullOrEmpty(CacheGetPriceOnState) ? int.Parse(CacheGetPriceOnState) : 10; + + public static string CacheGetModelOnBrand = ConfigurationHelper.GetSetting("MuleSoftCacheGetModelOnBrand", true); + private int _cacheGetModelOnBrand = !string.IsNullOrEmpty(CacheGetModelOnBrand) ? int.Parse(CacheGetModelOnBrand) : 10; + + public static string CacheGetActiveState = ConfigurationHelper.GetSetting("MuleSoftCacheGetActiveState", true); + private int _cacheGetActiveState = !string.IsNullOrEmpty(CacheGetActiveState) ? int.Parse(CacheGetActiveState) : 10; + + public static string CacheGetActiveCity = ConfigurationHelper.GetSetting("MuleSoftCacheGetActiveCity", true); + private int _cacheGetActiveCity = !string.IsNullOrEmpty(CacheGetActiveCity) ? int.Parse(CacheGetActiveCity) : 10; + + public static string CacheModelDetails = ConfigurationHelper.GetSetting("MuleSoftCacheModelDetails", true); + private int _cacheModelDetails = !string.IsNullOrEmpty(CacheModelDetails) ? int.Parse(CacheModelDetails) : 10; + + + #endregion + + private readonly ILogger _logger; + private IAssignDealerRepository Repository { get; } + private DealerSelection.Api.Infrastructure.CustomerDetail.IRepository CustomerDetailRepository { get; } + private IMulesoftApi MulesoftApi { get; } + private IHttpClientHandler ClientHandler { get; } + private readonly IMemoryCache _memoryCache; + + public AssignDealerApi(IAssignDealerRepository repository, IMulesoftApi mulesoftApi, DealerSelection.Api.Infrastructure.CustomerDetail.IRepository customerRepo, + IHttpClientHandler clientHandler, IMemoryCache memoryCache, ILogger logger) + { + Repository = repository; + MulesoftApi = mulesoftApi; + CustomerDetailRepository = customerRepo; + ClientHandler = clientHandler; + _memoryCache = memoryCache; + _logger = logger; + } + public async Task GetCustomerDataForJob(int buId, int recordId) + { + try + { + + MulesoftCustomerInfoDto customerInfo= await CustomerDetailRepository.GetCustomerData( buId, recordId); + await AssignDealers(customerInfo); + } + catch (Exception ex) + { + _logger.LogError("Api:- GetDealers:- " + ex.StackTrace.ToString()); + } + } + + private async Task AssignDealers(MulesoftCustomerInfoDto customerInfo) + { + try + { + MulesoftResponse dealerResponse = await MulesoftApi.GetDealers(customerInfo.BuId, customerInfo.BuName, customerInfo.CustomerLat, customerInfo.CustomerLong); + if (dealerResponse!=null && dealerResponse.IsRequestSuccessfull) + { + + JObject obj = JObject.Parse(dealerResponse.Result); + if (obj != null && obj["Data"] != null && obj["Data"].Count() > 0) + { + if (obj["Data"].Count() == 1) + { + //Save dealer Detail and Send to LSQ + JToken jArrResultData = (JToken)obj["Data"][0]; + if (jArrResultData != null) + { + customerInfo.DealerCode = (JValue)jArrResultData["Code"] != null ? Convert.ToString(((JValue)jArrResultData["Code"]).Value) : "0"; + customerInfo.DealerName = (JValue)jArrResultData["DisplayName"] != null ? Convert.ToString(((JValue)jArrResultData["DisplayName"]).Value) : "0"; + + try + { + var responseApi = await MulesoftApi.CallLSQBookingApi(customerInfo); + + if (responseApi != null && responseApi.IsRequestSuccessfull) + await UpdateDealerDetail(customerInfo, DealerSelectionJobStatus.Complete); + else + await UpdateDealerDetail(customerInfo, DealerSelectionJobStatus.ReadyForJob); + } + catch (Exception ex) + { + await UpdateDealerDetail(customerInfo, DealerSelectionJobStatus.ReadyForJob); + _logger.LogError("Error in LSQ " + ex.StackTrace.ToString()); + } + } + } + else + { + //Send to Webengage + CustomCfg cfg = CustomCfg.GetCustomCfg(customerInfo.BuId); + WebEngageEventData eventData = new WebEngageEventData(customerInfo.MobileNumber); + WebEngageEvent events = new WebEngageEvent(customerInfo.MobileNumber, cfg.WebengageEventName, eventData); + await WebEngageEventsAPICall(events, cfg); + } + } + } + } + catch (Exception ex) + { + _logger.LogError("BU:- " + customerInfo.BuId + "Api:- GetDealers:- " + ex.StackTrace.ToString()); + } + } + + private async Task WebEngageEventsAPICall(WebEngageEvent message, CustomCfg cfg) + { + _logger.LogInformation("WebEngageEventsAPICall Started: " + JsonConvert.SerializeObject(message)); + try + { + var json = JsonConvert.SerializeObject(message); + var baseApiUrl = Convert.ToString(cfg.WebengageApiHost + cfg.WebEngageLicenseCode + "/events"); + var options = new RestClientOptions(baseApiUrl) + { + MaxTimeout = -1, + }; + var client = new RestClient(); + var request = new RestRequest(baseApiUrl, Method.Post); + request.AddHeader("Content-Type", "application/json"); + request.AddHeader("Authorization", "Bearer " + cfg.WebEngageAuthToken); + request.AddStringBody(json, DataFormat.Json); + RestResponse response = await client.ExecuteAsync(request); + var content = response.Content; + + _logger.LogInformation("WebEngageEventsAPICall End: " + content); + } + catch (Exception ex) + { + _logger.LogError("PendingStatusUpdateApi:- WebEngageEventsAPICall:- " + ex.Message.ToString()); + } + } + + + private async Task UpdateDealerDetail(MulesoftCustomerInfoDto customerInfo, DealerSelectionJobStatus jobStatus) + { + CustomerDealerInfoRequestDto dto = new CustomerDealerInfoRequestDto + { + BuId = customerInfo.BuId, + DealerName = jobStatus == DealerSelectionJobStatus.Complete ? customerInfo.DealerName : "", + DealerCode = jobStatus == DealerSelectionJobStatus.Complete ? customerInfo.DealerCode : "", + DealerSelectionJobStatus = jobStatus == DealerSelectionJobStatus.Complete ? DealerSelectionJobStatus.Complete : DealerSelectionJobStatus.ReadyForJob, + RecordId = customerInfo.RecordId + + }; + await CustomerDetailRepository.UpdateDealerDetail(dto); + } + +} \ No newline at end of file diff --git a/Source/DealerSelection.Api/CommonUtil/AESEncryption.cs b/Source/DealerSelection.Api/CommonUtil/AESEncryption.cs new file mode 100644 index 0000000..b52f63f --- /dev/null +++ b/Source/DealerSelection.Api/CommonUtil/AESEncryption.cs @@ -0,0 +1,151 @@ +using System.Security.Cryptography; +using System.Text; + +namespace DealerSelection.Api.CommonUtil +{ + + public static class AESEncryption + { + + public static byte[] EncryptString(string plainText, byte[] key, byte[] iv) + { + // Instantiate a new Aes object to perform string symmetric encryption + Aes encryptor = Aes.Create(); + + encryptor.Mode = CipherMode.CBC; + + // Set key and IV + byte[] aesKey = new byte[32]; + Array.Copy(key, 0, aesKey, 0, 32); + encryptor.Key = aesKey; + encryptor.IV = iv; + + // Instantiate a new MemoryStream object to contain the encrypted bytes + MemoryStream memoryStream = new MemoryStream(); + + // Instantiate a new encryptor from our Aes object + ICryptoTransform aesEncryptor = encryptor.CreateEncryptor(); + + // Instantiate a new CryptoStream object to process the data and write it to the + // memory stream + CryptoStream cryptoStream = new CryptoStream(memoryStream, aesEncryptor, CryptoStreamMode.Write); + + // Convert the plainText string into a byte array + byte[] plainBytes = Encoding.ASCII.GetBytes(plainText); + + // Encrypt the input plaintext string + cryptoStream.Write(plainBytes, 0, plainBytes.Length); + + // Complete the encryption process + cryptoStream.FlushFinalBlock(); + + // Convert the encrypted data from a MemoryStream to a byte array + byte[] cipherBytes = memoryStream.ToArray(); + + // Close both the MemoryStream and the CryptoStream + memoryStream.Close(); + cryptoStream.Close(); + + // Convert the encrypted byte array to a base64 encoded string + string cipherText = Convert.ToBase64String(cipherBytes, 0, cipherBytes.Length); + + // Return the encrypted data as a string + return cipherBytes; + } + + public static string DecryptString(string cipherText, string key) + { + // Instantiate a new Aes object to perform string symmetric encryption + Aes encryptor = Aes.Create(); + + encryptor.Mode = CipherMode.CBC; + + byte[] salt = Convert.FromBase64String(cipherText).Take(16).ToArray(); + byte[] IVV = Convert.FromBase64String(cipherText).Skip(16).Take(16).ToArray(); + + + byte[] aesKey; + using (var pbkdf2 = new Rfc2898DeriveBytes(key, salt, 65536, HashAlgorithmName.SHA256)) + { + aesKey = pbkdf2.GetBytes(32); + } + + // Set key and IV + //byte[] aesKey = new byte[32]; + //Array.Copy(key, 0, aesKey, 0, 32); + encryptor.Key = aesKey; + encryptor.IV = IVV; + + + + + // Instantiate a new MemoryStream object to contain the encrypted bytes + MemoryStream memoryStream = new MemoryStream(); + + // Instantiate a new encryptor from our Aes object + ICryptoTransform aesDecryptor = encryptor.CreateDecryptor(); + + // Instantiate a new CryptoStream object to process the data and write it to the + // memory stream + CryptoStream cryptoStream = new CryptoStream(memoryStream, aesDecryptor, CryptoStreamMode.Write); + + // Will contain decrypted plaintext + string plainText = string.Empty; + + try + { + // Convert the ciphertext string into a byte array + byte[] cipherBytes = Convert.FromBase64String(cipherText).Skip(32).ToArray(); + + // Decrypt the input ciphertext string + cryptoStream.Write(cipherBytes, 0, cipherBytes.Length); + + // Complete the decryption process + cryptoStream.FlushFinalBlock(); + + // Convert the decrypted data from a MemoryStream to a byte array + byte[] plainBytes = memoryStream.ToArray(); + + // Convert the decrypted byte array to string + plainText = Encoding.ASCII.GetString(plainBytes, 0, plainBytes.Length); + } + finally + { + // Close both the MemoryStream and the CryptoStream + memoryStream.Close(); + cryptoStream.Close(); + } + + // Return the decrypted data as a string + return plainText; + } + + public static dynamic ReturnEncKey(string password,string message) + { + + byte[] salt = new byte[16]; + byte[] encKey; + using (var rng = RandomNumberGenerator.Create()) + { + rng.GetBytes(salt); + } + + using (var pbkdf2 = new Rfc2898DeriveBytes(password, salt, 65536, HashAlgorithmName.SHA256)) + { + encKey = pbkdf2.GetBytes(32); + } + + Random random = new Random(); + + byte[] iv = new byte[16]; + random.NextBytes(iv); + byte[] encrypted = EncryptString(message, encKey, iv); + byte[] finalstring = salt.Concat(iv).Concat(encrypted).ToArray(); + string encstring = Convert.ToBase64String(finalstring); + + return encstring; + } + + } + +} \ No newline at end of file diff --git a/Source/DealerSelection.Api/CommonUtil/CustomConfig.cs b/Source/DealerSelection.Api/CommonUtil/CustomConfig.cs new file mode 100644 index 0000000..c8dba12 --- /dev/null +++ b/Source/DealerSelection.Api/CommonUtil/CustomConfig.cs @@ -0,0 +1,132 @@ +using DealerSelection.Common.Configuration; + +namespace DealerSelection.Api.CommonUtil +{ + public class CustomCfg + { + public int BuId { get; set; } + public string BuCode { get; set; } + public string InfoBipAppilcationId { get; set; } + public string InfoBipMessageId { get; set; } + public string InfoBipFroms { get; set; } + public string CCAvenueAccessCode { get; set; } + public string CCAvenueMerchantCode { get; set; } + public string CCAvenueBaseUrl { get; set; } + public string BookingPrice { get; set; } + public string CCAvenueWorkingKey { get; set; } + public string WebengageLandingPageUrl { get; set; } + public string WebengageEventName { get; set; } + public string WebEngageLicenseCode { get; set; } + public string WebEngageAuthToken { get; set; } + public string WebengageApiHost { get; set; } + public string ValidateDuplicate { get; set; } + public int ValidateDuplicateHour { get; set; } + + public string ClientId { get; set; } + public string ClientSecret { get; set; } + public string Key { get; set; } + public string Audience { get; set; } + public string Issuer { get; set; } + public string Role { get; set; } + + public string ExpireMinutes { get; set; } + public static CustomCfg GetCustomCfg(int buId) + { + CustomCfg cfg = new CustomCfg(); + switch (buId) + { + case 1: + cfg.InfoBipAppilcationId = ConfigurationHelper.GetSetting("KtmCfg:InfoBipAppilcationId", true); + cfg.InfoBipMessageId = ConfigurationHelper.GetSetting("KtmCfg:InfoBipMessageId", true); + cfg.InfoBipFroms = ConfigurationHelper.GetSetting("KtmCfg:InfoBipFrom", true); + + cfg.CCAvenueAccessCode = ConfigurationHelper.GetSetting("KtmCfg:CCAvenueAccessCode", true); + cfg.CCAvenueMerchantCode = ConfigurationHelper.GetSetting("KtmCfg:CCAvenueMerchantCode", true); + cfg.CCAvenueBaseUrl = ConfigurationHelper.GetSetting("KtmCfg:CCAvenueBaseUrl", true); + cfg.BookingPrice = ConfigurationHelper.GetSetting("KtmCfg:BookingPrice", true); + cfg.CCAvenueWorkingKey = ConfigurationHelper.GetSetting("KtmCfg:CCAvenueWorkingKey", true); + cfg.BuCode= ConfigurationHelper.GetSetting("KtmCfg:BuCode", true); + cfg.WebengageLandingPageUrl= ConfigurationHelper.GetSetting("KtmCfg:LandingPageUrl", true); + cfg.WebengageEventName = ConfigurationHelper.GetSetting("KtmCfg:WebengageEventName", true); + cfg.WebEngageLicenseCode = ConfigurationHelper.GetSetting("KtmCfg:WebEngageLicenseCode", true); + cfg.WebEngageAuthToken = ConfigurationHelper.GetSetting("KtmCfg:WebEngageAuthToken", true); + cfg.WebengageApiHost = ConfigurationHelper.GetSetting("KtmCfg:WebengageApiHost", true); + cfg.ValidateDuplicate = ConfigurationHelper.GetSetting("KtmCfg:ValidateDuplicate", true); + cfg.ValidateDuplicateHour = ConfigurationHelper.GetSetting("KtmCfg:ValidateDuplicateHr", true); + cfg.BuId = buId; + + cfg.ClientId = ConfigurationHelper.GetSetting("KtmCfg:ClientId", true); + cfg.ClientSecret = ConfigurationHelper.GetSetting("KtmCfg:ClientSecret", true); + cfg.Key = ConfigurationHelper.GetSetting("KtmCfg:Key", true); + cfg.Audience = ConfigurationHelper.GetSetting("KtmCfg:Audience", true); + cfg.Issuer = ConfigurationHelper.GetSetting("KtmCfg:Issuer", true); + cfg.Role = ConfigurationHelper.GetSetting("KtmCfg:Role", true); + cfg.ExpireMinutes = ConfigurationHelper.GetSetting("KtmCfg:ExpireMinutes", true); + break; + case 2: + cfg.InfoBipAppilcationId = ConfigurationHelper.GetSetting("BajajCfg:InfoBipAppilcationId", true); + cfg.InfoBipMessageId = ConfigurationHelper.GetSetting("BajajCfg:InfoBipMessageId", true); + cfg.InfoBipFroms = ConfigurationHelper.GetSetting("BajajCfg:InfoBipFrom", true); + cfg.CCAvenueAccessCode = ConfigurationHelper.GetSetting("BajajCfg:CCAvenueAccessCode", true); + cfg.CCAvenueMerchantCode = ConfigurationHelper.GetSetting("BajajCfg:CCAvenueMerchantCode", true); + cfg.CCAvenueBaseUrl = ConfigurationHelper.GetSetting("BajajCfg:CCAvenueBaseUrl", true); + cfg.BookingPrice = ConfigurationHelper.GetSetting("BajajCfg:BookingPrice", true); + cfg.CCAvenueWorkingKey = ConfigurationHelper.GetSetting("BajajCfg:CCAvenueWorkingKey", true); + cfg.BuCode = ConfigurationHelper.GetSetting("BajajCfg:BuCode", true); + cfg.WebengageLandingPageUrl = ConfigurationHelper.GetSetting("BajajCfg:LandingPageUrl", true); + cfg.WebengageEventName = ConfigurationHelper.GetSetting("BajajCfg:WebengageEventName", true); + cfg.WebEngageLicenseCode = ConfigurationHelper.GetSetting("BajajCfg:WebEngageLicenseCode", true); + cfg.WebEngageAuthToken = ConfigurationHelper.GetSetting("BajajCfg:WebEngageAuthToken", true); + cfg.WebengageApiHost = ConfigurationHelper.GetSetting("BajajCfg:WebengageApiHost", true); + cfg.ValidateDuplicate = ConfigurationHelper.GetSetting("BajajCfg:ValidateDuplicate", true); + cfg.ValidateDuplicateHour = ConfigurationHelper.GetSetting("BajajCfg:ValidateDuplicateHr", true); + cfg.BuId = buId; + + cfg.ClientId = ConfigurationHelper.GetSetting("BajajCfg:ClientId", true); + cfg.ClientSecret = ConfigurationHelper.GetSetting("BajajCfg:ClientSecret", true); + cfg.Key = ConfigurationHelper.GetSetting("BajajCfg:Key", true); + cfg.Audience = ConfigurationHelper.GetSetting("BajajCfg:Audience", true); + cfg.Issuer = ConfigurationHelper.GetSetting("BajajCfg:Issuer", true); + cfg.Role = ConfigurationHelper.GetSetting("BajajCfg:Role", true); + cfg.ExpireMinutes = ConfigurationHelper.GetSetting("BajajCfg:ExpireMinutes", true); + break; + case 3: + cfg.InfoBipAppilcationId = ConfigurationHelper.GetSetting("TriumphCfg:InfoBipAppilcationId", true); + cfg.InfoBipMessageId = ConfigurationHelper.GetSetting("TriumphCfg:InfoBipMessageId", true); + cfg.InfoBipFroms = ConfigurationHelper.GetSetting("TriumphCfg:InfoBipFrom", true); + cfg.CCAvenueAccessCode = ConfigurationHelper.GetSetting("TriumphCfg:CCAvenueAccessCode", true); + cfg.CCAvenueMerchantCode = ConfigurationHelper.GetSetting("TriumphCfg:CCAvenueMerchantCode", true); + cfg.CCAvenueBaseUrl = ConfigurationHelper.GetSetting("TriumphCfg:CCAvenueBaseUrl", true); + cfg.BookingPrice = ConfigurationHelper.GetSetting("TriumphCfg:BookingPrice", true); + cfg.CCAvenueWorkingKey = ConfigurationHelper.GetSetting("TriumphCfg:CCAvenueWorkingKey", true); + cfg.BuCode = ConfigurationHelper.GetSetting("TriumphCfg:BuCode", true); + cfg.WebengageLandingPageUrl = ConfigurationHelper.GetSetting("TriumphCfg:LandingPageUrl", true); + cfg.WebengageEventName = ConfigurationHelper.GetSetting("TriumphCfg:WebengageEventName", true); + cfg.WebEngageLicenseCode = ConfigurationHelper.GetSetting("TriumphCfg:WebEngageLicenseCode", true); + cfg.WebEngageAuthToken = ConfigurationHelper.GetSetting("TriumphCfg:WebEngageAuthToken", true); + cfg.WebengageApiHost = ConfigurationHelper.GetSetting("TriumphCfg:WebengageApiHost", true); + cfg.ValidateDuplicate = ConfigurationHelper.GetSetting("TriumphCfg:ValidateDuplicate", true); + cfg.ValidateDuplicateHour = ConfigurationHelper.GetSetting("TriumphCfg:ValidateDuplicateHr", true); + cfg.BuId = buId; + + cfg.ClientId = ConfigurationHelper.GetSetting("TriumphCfg:ClientId", true); + cfg.ClientSecret = ConfigurationHelper.GetSetting("TriumphCfg:ClientSecret", true); + cfg.Key = ConfigurationHelper.GetSetting("TriumphCfg:Key", true); + cfg.Audience = ConfigurationHelper.GetSetting("TriumphCfg:Audience", true); + cfg.Issuer = ConfigurationHelper.GetSetting("TriumphCfg:Issuer", true); + cfg.Role = ConfigurationHelper.GetSetting("TriumphCfg:Role", true); + cfg.ExpireMinutes = ConfigurationHelper.GetSetting("TriumphCfg:ExpireMinutes", true); + break; + default: + cfg.InfoBipAppilcationId = ""; + cfg.InfoBipMessageId = ""; + cfg.InfoBipFroms = ""; + cfg.BuId = buId; + break; + } + return cfg; + + } + } + +} diff --git a/Source/DealerSelection.Api/CommonUtil/GenerateRandomString.cs b/Source/DealerSelection.Api/CommonUtil/GenerateRandomString.cs new file mode 100644 index 0000000..e96c3ee --- /dev/null +++ b/Source/DealerSelection.Api/CommonUtil/GenerateRandomString.cs @@ -0,0 +1,28 @@ +namespace DealerSelection.Api.CommonUtil +{ + public static class GenerateRandomString + { + public static string GenerateString(int lgth) + { + string random = ""; + try + { + Random ran = new Random(); + string b = "abcdefghijklmnopqrstuvwxyz"; + int length = lgth; + + for (int i = 0; i < length; i++) + { + int a = ran.Next(26); + random = random + b.ElementAt(a); + } + } + catch (Exception ex) + { + throw ex; + } + return random; + } + } + +} \ No newline at end of file diff --git a/Source/DealerSelection.Api/CommonUtil/MuleSoftTokenGenerate.cs b/Source/DealerSelection.Api/CommonUtil/MuleSoftTokenGenerate.cs new file mode 100644 index 0000000..375f4e1 --- /dev/null +++ b/Source/DealerSelection.Api/CommonUtil/MuleSoftTokenGenerate.cs @@ -0,0 +1,86 @@ +using DealerSelection.Api.Models; +using DealerSelection.Common.Configuration; +using Newtonsoft.Json.Linq; +using System.Net; +using System.Net.Http.Headers; +using System.Text; +using DealerSelection.Common.Interfaces.HttpClient; +using DealerSelection.Common.Logging; + +namespace DealerSelection.Api.CommonUtil +{ + + /// + /// Summary description for TestRideExcellon + /// + public static class MuleSoftIntegration + { + public static string ClientId = ConfigurationHelper.GetSetting("muleSoftAPIClientID", true); + public static string ClientSecret = ConfigurationHelper.GetSetting("muleSoftAIPClientSecret", true); + public static string TokenGenerateUrl = ConfigurationHelper.GetSetting("muleSoftGenerateTokenURL", true); + + public static async Task generateToken(IHttpClientHandler clientHandler) + { + AzureLogHelper.LogMessage("Api:- generateToken Started :- " + DateTime.Now); + MulesoftToken token = new MulesoftToken(); + try + { + var url = TokenGenerateUrl + "/token"; + + ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; + HttpClient client = clientHandler.GetHttpClient(); + Uri requestUri = new Uri(url); + + client.DefaultRequestHeaders.Add("client_id", ClientId); + client.DefaultRequestHeaders.Add("client_secret", ClientSecret); + client.DefaultRequestHeaders.Add("grant_type", "CLIENT_CREDENTIALS"); + client.DefaultRequestHeaders.Add("cache-control", "no-cache"); + + var response = await client.PostAsync(requestUri, null); + + if (response != null) + { + JObject obj = JObject.Parse(await response.Content.ReadAsStringAsync()); + if (response.StatusCode.ToString() == "OK") + { + if (!string.IsNullOrEmpty(Convert.ToString(obj["access_token"]))) + token.Value = Convert.ToString(obj["access_token"]); + if (!string.IsNullOrEmpty(Convert.ToString(obj["expires_in"]))) + token.ExpiresIn = Convert.ToInt32(obj["expires_in"]); + } + } + return token; + } + catch (Exception ex) + { + throw ex; + } + return token; + } + + + public static async Task ReturnMuleSoftResponse(IHttpClientHandler clientHandler, string encstring, string url, string authToken, string encKeyToHeader) + { + try + { + var data = "{\"encData\": \"" + encstring + "\"}"; + + HttpClient request = clientHandler.GetHttpClient(); + Uri requestUri = new Uri(url); + + var httpContent = new MultipartFormDataContent(); + httpContent.Headers.ContentType = new MediaTypeHeaderValue("application/json"); + request.DefaultRequestHeaders.Add("client_id", ClientId); + request.DefaultRequestHeaders.Add("client_secret", ClientSecret); + request.DefaultRequestHeaders.Add("Authorization", "Bearer " + authToken); + request.DefaultRequestHeaders.Add("encKey", encKeyToHeader); + return await request.PostAsync(requestUri, new StringContent(data, UnicodeEncoding.UTF8, "application/json")); + } + catch (Exception ex) + { + throw ex; + } + return null; + } + } +} diff --git a/Source/DealerSelection.Api/DealerSelection.Api.csproj b/Source/DealerSelection.Api/DealerSelection.Api.csproj new file mode 100644 index 0000000..ef879f9 --- /dev/null +++ b/Source/DealerSelection.Api/DealerSelection.Api.csproj @@ -0,0 +1,42 @@ + + + + net6.0 + enable + enable + + + + 1701;1702;8618;8601;8600;8602;8603;CA2254 + + + + 1701;1702;8618;8601;8600;8602;8603;CA2254 + + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + CCAvenue\MCPG.CCA.Util.dll + True + + + + diff --git a/Source/DealerSelection.Api/InfoBipSmsServiceApi.cs b/Source/DealerSelection.Api/InfoBipSmsServiceApi.cs new file mode 100644 index 0000000..a8a97ae --- /dev/null +++ b/Source/DealerSelection.Api/InfoBipSmsServiceApi.cs @@ -0,0 +1,143 @@ +using DealerSelection.Api.CommonUtil; +using DealerSelection.Api.Infrastructure.InfoBip; +using DealerSelection.Api.Interface; +using DealerSelection.Common.Interfaces.HttpClient; +using Microsoft.Extensions.Logging; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using System.Net; +using System.Text; + +/// +/// Summary description for KarixSmsService +/// +public class InfoBipSmsServiceApi : IInfoBipSmsServiceApi +{ + + static string userAuth = Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes("Bajaj_OTP1" + ":" + "BAL@October2022")); + private IRepository Repository { get; } + private readonly ILogger _logger; + private IHttpClientHandler ClientHandler { get; } + public InfoBipSmsServiceApi(IRepository repository, IHttpClientHandler clientHandler, ILogger logger) + { + Repository = repository; + ClientHandler = clientHandler; + _logger = logger; + } + public InfoBipSmsServiceApi() + { + + } + + public async Task sendOTP(int buId, string strMobile) + { + CustomCfg cfg = CustomCfg.GetCustomCfg(buId); + JObject obj = new JObject(); + try + { + var reqObject = new SendOTP + { + applicationId = cfg.InfoBipAppilcationId, + messageId = cfg.InfoBipMessageId, + from = cfg.InfoBipFroms, + to = "91" + strMobile + }; + var json = JsonConvert.SerializeObject(reqObject); + + string apiUrl = "https://266k6.api.infobip.com/2fa/2/pin"; + + obj = await GetDataFromInfoBip(buId, strMobile, apiUrl, "verify", json); + } + catch (Exception ex) + { + _logger.LogError("Api:- sendOTP:- " + ex.StackTrace.ToString()); + } + + return obj; + } + + public async Task resendOTP(int buId, string strMobile, string strOtpPinId) + { + var errorMessage = ""; + JObject obj = new JObject(); + try + { + string apiUrl = "https://266k6.api.infobip.com/2fa/2/pin/" + strOtpPinId + "/resend"; + HttpWebRequest request = (HttpWebRequest)WebRequest.Create(apiUrl); + request.Method = "POST"; + request.Headers.Add("Authorization", "Basic " + userAuth); + request.Headers.Add("cache-control", "no-cache"); + HttpWebResponse response = (HttpWebResponse)request.GetResponse(); + Stream responseStream = response.GetResponseStream(); + StreamReader reader = new StreamReader(responseStream); + string content = reader.ReadToEnd(); + string apiRequest = strOtpPinId; + string apiResponse = content; + obj = JObject.Parse(content); + await Repository.SaveResponse(buId, strMobile, "resend otp", apiRequest, apiResponse, errorMessage); + } + catch (Exception ex) + { + errorMessage = ex.Message; + _logger.LogError("BUID:- " + buId + "Api:- resendOTP:- " + ex.Message.ToString()); + } + + + return obj; + } + + public async Task verifyOTP(int buId, string strMobile, string strOtpPinId, string otpPin) + { + JObject obj = new(); + try + { + var reqObject = new OTP + { + pin = otpPin + }; + var json = JsonConvert.SerializeObject(reqObject); + + string apiUrl = "https://266k6.api.infobip.com/2fa/2/pin/" + strOtpPinId + "/verify"; + + obj = await GetDataFromInfoBip(buId, strMobile, apiUrl, "verify", json); + } + catch (Exception ex) + { + _logger.LogError("BUID:- " + buId + " Api:- verifyOTP:- " + ex.StackTrace.ToString()); + } + + + return obj; + } + + private async Task GetDataFromInfoBip(int buId, string strMobile, string baseUrl, string otpRequestType, string data) + { + HttpClient client = ClientHandler.GetHttpClient(); + Uri requestUri = new Uri(baseUrl); + + + client.DefaultRequestHeaders.Add("Authorization", "Basic " + userAuth); + client.DefaultRequestHeaders.Add("cache-control", "no-cache"); + + var response = await client.PostAsync(requestUri, new StringContent(data, UnicodeEncoding.UTF8, "application/json")); + + JObject obj = JObject.Parse(await response.Content.ReadAsStringAsync()); + + _logger.LogError($"BuId: {buId}, MobileNumber: {strMobile}, OTP Type: {otpRequestType}, ApiRequest: {data} , ApiResponse: {response}"); + + return obj; + } +} + +public class OTP +{ + public string pin { get; set; } +} + +public class SendOTP +{ + public string applicationId { get; set; } + public string messageId { get; set; } + public string from { get; set; } + public string to { get; set; } +} \ No newline at end of file diff --git a/Source/DealerSelection.Api/JwtTokenApi.cs b/Source/DealerSelection.Api/JwtTokenApi.cs new file mode 100644 index 0000000..371f0a5 --- /dev/null +++ b/Source/DealerSelection.Api/JwtTokenApi.cs @@ -0,0 +1,112 @@ +using DealerSelection.Api.CommonUtil; +using DealerSelection.Api.Infrastructure.Jwt; +using DealerSelection.Api.Interface; +using DealerSelection.Api.Models; +using Microsoft.Extensions.Logging; +using Microsoft.IdentityModel.Tokens; +using System.IdentityModel.Tokens.Jwt; +using System.Security.Claims; +using System.Text; + +public class JwtTokenApi : IJwtTokenApi +{ + private IJwtRepository Repository { get; } + private readonly ILogger _logger; + + public JwtTokenApi(IJwtRepository repository, ILogger logger) + { + Repository = repository; + _logger = logger; + } + + public async Task GenerateToken(AuthValidateModel user) + { + try + { + bool isValidUser = await Authenticate(user); + if (isValidUser) + { + AuthModel auth = new AuthModel + { + BuId = user.BuId, + ClientId = user.ClientId, + SecretId = user.SecretId, + Role = "Admin" + }; + CustomCfg cfg = CustomCfg.GetCustomCfg(auth.BuId); + + var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(cfg.Key)); + string expireMinutes = cfg.ExpireMinutes; + int tokenExpireMinutes = string.IsNullOrEmpty(expireMinutes) ? 1439 : int.Parse(expireMinutes); + var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256); + var claims = new[] + { + new Claim(ClaimTypes.NameIdentifier,auth.ClientId), + new Claim(ClaimTypes.Role,auth.Role), + }; + var token = new JwtSecurityToken( + cfg.Issuer, + cfg.Audience, + claims, + expires: DateTime.UtcNow.AddMinutes(tokenExpireMinutes), + signingCredentials: credentials); + return new JwtSecurityTokenHandler().WriteToken(token); + } + } + catch (Exception ex) + { + _logger.LogError("JwtTokenApi Api GenerateToken:- " + ex.Message.ToString()); + } + + return null; + } + + public async Task Authenticate(AuthValidateModel userLogin) + { + try + { + CustomCfg cfg = CustomCfg.GetCustomCfg(userLogin.BuId); + + return cfg.ClientId.ToLower() == userLogin.ClientId.ToLower() && + cfg.ClientSecret.ToLower() == userLogin.SecretId.ToLower(); + } + catch (Exception ex) + { + _logger.LogError("JwtTokenApi Api Authenticate:- " + ex.Message.ToString()); + } + return false; + } + + public async Task IsTokenExpired(string tokenValue) + { + TokenValidProperty tokenValid = new TokenValidProperty(); + try + { + var tokenTicks = GetTokenExpirationTime(tokenValue); + var tokenDate = DateTimeOffset.FromUnixTimeSeconds(tokenTicks).UtcDateTime; + + var now = DateTime.UtcNow; + var valid = tokenDate >= now; + + tokenValid.isValid = valid; + tokenValid.Ttl = tokenDate.TimeOfDay.TotalSeconds - now.TimeOfDay.TotalSeconds; + + return tokenValid; + } + catch (Exception ex) + { + _logger.LogError("JwtTokenApi Api IsTokenExpired:- " + ex.Message.ToString()); + return tokenValid; + } + } + + private static long GetTokenExpirationTime(string token) + { + var handler = new JwtSecurityTokenHandler(); + var jwtSecurityToken = handler.ReadJwtToken(token); + var tokenExp = jwtSecurityToken.Claims.First(claim => claim.Type.Equals("exp")).Value; + var ticks = long.Parse(tokenExp); + return ticks; + } + +} \ No newline at end of file diff --git a/Source/DealerSelection.Api/MulesoftApi.cs b/Source/DealerSelection.Api/MulesoftApi.cs new file mode 100644 index 0000000..921af0b --- /dev/null +++ b/Source/DealerSelection.Api/MulesoftApi.cs @@ -0,0 +1,722 @@ +using DealerSelection.Api.CommonUtil; +using DealerSelection.Api.Infrastructure.Mulesoft; +using DealerSelection.Api.Interface; +using DealerSelection.Api.Models; +using DealerSelection.Common.Configuration; +using DealerSelection.Common.Interfaces.HttpClient; +using DealerSelection.Common.Logging; +using Microsoft.Extensions.Caching.Memory; +using Microsoft.Extensions.Logging; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using System.Text; + +public class MulesoftApi : IMulesoftApi +{ + + #region MuleSoft + + public static string baseApiUrl = ConfigurationHelper.GetSetting("muleSoftAPIDomain", true); + public static string dealerDetailApiUrl = ConfigurationHelper.GetSetting("muleSoftDealerDetail", true); + public static string bookingApiUrl = ConfigurationHelper.GetSetting("muleSoftBookingAPILeadSquareDomain", true); + public static string masterSchemaId = ConfigurationHelper.GetSetting("masterSchemaId", true); + public static string masterDealerDetailSchemaId = ConfigurationHelper.GetSetting("masterDealerDetailSchemaId", true); + public static string muleSoftStateWisePrice = ConfigurationHelper.GetSetting("muleSoftStateWisePrice", true); + public static string muleSoftBrandWiseModel = ConfigurationHelper.GetSetting("muleSoftBrandWiseModel", true); + public static string muleSoftPricemasterSchemaId = ConfigurationHelper.GetSetting("muleSoftStateWisePricemasterSchemaId", true); + public static string muleSoftModelmasterSchemaId = ConfigurationHelper.GetSetting("muleSoftBrandWiseModelmasterSchemaId", true); + + public static string muleSoftStateMasterSchemaId = ConfigurationHelper.GetSetting("muleSoftStateMasterSchemaId", true); + public static string muleSoftStateMasterSchemaApi = ConfigurationHelper.GetSetting("muleSoftStateMasterSchemaApi", true); + public static string muleSoftCityMasterSchemaId = ConfigurationHelper.GetSetting("muleSoftCityMasterSchemaId", true); + public static string muleSoftCityMasterSchemaApi = ConfigurationHelper.GetSetting("muleSoftCityMasterSchemaApi", true); + public static string muleSoftModelMasterSchemaItemId = ConfigurationHelper.GetSetting("muleSoftModelMasterSchemaItemId", true); + public static string muleSoftModelMasterSchemaItemApi = ConfigurationHelper.GetSetting("muleSoftModelMasterSchemaItemApi", true); + + #endregion + + + #region Caching + + public static string CacheGetDealersDetail = ConfigurationHelper.GetSetting("MuleSoftCacheGetDealersDetail", true); + private int _cacheGetDealersDetail = !string.IsNullOrEmpty(CacheGetDealersDetail) ? int.Parse(CacheGetDealersDetail) : 10; + + public static string CacheGetPriceOnState = ConfigurationHelper.GetSetting("MuleSoftCacheGetPriceOnState", true); + private int _cacheGetPriceOnState = !string.IsNullOrEmpty(CacheGetPriceOnState) ? int.Parse(CacheGetPriceOnState) : 10; + + public static string CacheGetModelOnBrand = ConfigurationHelper.GetSetting("MuleSoftCacheGetModelOnBrand", true); + private int _cacheGetModelOnBrand = !string.IsNullOrEmpty(CacheGetModelOnBrand) ? int.Parse(CacheGetModelOnBrand) : 10; + + public static string CacheGetActiveState = ConfigurationHelper.GetSetting("MuleSoftCacheGetActiveState", true); + private int _cacheGetActiveState = !string.IsNullOrEmpty(CacheGetActiveState) ? int.Parse(CacheGetActiveState) : 10; + + public static string CacheGetActiveCity = ConfigurationHelper.GetSetting("MuleSoftCacheGetActiveCity", true); + private int _cacheGetActiveCity = !string.IsNullOrEmpty(CacheGetActiveCity) ? int.Parse(CacheGetActiveCity) : 10; + + public static string CacheModelDetails = ConfigurationHelper.GetSetting("MuleSoftCacheModelDetails", true); + private int _cacheModelDetails = !string.IsNullOrEmpty(CacheModelDetails) ? int.Parse(CacheModelDetails) : 10; + + + #endregion + + private readonly ILogger _logger; + private IRepository Repository { get; } + private IMulesoftTokenApi MulesoftTokenApi { get; } + private IHttpClientHandler ClientHandler { get; } + private readonly IMemoryCache _memoryCache; + + public MulesoftApi(IRepository repository, IMulesoftTokenApi mulesoftTokenApi, + IHttpClientHandler clientHandler, IMemoryCache memoryCache, ILogger logger) + { + Repository = repository; + MulesoftTokenApi = mulesoftTokenApi; + ClientHandler = clientHandler; + _memoryCache = memoryCache; + _logger = logger; + } + + + public async Task GetDealers(int buId, string buUnit, string strlat, string strLong) + { + MulesoftResponse response = null; + try + { + string authToken = await MulesoftTokenApi.FetchToken(); + string message = "{\"bu\": \"" + buUnit + "\", \"latitude\": " + strlat + ", \"longitude\": " + + strLong + ", \"masterSchemaId\": \"" + masterSchemaId + "\"}"; + + if (!string.IsNullOrEmpty(authToken)) + { + string password = GenerateRandomString.GenerateString(32); + string encstring = AESEncryption.ReturnEncKey(password, message); + + var plainTextBytes = Encoding.UTF8.GetBytes(password); + string encKeyToHeader = Convert.ToBase64String(plainTextBytes); + + var response2 = await MuleSoftIntegration.ReturnMuleSoftResponse(ClientHandler, + encstring, baseApiUrl, authToken, encKeyToHeader); + + if (response2 != null) + { + response = await ValidateMuleSoftResponse(buId, response2); + + } + + } + } + catch (Exception ex) + { + _logger.LogError("BU:- " + buId + "Api:- GetDealers:- " + ex.StackTrace.ToString()); + } + return response; + } + + public async Task GetAndInsertDealerDetails(int buId, string dealerCode) + { + MulesoftResponse response = null; + try + { + var cacheKey = "getDealerDetails_" + buId + dealerCode; + if (!_memoryCache.TryGetValue(cacheKey, out response)) + { + AzureLogHelper.LogMessage("Api:- GetAndInsertDealerDetails:- API:- " + cacheKey); + + string authToken = await MulesoftTokenApi.FetchToken(); + string message = "{\"branchCode\": \"" + dealerCode + + "\",\"masterSchemaId\": \"" + masterDealerDetailSchemaId + "\"}"; + + if (!string.IsNullOrEmpty(authToken)) + { + string password = GenerateRandomString.GenerateString(32); + string encstring = AESEncryption.ReturnEncKey(password, message); + + var plainTextBytes = Encoding.UTF8.GetBytes(password); + string encKeyToHeader = Convert.ToBase64String(plainTextBytes); + + var response2 = await MuleSoftIntegration.ReturnMuleSoftResponse(ClientHandler, + encstring, dealerDetailApiUrl, authToken, encKeyToHeader); + response = await DecryptDealerDetail(buId, response2); + var cacheExpiryOptions = new MemoryCacheEntryOptions + { + AbsoluteExpiration = DateTime.Now.AddMinutes(_cacheGetDealersDetail), + Priority = CacheItemPriority.High + }; + _memoryCache.Set(cacheKey, response, cacheExpiryOptions); + } + } + _logger.LogError("Api:- GetAndInsertDealerDetails From Cache:- " + cacheKey); + } + catch (Exception ex) + { + _logger.LogError("Api:- GetAndInsertDealerDetails:- " + ex.Message.ToString()); + } + return response; + } + + public async Task GetStateWisePrice(int buId, string stateCode, string itemId) + { + MulesoftResponse response = null; + try + { + var cacheKey = "getStateWisePrice_" + buId + stateCode + itemId; + if (!_memoryCache.TryGetValue(cacheKey, out response)) + { + _logger.LogError("Api:- GetStateWisePrice API:- " + cacheKey); + + string authToken = await MulesoftTokenApi.FetchToken(); + string message = "{\"statecode\": \"" + stateCode.ToUpper() + "\",\"itemId\": \"" + + itemId + "\",\"masterSchemaId\": \"" + muleSoftPricemasterSchemaId + "\"}"; + + if (!string.IsNullOrEmpty(authToken)) + { + string password = GenerateRandomString.GenerateString(32); + string encstring = AESEncryption.ReturnEncKey(password, message); + + var plainTextBytes = Encoding.UTF8.GetBytes(password); + string encKeyToHeader = Convert.ToBase64String(plainTextBytes); + + var response2 = await MuleSoftIntegration.ReturnMuleSoftResponse(ClientHandler, + encstring, muleSoftStateWisePrice, authToken, encKeyToHeader); + response = await ValidateMuleSoftResponse(buId, response2); + var jsonresult = JObject.Parse(response.Result); + + if (Convert.ToBoolean(jsonresult["IsRequestSuccessfull"]) && jsonresult["Data"] != null) + { + string exShowroomPrice = jsonresult["Data"][0]["ExPrice"].ToString(); + MulesoftResponse mulesoftResponse = new MulesoftResponse(buId, 0, Convert.ToBoolean(jsonresult["IsRequestSuccessfull"]), + exShowroomPrice, "", ""); + + var cacheExpiryOptions = new MemoryCacheEntryOptions + { + AbsoluteExpiration = DateTime.Now.AddMinutes(_cacheGetPriceOnState), + Priority = CacheItemPriority.High + }; + _memoryCache.Set(cacheKey, mulesoftResponse, cacheExpiryOptions); + + return mulesoftResponse; + } + else + { + return new MulesoftResponse(buId, 0, false, response.Result, "", ""); + } + } + } + _logger.LogError("Api:- GetStateWisePrice From Cache :- " + cacheKey); + } + catch (Exception ex) + { + _logger.LogError("Api:- GetStateWisePrice:- " + ex.Message.ToString()); + } + return response; + } + + public async Task GetModelOnBrand(int buId, string brand) + { + MulesoftResponse response = null; + try + { + var cacheKey = "getModelOnBrand_" + buId + brand; + if (!_memoryCache.TryGetValue(cacheKey, out response)) + { + _logger.LogError("Api:- GetModelOnBrand API:- " + cacheKey); + + string authToken = await MulesoftTokenApi.FetchToken(); + string message = "{\"brand\": \"" + brand.ToUpper() + + "\",\"masterSchemaId\": \"" + muleSoftModelmasterSchemaId + "\"}"; + + if (!string.IsNullOrEmpty(authToken)) + { + string password = GenerateRandomString.GenerateString(32); + string encstring = AESEncryption.ReturnEncKey(password, message); + + var plainTextBytes = Encoding.UTF8.GetBytes(password); + string encKeyToHeader = Convert.ToBase64String(plainTextBytes); + + var response2 = await MuleSoftIntegration.ReturnMuleSoftResponse(ClientHandler, + encstring, muleSoftBrandWiseModel, authToken, encKeyToHeader); + response = await ValidateMuleSoftResponse(buId, response2); + + var cacheExpiryOptions = new MemoryCacheEntryOptions + { + AbsoluteExpiration = DateTime.Now.AddMinutes(_cacheGetModelOnBrand), + Priority = CacheItemPriority.High + }; + _memoryCache.Set(cacheKey, response, cacheExpiryOptions); + } + } + _logger.LogError("Api:- GetModelOnBrand From Cache:- " + cacheKey); + } + catch (Exception ex) + { + _logger.LogError("Api:- GetModelOnBrand:- " + ex.Message.ToString()); + } + return response; + } + + public async Task GetActiveState(int buId) + { + CustomCfg cfg = CustomCfg.GetCustomCfg(buId); + MulesoftResponse response = null; + try + { + var cacheKey = "getActiveState_" + buId; + if (!_memoryCache.TryGetValue(cacheKey, out response)) + { + _logger.LogError("Api:- GetActiveState API:- " + cacheKey); + + string authToken = await MulesoftTokenApi.FetchToken(); + string message = "{\"bu\": \"" + cfg.BuCode.ToUpper() + + "\",\"masterSchemaId\": \"" + muleSoftStateMasterSchemaId + "\"}"; + + if (!string.IsNullOrEmpty(authToken)) + { + string password = GenerateRandomString.GenerateString(32); + string encstring = AESEncryption.ReturnEncKey(password, message); + + var plainTextBytes = Encoding.UTF8.GetBytes(password); + string encKeyToHeader = Convert.ToBase64String(plainTextBytes); + + var response2 = await MuleSoftIntegration.ReturnMuleSoftResponse(ClientHandler, encstring, + muleSoftStateMasterSchemaApi, authToken, encKeyToHeader); + + response = await ValidateMuleSoftResponse(0, response2); + + var cacheExpiryOptions = new MemoryCacheEntryOptions + { + AbsoluteExpiration = DateTime.Now.AddMinutes(_cacheGetActiveState), + Priority = CacheItemPriority.High + }; + _memoryCache.Set(cacheKey, response, cacheExpiryOptions); + } + } + _logger.LogError("Api:- GetActiveState from Cache:- " + cacheKey); + } + catch (Exception ex) + { + _logger.LogError("Api:- GetActiveState:- " + ex.Message.ToString()); + } + return response; + } + + public async Task GetActiveCity(int buId, string stateCode) + { + CustomCfg cfg = CustomCfg.GetCustomCfg(buId); + MulesoftResponse response = null; + try + { + var cacheKey = "getActiveCity_" + buId + stateCode; + if (!_memoryCache.TryGetValue(cacheKey, out response)) + { + _logger.LogError("Api GetActiveCity:- API:- " + cacheKey); + + string authToken = await MulesoftTokenApi.FetchToken(); + string message = "{\"bu\": \"" + cfg.BuCode.ToUpper() + "\",\"stateId\": \"" + stateCode.ToUpper() + + "\",\"masterSchemaId\": \"" + muleSoftCityMasterSchemaId + "\"}"; + + if (!string.IsNullOrEmpty(authToken)) + { + string password = GenerateRandomString.GenerateString(32); + string encstring = AESEncryption.ReturnEncKey(password, message); + + var plainTextBytes = Encoding.UTF8.GetBytes(password); + string encKeyToHeader = Convert.ToBase64String(plainTextBytes); + + var response2 = await MuleSoftIntegration.ReturnMuleSoftResponse(ClientHandler, + encstring, muleSoftCityMasterSchemaApi, + authToken, encKeyToHeader); + response = await ValidateMuleSoftResponse(0, response2); + + var cacheExpiryOptions = new MemoryCacheEntryOptions + { + AbsoluteExpiration = DateTime.Now.AddMinutes(_cacheGetActiveCity), + Priority = CacheItemPriority.High + }; + _memoryCache.Set(cacheKey, response, cacheExpiryOptions); + } + } + + _logger.LogError("Api:- GetStateWisePrice:- API:- From Cache" + cacheKey); + } + catch (Exception ex) + { + _logger.LogError("Api:- GetActiveCity:- " + ex.Message.ToString()); + } + return response; + } + + public async Task ModelDetailsByItemCode(int buId, string itemId) + { + MulesoftResponse response = null; + try + { + var cacheKey = "modelDetailsItemCode_" + buId + itemId; + if (!_memoryCache.TryGetValue(cacheKey, out response)) + { + _logger.LogError("Api:- GetStateWisePrice:- API:- From Cache" + cacheKey); + + string authToken = await MulesoftTokenApi.FetchToken(); + string message = "{\"itemid\": \"" + itemId + "\",\"masterSchemaId\": \"" + + muleSoftModelMasterSchemaItemId + "\"}"; + + if (!string.IsNullOrEmpty(authToken)) + { + string password = GenerateRandomString.GenerateString(32); + string encstring = AESEncryption.ReturnEncKey(password, message); + + var plainTextBytes = Encoding.UTF8.GetBytes(password); + string encKeyToHeader = Convert.ToBase64String(plainTextBytes); + + var response2 = await MuleSoftIntegration.ReturnMuleSoftResponse(ClientHandler, + encstring, muleSoftModelMasterSchemaItemApi, authToken, encKeyToHeader); + response = await ValidateMuleSoftResponse(0, response2); + + var cacheExpiryOptions = new MemoryCacheEntryOptions + { + AbsoluteExpiration = DateTime.Now.AddMinutes(_cacheModelDetails), + Priority = CacheItemPriority.High + }; + _memoryCache.Set(cacheKey, response, cacheExpiryOptions); + } + } + + _logger.LogError("Api:- GetStateWisePrice:- API:- From Cache" + cacheKey); + } + catch (Exception ex) + { + _logger.LogError("Api:- GetStateWisePrice:- " + ex.Message.ToString()); + } + return response; + } + + public async Task GetCustomerInfo(int buId, string bookingId) + { + return await Repository.GetCustomerInfo(buId, bookingId); + } + + public async Task CallLSQBookingApi( MulesoftCustomerInfoDto customerInfo) + { + _logger.LogInformation($"BU:- {customerInfo.BuId} at MulesofApi:- CallBookingApi for Booking Id:- {customerInfo.BookingId}"); + try + { + if (customerInfo != null) + { + string mx_Composite_Key = string.Empty, enquiryClassification = string.Empty, + leadPlatform = "Website", autoModel = string.Empty, + bookingStatus = string.Empty, isSuccessBooking = "True"; + string utmSource = GetUTMDetails(customerInfo.ReferralUrl, "utm_source"); + string utmMedium = GetUTMDetails(customerInfo.ReferralUrl, "utm_medium"); + string sourceCampaign = GetUTMDetails(customerInfo.ReferralUrl, "utm_campaign"); + string utmContent = GetUTMDetails(customerInfo.ReferralUrl, "utm_content"); + + if (!string.IsNullOrEmpty(customerInfo.DealerCode)) + mx_Composite_Key = customerInfo.MobileNumber + customerInfo.DealerCode + "Open"; + else + mx_Composite_Key = customerInfo.MobileNumber + "nullOpen"; + + string mx_Source_Of_Enquiry = "Organic"; string mx_Enquiry_Sub_source = "Website"; + if (!string.IsNullOrEmpty(customerInfo.UtmCustomDetails1)) + { + mx_Source_Of_Enquiry = customerInfo.UtmCustomDetails1; + + } + if (!string.IsNullOrEmpty(customerInfo.UtmCustomDetails2)) + { + mx_Enquiry_Sub_source = customerInfo.UtmCustomDetails2; + + } + if (customerInfo.IsRegisterInterestRequest || string.IsNullOrWhiteSpace(customerInfo.DealerCode) || string.IsNullOrWhiteSpace(customerInfo.ModelCode)) + { + enquiryClassification = "Cold"; + autoModel = "No"; + customerInfo.DealerCode = string.Empty; + } + else + { + enquiryClassification = "Hot"; + autoModel = "Yes"; + } + if (customerInfo.Status != "Successful") + { + customerInfo.Status = string.Empty; + customerInfo.BookingId = string.Empty; + customerInfo.CCTransactionId = string.Empty; + customerInfo.ReceiptId = string.Empty; + customerInfo.AmountPaid = string.Empty; + isSuccessBooking = "False"; + } + string pincode = customerInfo.PinCode; + //default pincode value, incase pincode column is empty for the record + if (string.IsNullOrEmpty(pincode)) + pincode = "400070"; + + string message = "{\"bu\": \"PB\", \"model_Code\": \"" + customerInfo.ModelCode + "\"," + + "\"color\": \"" + customerInfo.ColorCode + "\"," + + "\"customer_Name\": \"" + customerInfo.CustomerName + "\"" + + ", \"location_of_the_customer\": \"\", \"dealer_Code\": \"" + customerInfo.DealerCode + "\", " + + "\"mobile\": \"" + customerInfo.MobileNumber + "\"" + + ", \"otp_verified\": \"true\", \"pincode\": \"" + pincode + "\"," + + " \"enquiry_mode\": \"Digital\"" + + ", \"source\": \"" + mx_Source_Of_Enquiry + "\", \"sub_source\": \"" + mx_Enquiry_Sub_source + "\"," + + " \"referral_URL\": \"\"" + + ", \"composite_Key\": \"" + mx_Composite_Key + "\", \"enquiry_Classification\": \"" + enquiryClassification + "\"," + + " \"auto_model\": \"" + autoModel + "\"" + + ", \"bu_Sub_type\": \"\", \"sitcore_Booking_ID\": \"" + customerInfo.BookingId + "\", " + + "\"booking_Status\": \"" + customerInfo.Status + "\"" + + ", \"cc_Avenue_Transaction_ID\": \"" + customerInfo.CCTransactionId + "\"," + + " \"booking_receipt_Number\": \"" + customerInfo.ReceiptId + "\"," + + " \"booking_amount_TRM\": \"" + customerInfo.AmountPaid + "\"," + + " \"test_ride_date\": \"\", \"test_ride_slot\": \"\"" + + ", \"test_ride_location\": \"\"," + + "\"utmSource\": \"" + utmSource + "\", \"utmMedium\":\"" + utmMedium + "\"," + + " \"sourceCampaign\": \"" + sourceCampaign + "\", \"utmContent\":\"" + utmContent + "\"," + + " \"consentToWhatsapp\": \"" + customerInfo.IsWhatsappOptIn + "\",\"leadPlatform\": \"" + leadPlatform + "\" }"; + + + + string authToken = await MulesoftTokenApi.FetchToken(); + + if (!string.IsNullOrEmpty(authToken)) + { + string password = GenerateRandomString.GenerateString(32); + string encstring = AESEncryption.ReturnEncKey(password, message); + + var plainTextBytes = Encoding.UTF8.GetBytes(password); + string encKeyToHeader = Convert.ToBase64String(plainTextBytes); + + // var url = ""; + var response2 = await MuleSoftIntegration.ReturnMuleSoftResponse(ClientHandler, encstring, bookingApiUrl, authToken, encKeyToHeader); + + LeadData _leadData = DecryptBookingApi(response2); + await Repository.UpdateMulesoftResponse(customerInfo.BuId, customerInfo.RecordId, customerInfo.BookingId, message, isSuccessBooking, _leadData); + return new Response(customerInfo.BuId, 0, true, "true", "", ""); + } + } + } + catch (Exception ex) + { + _logger.LogError("Api:- CallBookingApi:- " + ex.StackTrace.ToString()); + } + return new Response(customerInfo.BuId, 0, false, "false", "", ""); + } + + public async Task> GetDataForLsqPush(int buId) + { + return await Repository.GetDataForLsqPush(buId); + } + + private LeadData DecryptBookingApi(HttpResponseMessage response) + { + LeadData _leadData = new LeadData(); + JObject obj = JObject.Parse(response.Content.ReadAsStringAsync().Result); + try + { + if (response.StatusCode.ToString() == "OK") + { + if (obj["encData"] != null && !string.IsNullOrEmpty(Convert.ToString(obj["encData"]))) + { + string pass = string.Empty; + string encResult2 = Convert.ToString(obj["encData"]); + // get enckey from response header + if (response.Headers.Contains("Enckey")) + { + var decodekey = response.Headers.GetValues("Enckey").First(); + if (!string.IsNullOrEmpty(decodekey)) + { + var base64EncodedBytes = Convert.FromBase64String(decodekey); + pass = Encoding.UTF8.GetString(base64EncodedBytes); + } + } + + // Decrypt result by encKey + if (!string.IsNullOrEmpty(encResult2)) + { + _leadData.ApiResponse = AESEncryption.DecryptString(encResult2, pass); + + _logger.LogInformation("DecryptBookingApi decrpted message: " + _leadData.ApiResponse); + + JObject obj1 = JObject.Parse(_leadData.ApiResponse); + string lead_status_code = (string)obj1["statusCode"]; + + if (lead_status_code == "200" && obj1["message"]?["IsSuccess"] != null) + { + _leadData.Lead_status = (string)obj1["message"]["IsSuccess"]; + _leadData.LeadResponseStatus = lead_status_code; + if (_leadData.Lead_status.ToLower().Equals("true")) + { + _leadData.Lead_transferred = "y"; + string[] ids = ((string)obj1["message"]["Value"]).Split(' '); + if (ids.Length == 1) + ids = ((string)obj1["message"]["Value"]).Split(','); + if (ids.Length > 0) + _leadData.Prospect_id = ids[0]; + if (ids.Length > 1) + _leadData.Opportunity_id = ids[1]; + } + else + { + _leadData.Lead_transferred = "n"; + } + } + } + } + } + else + { + _leadData.Lead_transferred = "n"; + _leadData.Lead_status = "Failure"; + _leadData.ApiResponse = ((int)response.StatusCode) + JsonConvert.SerializeObject(obj, Formatting.None); + } + } + catch (Exception ex) + { + _logger.LogError("Api:- DecryptBookingApi:- " + ex.StackTrace.ToString()); + } + return _leadData; + } + + private async Task ValidateMuleSoftResponse(int buId, HttpResponseMessage response2) + { + JObject obj = JObject.Parse(await response2.Content.ReadAsStringAsync()); + + try + { + if (response2.StatusCode.ToString() == "OK") + { + if (obj["encData"] != null && !string.IsNullOrWhiteSpace(Convert.ToString(obj["encData"]))) + { + string pass = string.Empty; + string encResult2 = Convert.ToString(obj["encData"]); + // get enckey from response header + if (response2.Headers.Contains("encKey")) + { + var decodekey = response2.Headers.GetValues("encKey").First(); + if (!string.IsNullOrEmpty(decodekey)) + { + var base64EncodedBytes = Convert.FromBase64String(decodekey); + pass = Encoding.UTF8.GetString(base64EncodedBytes); + } + } + // Decrypt result by encKey + if (!string.IsNullOrWhiteSpace(encResult2)) + { + string decrypted = AESEncryption.DecryptString(encResult2, pass); + JObject obj1 = JObject.Parse(decrypted); + return new MulesoftResponse(buId, 0, true, JsonConvert.SerializeObject(obj1, Formatting.None), "Dealer Found", ""); + } + } + } + else if (((int)response2.StatusCode) == 404) + { + return new MulesoftResponse(buId, 0, true, JsonConvert.SerializeObject(obj, Formatting.None), "No Dealer Found", ""); + } + else if (((int)response2.StatusCode) == 401) + { + return new MulesoftResponse(buId, 0, true, JsonConvert.SerializeObject(obj, Formatting.None), Convert.ToString(obj["error"]), ""); + } + else + { + return new MulesoftResponse(buId, 0, false, JsonConvert.SerializeObject(obj, Formatting.None), "System Down" + JsonConvert.SerializeObject(obj, Formatting.None), ""); + } + } + catch (Exception ex) + { + _logger.LogError("Api:- ValidateMuleSoftResponse:- " + ex.StackTrace.ToString()); + } + return new MulesoftResponse(buId, 0, false, JsonConvert.SerializeObject(obj, Formatting.None), "System Down" + JsonConvert.SerializeObject(obj, Formatting.None), ""); + } + + private async Task DecryptDealerDetail(int buId, HttpResponseMessage response2) + { + JObject obj = JObject.Parse(await response2.Content.ReadAsStringAsync()); + + try + { + if (response2.StatusCode.ToString() == "OK") + { + if (obj["encData"] != null && !string.IsNullOrWhiteSpace(Convert.ToString(obj["encData"]))) + { + string pass = string.Empty; + string encResult2 = Convert.ToString(obj["encData"]); + // get enckey from response header + if (response2.Headers.Contains("encKey")) + { + var decodekey = response2.Headers.GetValues("encKey").First(); + if (!string.IsNullOrEmpty(decodekey)) + { + var base64EncodedBytes = Convert.FromBase64String(decodekey); + pass = Encoding.UTF8.GetString(base64EncodedBytes); + } + } + // Decrypt result by encKey + if (!string.IsNullOrWhiteSpace(encResult2)) + { + string decrypted = AESEncryption.DecryptString(encResult2, pass); + JObject obj1 = JObject.Parse(decrypted); + if (obj1 != null) + { + JToken jArrResultData = (JToken)obj1["Data"]; + if (jArrResultData != null) + { + DealerDetailDto dto = new DealerDetailDto(); + dto.BuId = buId; + dto.DealerCode = (JValue)jArrResultData["Code"] != null ? Convert.ToString(((JValue)jArrResultData["Code"]).Value) : "0"; + dto.Address1 = (JValue)jArrResultData["AddressLine1"] != null ? Convert.ToString(((JValue)jArrResultData["AddressLine1"]).Value) : "0"; + dto.Address2 = (JValue)jArrResultData["AddressLine2"] != null ? Convert.ToString(((JValue)jArrResultData["AddressLine2"]).Value) : "0"; + dto.City = (JValue)jArrResultData["CityName"] != null ? Convert.ToString(((JValue)jArrResultData["CityName"]).Value) : "0"; + dto.State = (JValue)jArrResultData["StateName"] != null ? Convert.ToString(((JValue)jArrResultData["StateName"]).Value) : "0"; + dto.Zip = (JValue)jArrResultData["Zip"] != null ? Convert.ToString(((JValue)jArrResultData["Zip"]).Value) : "0"; + dto.DisplayName = (JValue)jArrResultData["DisplayName"] != null ? Convert.ToString(((JValue)jArrResultData["DisplayName"]).Value) : "0"; + dto.ContactCard = (JValue)jArrResultData["ContactCard"] != null ? Convert.ToString(((JValue)jArrResultData["ContactCard"]).Value) : "0"; + dto.SalesPersonMail = (JValue)jArrResultData["SalesPersonEmail"] != null ? Convert.ToString(((JValue)jArrResultData["SalesPersonEmail"]).Value) : "0"; + dto.SaleMobileNumber = (JValue)jArrResultData["SalesPersonContact"] != null ? Convert.ToString(((JValue)jArrResultData["SalesPersonContact"]).Value) : "0"; + dto.EcomSalesAddress = (JValue)jArrResultData["EcomSalesAddress"] != null ? Convert.ToString(((JValue)jArrResultData["EcomSalesAddress"]).Value) : "0"; + await Repository.InsertAndUpdateDealerRecord(dto); + return new MulesoftResponse(buId, 0, true, dto.Zip, "Dealer Detail Updated", ""); + } + } + } + } + } + else if (((int)response2.StatusCode) == 404) + { + return new MulesoftResponse(buId, 0, true, JsonConvert.SerializeObject(obj, Formatting.None), "No Dealer Found", ""); + + } + else if (((int)response2.StatusCode) == 401) + { + return new MulesoftResponse(buId, 0, true, JsonConvert.SerializeObject(obj, Formatting.None), Convert.ToString(obj["error"]), ""); + } + else + { + return new MulesoftResponse(buId, 0, true, JsonConvert.SerializeObject(obj, Formatting.None), "System Down" + JsonConvert.SerializeObject(obj, Formatting.None), ""); + } + + } + catch (Exception ex) + { + _logger.LogError("Api:- DecryptDealerDetail:- " + ex.Message.ToString()); + } + return new MulesoftResponse(buId, 0, true, JsonConvert.SerializeObject(obj, Formatting.None), "System Down" + JsonConvert.SerializeObject(obj, Formatting.None), ""); + } + + private string GetUTMDetails(string referrerUrl, string utmName) + { + try + { + Uri referrerUri = new(referrerUrl); + var query = referrerUri.Query.Replace("?", ""); + if (!string.IsNullOrWhiteSpace(query)) + { + var dict = query.Split('&').Select(q => q.Split('=')).ToDictionary(k => k[0], v => v[1]); + + if (dict.ContainsKey(utmName)) + return dict[utmName]; + } + } + catch (Exception ex) + { + _logger.LogError("Api:- GetUTMDetails:- " + ex.Message.ToString()); + } + return ""; + } +} \ No newline at end of file diff --git a/Source/DealerSelection.Api/MulesoftTokenApi.cs b/Source/DealerSelection.Api/MulesoftTokenApi.cs new file mode 100644 index 0000000..2ca5a04 --- /dev/null +++ b/Source/DealerSelection.Api/MulesoftTokenApi.cs @@ -0,0 +1,68 @@ +using DealerSelection.Api.CommonUtil; +using DealerSelection.Api.Interface; +using DealerSelection.Api.Models; +using DealerSelection.Common.Interfaces.HttpClient; +using Microsoft.Extensions.Caching.Memory; +using Microsoft.Extensions.Logging; + +namespace DealerSelection.Api; + +public class MulesoftTokenApi : IMulesoftTokenApi +{ + private readonly ILogger _logger; + private readonly IMemoryCache cache; + IHttpClientHandler ClientHandler { get; } + + public MulesoftTokenApi(IMemoryCache cache, IHttpClientHandler clientHandler + , ILogger logger) + { + this.cache = cache; + ClientHandler = clientHandler; + _logger = logger; + } + + public async Task FetchToken() + { + string token = string.Empty; + try + { + // if cache doesn't contain + // an entry called TOKEN + // error handling mechanism is mandatory + if (!cache.TryGetValue("TOKEN", out token)) + { + var tokenmodel = await GetTokenFromApi(); + // keep the value within cache for + // given amount of time + // if value is not accessed within the expiry time + // delete the entry from the cache + if (tokenmodel.ExpiresIn > 0) + { + var options = new MemoryCacheEntryOptions() + .SetAbsoluteExpiration( + TimeSpan.FromSeconds(tokenmodel.ExpiresIn - 300)); + + cache.Set("TOKEN", tokenmodel.Value, options); + + token = tokenmodel.Value; + + _logger.LogInformation("MulesoftTokenApi at FetchToken - token Generated Successfully :- " + DateTime.Now); + } + } + } + catch (Exception ex) + { + _logger.LogError("MulesoftTokenApi Api:- FetchToken:- " + ex.Message.ToString()); + } + return token; + } + + private async Task GetTokenFromApi() + { + // get api implementation happens here + // returns a token model + _logger.LogInformation("MulesoftTokenApi at GetTokenFromApi Started :- " + DateTime.Now); + MulesoftToken token = await MuleSoftIntegration.generateToken(ClientHandler); + return token; + } +} diff --git a/Source/DealerSelection.Api/YellowAIApi.cs b/Source/DealerSelection.Api/YellowAIApi.cs new file mode 100644 index 0000000..c47c0c7 --- /dev/null +++ b/Source/DealerSelection.Api/YellowAIApi.cs @@ -0,0 +1,77 @@ +using DealerSelection.Api.Infrastructure.CustomerDetail; +using DealerSelection.Api.Interface; +using DealerSelection.Api.Models; +using DealerSelection.Common.Exceptions; +using Microsoft.Extensions.Logging; +using System.Text.RegularExpressions; + +namespace DealerSelection.Api; +public class YellowAIApi : IYellowAIApi +{ + + private readonly ILogger _logger; + private IRepository CustomerDetailRepository { get; } + + public YellowAIApi(IRepository customerRepo, ILogger logger) + { + CustomerDetailRepository = customerRepo; + _logger = logger; + } + + + public async Task UpdateSelectedDealer(CustomerDealerInfoRequest request) + { + if (IsValidData(request.MobileNumber, request.DealerCode, request.DealerName)) + { + var isDuplicate = await IsDuplicateMobileNumber(request.MobileNumber); + if (!isDuplicate) + { + + //Push to LSQ then make it complete + + + + // + CustomerDealerInfoRequestDto dto = new CustomerDealerInfoRequestDto + { + BuId = request.BuId, + RecordId = request.RecordId, + MobileNumber = request.MobileNumber, + ModelCode = request.ModelCode, + ModelName = request.ModelName, + ModelVariant = request.ModelVariant, + DealerName = request.DealerName, + DealerCode = request.DealerCode, + PinCode = request.PinCode, + Latitude = request.Latitude, + Longitude = request.Longitude, + DealerSelectionJobStatus = DealerSelectionJobStatus.Complete //Marking JobStatus Complete once we receive response from Yellow API + }; + await CustomerDetailRepository.UpdateDealerDetail(dto); + } + else + _logger.LogWarning($"Duplicate MobileNumber exist. Data Details: {request.RequestDetail()}."); + } + else + { + _logger.LogWarning($"Invalid data. Data Details: {request.RequestDetail()}."); + throw new ValidationException("Invalid data."); + } + } + + private static bool IsValidData(int mobileNumber, string dealerCode, string dealerName) + { + bool valid = Regex.IsMatch(mobileNumber.ToString(), @"^[0-9]{10}$"); + + if (valid && string.IsNullOrWhiteSpace(dealerCode) && string.IsNullOrWhiteSpace(dealerName)) + valid = false; + + return valid; + } + + private async Task IsDuplicateMobileNumber(int mobileNumber) + { + return await CustomerDetailRepository.IsDuplicateMobileNumber(mobileNumber); + } + +} \ No newline at end of file diff --git a/Source/DealerSelection.Common/CommonBaseClass/ExceptionBase.cs b/Source/DealerSelection.Common/CommonBaseClass/ExceptionBase.cs new file mode 100644 index 0000000..9a17ef5 --- /dev/null +++ b/Source/DealerSelection.Common/CommonBaseClass/ExceptionBase.cs @@ -0,0 +1,9 @@ +namespace DealerSelection.Common.CommonBaseClass; + +public class ExceptionBase : Exception +{ + protected ExceptionBase(string message) : base(message) + { } + protected ExceptionBase(string message, Exception innerException) : base(message, innerException) + { } +} diff --git a/Source/DealerSelection.Common/CommonBaseClass/ExceptionFilterBase.cs b/Source/DealerSelection.Common/CommonBaseClass/ExceptionFilterBase.cs new file mode 100644 index 0000000..1dc4400 --- /dev/null +++ b/Source/DealerSelection.Common/CommonBaseClass/ExceptionFilterBase.cs @@ -0,0 +1,92 @@ +using DealerSelection.Common.Exceptions; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Filters; +using System.Net; + +namespace DealerSelection.Common.CommonBaseClass; + +public class ExceptionFilterBase : ExceptionFilterAttribute, IExceptionFilter +{ + protected IDictionary Mappings { get; } + public ExceptionFilterBase() + { + Mappings = new Dictionary + { + {typeof(System.Security.Authentication.AuthenticationException), HttpStatusCode.Unauthorized }, + {typeof(System.Security.Authentication.InvalidCredentialException), HttpStatusCode.Unauthorized }, + {typeof(AuthorizationException), HttpStatusCode.Forbidden }, + {typeof(DataNotFoundException), HttpStatusCode.Forbidden }, + {typeof(DuplicateException), HttpStatusCode.Conflict }, + + {typeof(InvalidDataException), HttpStatusCode.BadRequest }, + {typeof(ValidationException), HttpStatusCode.BadRequest }, + {typeof(NullValueException), HttpStatusCode.BadRequest }, + {typeof(PartialSuccessException), HttpStatusCode.MultiStatus } + + }; + } + + public override void OnException(ExceptionContext context) + { + Exception exception = context.Exception; + if (exception.StackTrace != null) + { + string exceptionStack = exception.StackTrace.StandardizeText(true); + context.HttpContext.Request.Headers.Add("BajaBooking-Custom-ExceptionStack", exceptionStack); + } + + HttpStatusCode httpStatusCode = Mappings.ContainsKey(exception.GetType()) + ? Mappings[exception.GetType()] : HttpStatusCode.InternalServerError; + + foreach (KeyValuePair item in Mappings) + { + if (exception.GetType().IsSubclassOf(item.Key) || exception.GetType() == item.Key) + { + httpStatusCode = item.Value; + break; + } + } + + try + { + if (context.Exception.InnerException != null) + context.HttpContext.Request.Headers.Add("BajaBooking-Custom-InnerException", context.Exception.InnerException.ToString().StandardizeText(true)); + } + catch (Exception ex) + { + try + { + context.HttpContext.Request.Headers.Add("BajaBooking-Custom-InnerException", "Cannot add detailed error to header because: " + ex.Message); + } + catch + { + context.HttpContext.Request.Headers.Add("BajaBooking-Custom-InnerException", "Cannot add detailed error to header for unknown reason: " + ex.Message); + } + } + + //if (ConfigurationHelper.GetSetting("IncludeErrorInResponse", false) || httpStatusCode != HttpStatusCode.InternalServerError) + //{ + // AssignError(context, httpStatusCode, false, exception.Message); + //} + //else + //{ + // context.HttpContext.Request.Headers.Add("BajaBooking-Custom-RealException", exception.Message.StandardizeText(false)); + //} + } + private static void AssignError(ExceptionContext context, HttpStatusCode httpStatusCode, bool withNewLine, string? message = null, string? reason = null) + { + reason ??= message; + string reasonPhrase = reason!.StandardizeText(withNewLine); + context.Result = new ContentResult { Content = reasonPhrase, StatusCode = (int)httpStatusCode, ContentType = "text/plain" }; + } + +} +public static class StringOps +{ + public static string StandardizeText(this string inp, bool withNewLine) + { + if(withNewLine) + return inp.Replace("\r", "\r ").Replace("\n", "\n "); + return inp.Replace("\r", " ").Replace("\n", " "); + } +} diff --git a/Source/DealerSelection.Common/CommonBaseClass/StartupBase.cs b/Source/DealerSelection.Common/CommonBaseClass/StartupBase.cs new file mode 100644 index 0000000..e94a58b --- /dev/null +++ b/Source/DealerSelection.Common/CommonBaseClass/StartupBase.cs @@ -0,0 +1,235 @@ +using DealerSelection.Common.Helpers; +using DealerSelection.Common.Middleware; +using Lamar; +using Lamar.Microsoft.DependencyInjection; +using Microsoft.AspNetCore.Authentication.JwtBearer; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http.Json; +using Microsoft.AspNetCore.HttpOverrides; +using Microsoft.AspNetCore.Mvc.Formatters; +using Microsoft.AspNetCore.ResponseCompression; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.ApplicationInsights; +using Microsoft.IdentityModel.Tokens; +using Microsoft.OpenApi.Models; +using System.IO.Compression; +using System.Reflection; +using System.Text; +using System.Text.Json.Serialization; + +namespace DealerSelection.Common.CommonBaseClass; + +public abstract class StartupBase +{ + public WebApplication CreateHostBuilder(string[] args) + { + try + { + WebApplicationBuilder builder = WebApplication.CreateBuilder(args); + + builder.Host.UseLamar((context, registry) => + { + registry.IncludeRegistry(CreateDIRegistry()); + registry.AddControllers(); + }); + + SetupService(builder.Services); + SetupSwaggerOptions(builder); + + #region AzureLogging + + AzureLogging(builder); + + #endregion + + #region JWT Authentication + JWTAuthentication(builder); + #endregion + + WebApplication app = builder.Build(); + app.UseResponseCompression(); + + app.UseRouting(); + + if (Configuration.ConfigurationHelper.GetSetting("BrowseSwagger", true) == "True") + SetupSwagger(app); + + app.UseCors(x => x + //.WithOrigins("https://www.ktmindia.com", "https://www.triumphmotorcyclesindia.com") //Used for PROD + .AllowAnyOrigin() //Only used for Development + .AllowAnyMethod() + .AllowAnyHeader()); + + //app.UseMiddleware(); + app.UseMiddleware(); + //app.UseMiddleware(); + // app.UseMiddleware(); + + app.UseForwardedHeaders(new ForwardedHeadersOptions + { + ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto + }); + + app.UseAuthentication(); + app.UseAuthorization(); + app.UseStaticFiles(); + // app.MapControllers(); + + app.UseEndpoints(endpoints => + { + endpoints.MapControllers(); + endpoints.MapHealthChecks("/health"); + }); + return app; + } + catch (Exception ex) + { + Console.WriteLine(ex); + throw; + } + } + + private void SetupService(IServiceCollection services) + { + //Caching + services.AddMemoryCache(); + + services.AddSingleton(); + services.AddMvc(options => options.Filters.Add(new ExceptionFilterBase())); + services.AddMvc(options => options.OutputFormatters.Add(new XmlSerializerOutputFormatter())); + + services.AddResponseCompression(options => + { + options.Providers.Add(); + options.EnableForHttps = true; + }); + + services.Configure(options => + { + options.Level = CompressionLevel.Optimal; + }); + + services.AddResponseCompression(options => + { + options.Providers.Add(); + options.EnableForHttps = true; + }); + + services.AddEndpointsApiExplorer(); + services.AddControllers().AddXmlDataContractSerializerFormatters(); + services.AddHealthChecks(); + services.Configure(options => + { + options.SerializerOptions.Converters.Add(new JsonStringEnumConverter()); + }); + services.Configure(options => + { + options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter()); + }); + } + + private void AzureLogging(WebApplicationBuilder builder) + { + builder.Logging.AddApplicationInsights( + configureTelemetryConfiguration: (config) => config.ConnectionString = + builder.Configuration.GetConnectionString("AZURE_LOGGING"), + configureApplicationInsightsLoggerOptions: (options) => { } + ); + builder.Logging.AddFilter("traces", LogLevel.Trace); + } + + + private void JWTAuthentication(WebApplicationBuilder builder) + { + List audiences = new List(); + string[] getAudiences = builder.Configuration["Jwt:Audience"].Split(','); + foreach (var audience in getAudiences) + { + audiences.Add(audience); + } + builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(options => + { + options.TokenValidationParameters = new TokenValidationParameters + { + ValidateIssuer = true, + ValidateAudience = true, + ValidateLifetime = true, + ValidateIssuerSigningKey = true, + ValidIssuer = builder.Configuration["Jwt:Issuer"], + ValidAudiences = new List(audiences), + IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Key"])) + }; + }); + } + + private void SetupSwaggerOptions(WebApplicationBuilder builder) + { + builder.Services.AddSwaggerGen(options => + { + + SwashbuckleSchemaHelper schemaHelper = new SwashbuckleSchemaHelper(); + //handle checking for duplicate return types and makes the name unique + options.CustomSchemaIds(type => schemaHelper.GetSchemaId(type)); + // options.DocumentFilter(); + // options.OperationFilter(); + + #region Swagger Customization For Authentication + + options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme + { + Name = "Authorization", + Type = SecuritySchemeType.Http, + Scheme = "Bearer", + //Reference = new OpenApiReference { Id = "Bearer", Type = ReferenceType.SecurityScheme }, + BearerFormat = "JWT", + In = ParameterLocation.Header, + Description = "Please Enter a Valid JWT Token", + }); + options.AddSecurityRequirement(new OpenApiSecurityRequirement + { + { + new OpenApiSecurityScheme + { + Reference = new OpenApiReference + { + Type=ReferenceType.SecurityScheme, + Id="Bearer" + } + }, + new string[]{} + } + }); + #endregion + + options.SwaggerDoc("v1", new OpenApiInfo + { + Version = "v1", + Title = "Dealer Selection API", + Description = "Web API for Dealer Selection Management" + }); + options.EnableAnnotations(); + + string xmlFileName = $"{Assembly.GetEntryAssembly()!.GetName().Name}.xml"; + options.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, xmlFileName)); + + }); + } + + private static void SetupSwagger(WebApplication app) + { + app.UseSwagger(c => + { + c.RouteTemplate = "help/ui/{documentName}/swagger.json"; + }); + app.UseSwaggerUI(c => + { + c.SwaggerEndpoint("/help/ui/v1/swagger.json", "Sample API"); + c.RoutePrefix = "help/ui"; + c.InjectStylesheet("/CustomContent/SwaggerHeader.css"); + }); + } + protected abstract ServiceRegistry CreateDIRegistry(); +} diff --git a/Source/DealerSelection.Common/CommonBaseClass/WebApiConfigurationCfgBase.cs b/Source/DealerSelection.Common/CommonBaseClass/WebApiConfigurationCfgBase.cs new file mode 100644 index 0000000..551cb67 --- /dev/null +++ b/Source/DealerSelection.Common/CommonBaseClass/WebApiConfigurationCfgBase.cs @@ -0,0 +1,6 @@ +namespace DealerSelection.Common.CommonBaseClass; + +public abstract class WebApiConfigurationCfgBase +{ + +} diff --git a/Source/DealerSelection.Common/Configuration/ConfigurationHelper.cs b/Source/DealerSelection.Common/Configuration/ConfigurationHelper.cs new file mode 100644 index 0000000..1ea1951 --- /dev/null +++ b/Source/DealerSelection.Common/Configuration/ConfigurationHelper.cs @@ -0,0 +1,102 @@ +using Microsoft.Extensions.Configuration; +using System.Configuration; +using System.Reflection; + +namespace DealerSelection.Common.Configuration; + +public static class ConfigurationHelper +{ + public static int SetEnvironmentVariables(string settingsFile) + { + IConfigurationRoot? config = LoadSettingsFile(settingsFile); + int count = 0; + + if (config != null) + { + foreach (KeyValuePair pair in config.AsEnumerable()) + { + if (pair.Value == null) + continue; + + Environment.SetEnvironmentVariable(pair.Key, pair.Value); + count++; + } + } + + return count; + } + + public static IConfigurationRoot? LoadSettingsFile(string settingsFile) + { + string basePath = FindBaseLocation(settingsFile); + IConfigurationBuilder builder = new ConfigurationBuilder() + .SetBasePath(basePath) + .AddJsonFile(settingsFile); + + return builder.Build(); + } + + public static string GetConnectionString(string cxnName, string cfgFile = "connectionString.json") + { + IConfigurationRoot? root = LoadSettingsFile(cfgFile); + string settings = root.GetConnectionString(cxnName); + if (!string.IsNullOrEmpty(settings)) + { + return settings; + } + throw new ConfigurationErrorsException($"Connection stirng {cxnName} not found in connection strings cfg file {cfgFile}."); + } + private static string FindBaseLocation(string settingsFile) + { + string?[] baseLocations = + { + Directory.GetCurrentDirectory(), + AppDomain.CurrentDomain.BaseDirectory, + Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + }; + + foreach (string? baseLocation in baseLocations) + { + if (string.IsNullOrEmpty(baseLocation)) + continue; + string path = Path.Combine(baseLocation, settingsFile); + if (File.Exists(path)) + return baseLocation; + } + + return baseLocations[1]!; + } + + public static T? GetSetting(string key, bool mustExist) + { + return GetSetting(key, default(T), mustExist); + } + + public static T? GetSetting(string key, T? defaultValue = default) + { + return GetSetting(key, defaultValue, false); + } + + public static T GetSetting(string key, T defaultValue, bool mustExist) + { + string? valString = Environment.GetEnvironmentVariable(key); + + if (valString == null) + { + if (mustExist) + { + throw new ConfigurationErrorsException($"Setting {key} not found"); + } + return defaultValue; + } + + try + { + return (T)Convert.ChangeType(valString, typeof(T)); + } + catch (Exception ex) + { + throw new ConfigurationErrorsException($"Settings {key} ('{valString}') cannot be converted to type {typeof(T).Name}", ex); + } + } +} diff --git a/Source/DealerSelection.Common/Data/ConnectionHelper.cs b/Source/DealerSelection.Common/Data/ConnectionHelper.cs new file mode 100644 index 0000000..ab3c5af --- /dev/null +++ b/Source/DealerSelection.Common/Data/ConnectionHelper.cs @@ -0,0 +1,36 @@ + +using System.Data.SqlClient; +using DealerSelection.Common.Configuration; + +namespace DealerSelection.Common.Data; + +public static class ConnectionHelper +{ + public static SqlConnection GetConnectionSync(string cxnName) + { + SqlConnection cxn = GetConnection(cxnName); + cxn.Open(); + return cxn; + } + + public static SqlConnection GetConnectionAsync(string cxnName) + { + SqlConnection cxn = GetConnection(cxnName); + cxn.OpenAsync(); + return cxn; + } + + private static SqlConnection GetConnection(string cxnName) + { + string cxnString = GetConnectionString(cxnName); + + SqlConnection cxn = new SqlConnection(cxnString); + return cxn; + } + + public static string GetConnectionString(string cxnName) + { + string cxnString = ConfigurationHelper.GetConnectionString(cxnName); + return cxnString; + } +} diff --git a/Source/DealerSelection.Common/Data/Dapper/RepositoryBaseDapperAsync.cs b/Source/DealerSelection.Common/Data/Dapper/RepositoryBaseDapperAsync.cs new file mode 100644 index 0000000..2f00975 --- /dev/null +++ b/Source/DealerSelection.Common/Data/Dapper/RepositoryBaseDapperAsync.cs @@ -0,0 +1,25 @@ +using System.Data.SqlClient; + +namespace DealerSelection.Common.Data.Dapper; + +public class RepositoryBaseDapperAsync : RepositoryBaseDIAsync +{ + public RepositoryBaseDapperAsync(string cxnName) : base(cxnName) + { + + } + + protected async Task OpenCxnWithMappingAsync() + { + Task cxnTask = OpenCxnAsync(); + SetTypeMap(); + + return await cxnTask; + } + + protected void SetTypeMap() + { + TypeMapHelper.SetTypeMap(); + } + +} \ No newline at end of file diff --git a/Source/DealerSelection.Common/Data/Dapper/RepositoryBaseDapperSync.cs b/Source/DealerSelection.Common/Data/Dapper/RepositoryBaseDapperSync.cs new file mode 100644 index 0000000..b3fbb1e --- /dev/null +++ b/Source/DealerSelection.Common/Data/Dapper/RepositoryBaseDapperSync.cs @@ -0,0 +1,25 @@ +using System.Data.SqlClient; + +namespace DealerSelection.Common.Data.Dapper; + +public class RepositoryBaseDapperSync : RepositoryBaseDISync +{ + public RepositoryBaseDapperSync(string cxnName) : base(cxnName) + { + + } + + protected SqlConnection OpenCxnWithMappingSync() + { + SqlConnection cxn = OpenCxnSync(); + SetTypeMap(); + + return cxn; + } + + protected void SetTypeMap() + { + TypeMapHelper.SetTypeMap(); + } + +} \ No newline at end of file diff --git a/Source/DealerSelection.Common/Data/Dapper/TypeMapHelper.cs b/Source/DealerSelection.Common/Data/Dapper/TypeMapHelper.cs new file mode 100644 index 0000000..ce5f7ea --- /dev/null +++ b/Source/DealerSelection.Common/Data/Dapper/TypeMapHelper.cs @@ -0,0 +1,30 @@ +using DealerSelection.Common.Entity; +using Dapper; +using System.Reflection; + +namespace DealerSelection.Common.Data.Dapper; + +public static class TypeMapHelper +{ + public static void SetTypeMap() + { + CustomPropertyTypeMap map = new CustomPropertyTypeMap( + typeof(T), + PropertySelector); + SqlMapper.SetTypeMap(typeof(T), map); + } + private static PropertyInfo PropertySelector(Type type, string columnName) + { + PropertyInfo[] properties = type.GetProperties(); + return properties.FirstOrDefault( + prop => prop.Name.Equals(columnName, StringComparison.OrdinalIgnoreCase) + || columnName.Equals(GetColumnFromAttribute(prop), StringComparison.OrdinalIgnoreCase)); + } + public static string GetColumnFromAttribute(MemberInfo member) + { + if (member == null) return null; + FieldMapAttribute attrib = (FieldMapAttribute)Attribute.GetCustomAttribute( + member, typeof(FieldMapAttribute), true); + return attrib?.DbFieldName; + } +} diff --git a/Source/DealerSelection.Common/Data/RepositoryBaseDIAsync.cs b/Source/DealerSelection.Common/Data/RepositoryBaseDIAsync.cs new file mode 100644 index 0000000..aaaef1a --- /dev/null +++ b/Source/DealerSelection.Common/Data/RepositoryBaseDIAsync.cs @@ -0,0 +1,35 @@ +using DealerSelection.Common.Exceptions; +using DealerSelection.Common.Interfaces.Data; +using System.Data.SqlClient; + +namespace DealerSelection.Common.Data; + +public abstract class RepositoryBaseDIAsync : RepositoryDIBase, IRepositoryDIAsync +{ + public RepositoryBaseDIAsync(string cxnName) : base(cxnName) + { + + } + + public async Task OpenCxnAsync() + { + SqlConnection cxn = new SqlConnection(CxnString); + try + { + await cxn.OpenAsync(); + } + catch (SqlException ex) + { + foreach(SqlError error in ex.Errors) + { + if(error.Number == 53) + { + throw new DbConnectionException($"DB Connection error for CxnString: {CxnString}. Exception: {ex}"); + } + } + throw; + } + + return cxn; + } +} diff --git a/Source/DealerSelection.Common/Data/RepositoryBaseDISync.cs b/Source/DealerSelection.Common/Data/RepositoryBaseDISync.cs new file mode 100644 index 0000000..31c3022 --- /dev/null +++ b/Source/DealerSelection.Common/Data/RepositoryBaseDISync.cs @@ -0,0 +1,35 @@ +using DealerSelection.Common.Exceptions; +using DealerSelection.Common.Interfaces.Data; +using System.Data.SqlClient; + +namespace DealerSelection.Common.Data; + +public abstract class RepositoryBaseDISync : RepositoryDIBase, IRepositoryDISync +{ + public RepositoryBaseDISync(string cxnName) : base(cxnName) + { + + } + + public SqlConnection OpenCxnSync() + { + SqlConnection cxn = new SqlConnection(CxnString); + try + { + cxn.Open(); + } + catch (SqlException ex) + { + foreach(SqlError error in ex.Errors) + { + if(error.Number == 53) + { + throw new DbConnectionException($"DB Connection error for CxnString: {CxnString}. Exception: {ex}"); + } + } + throw; + } + + return cxn; + } +} diff --git a/Source/DealerSelection.Common/Data/RepositoryDIBase.cs b/Source/DealerSelection.Common/Data/RepositoryDIBase.cs new file mode 100644 index 0000000..4cfc709 --- /dev/null +++ b/Source/DealerSelection.Common/Data/RepositoryDIBase.cs @@ -0,0 +1,11 @@ + +namespace DealerSelection.Common.Data; + +public abstract class RepositoryDIBase +{ + public string CxnString { get; } + protected RepositoryDIBase(string cxnName) + { + CxnString = ConnectionHelper.GetConnectionString(cxnName); + } +} diff --git a/Source/DealerSelection.Common/DealerSelection.Common.csproj b/Source/DealerSelection.Common/DealerSelection.Common.csproj new file mode 100644 index 0000000..507e881 --- /dev/null +++ b/Source/DealerSelection.Common/DealerSelection.Common.csproj @@ -0,0 +1,56 @@ + + + + net6.0 + enable + enable + + + + 1701;1702;8603;1822;8602;8604 + + + + 1701;1702;8603;1822;8602;8604 + + + + + + + + + + + + + + + + + + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + Never + + + + diff --git a/Source/DealerSelection.Common/Entity/FieldMapAttribute.cs b/Source/DealerSelection.Common/Entity/FieldMapAttribute.cs new file mode 100644 index 0000000..ee0e645 --- /dev/null +++ b/Source/DealerSelection.Common/Entity/FieldMapAttribute.cs @@ -0,0 +1,24 @@ +namespace DealerSelection.Common.Entity; + +/// +/// An Attribute that provides a mapping between a property on an object and a fields in a database table. +/// +[AttributeUsage(AttributeTargets.Property)] +public sealed class FieldMapAttribute : Attribute +{ + readonly string _dbFieldName; + + /// + /// Initialize a new FieldMapAttribute + /// + /// Name of database field that this property represents + public FieldMapAttribute(string dbFieldName) + { + _dbFieldName = dbFieldName; + } + + /// + /// Name of field that the perperty this attribute is attached to is mapped to. + /// + public string DbFieldName => _dbFieldName; +} diff --git a/Source/DealerSelection.Common/Exceptions/AuthorizationException.cs b/Source/DealerSelection.Common/Exceptions/AuthorizationException.cs new file mode 100644 index 0000000..df80a1f --- /dev/null +++ b/Source/DealerSelection.Common/Exceptions/AuthorizationException.cs @@ -0,0 +1,8 @@ +using DealerSelection.Common.CommonBaseClass; + +namespace DealerSelection.Common.Exceptions; + +public class AuthorizationException : ExceptionBase +{ + public AuthorizationException(string message) : base(message) { } +} diff --git a/Source/DealerSelection.Common/Exceptions/DataNotFoundException.cs b/Source/DealerSelection.Common/Exceptions/DataNotFoundException.cs new file mode 100644 index 0000000..07df4ab --- /dev/null +++ b/Source/DealerSelection.Common/Exceptions/DataNotFoundException.cs @@ -0,0 +1,8 @@ +using DealerSelection.Common.CommonBaseClass; + +namespace DealerSelection.Common.Exceptions; + +public class DataNotFoundException : ExceptionBase +{ + public DataNotFoundException(string message) : base(message) { } +} diff --git a/Source/DealerSelection.Common/Exceptions/DbConnectionException.cs b/Source/DealerSelection.Common/Exceptions/DbConnectionException.cs new file mode 100644 index 0000000..6ee8d8c --- /dev/null +++ b/Source/DealerSelection.Common/Exceptions/DbConnectionException.cs @@ -0,0 +1,15 @@ + +using DealerSelection.Common.CommonBaseClass; + +namespace DealerSelection.Common.Exceptions; + +public class DbConnectionException : ExceptionBase +{ + public DbConnectionException(string message) : base(message) + { + } + + public DbConnectionException(string message, Exception innerException) : base(message, innerException) + { + } +} diff --git a/Source/DealerSelection.Common/Exceptions/DuplicateException.cs b/Source/DealerSelection.Common/Exceptions/DuplicateException.cs new file mode 100644 index 0000000..c7a988c --- /dev/null +++ b/Source/DealerSelection.Common/Exceptions/DuplicateException.cs @@ -0,0 +1,8 @@ +using DealerSelection.Common.CommonBaseClass; + +namespace DealerSelection.Common.Exceptions; + +public class DuplicateException : ExceptionBase +{ + public DuplicateException(string message) : base(message) { } +} diff --git a/Source/DealerSelection.Common/Exceptions/NullValueException.cs b/Source/DealerSelection.Common/Exceptions/NullValueException.cs new file mode 100644 index 0000000..c6576d5 --- /dev/null +++ b/Source/DealerSelection.Common/Exceptions/NullValueException.cs @@ -0,0 +1,8 @@ +using DealerSelection.Common.CommonBaseClass; + +namespace DealerSelection.Common.Exceptions; + +public class NullValueException : ExceptionBase +{ + public NullValueException(string message) : base(message) { } +} diff --git a/Source/DealerSelection.Common/Exceptions/PartialSuccessException.cs b/Source/DealerSelection.Common/Exceptions/PartialSuccessException.cs new file mode 100644 index 0000000..40bc6fd --- /dev/null +++ b/Source/DealerSelection.Common/Exceptions/PartialSuccessException.cs @@ -0,0 +1,8 @@ +using DealerSelection.Common.CommonBaseClass; + +namespace DealerSelection.Common.Exceptions; + +public class PartialSuccessException : ExceptionBase +{ + public PartialSuccessException(string message) : base(message) { } +} diff --git a/Source/DealerSelection.Common/Exceptions/ValidationException.cs b/Source/DealerSelection.Common/Exceptions/ValidationException.cs new file mode 100644 index 0000000..b996784 --- /dev/null +++ b/Source/DealerSelection.Common/Exceptions/ValidationException.cs @@ -0,0 +1,8 @@ +using DealerSelection.Common.CommonBaseClass; + +namespace DealerSelection.Common.Exceptions; + +public class ValidationException : ExceptionBase +{ + public ValidationException(string message) : base(message) { } +} diff --git a/Source/DealerSelection.Common/Helpers/SwaggerCfg.cs b/Source/DealerSelection.Common/Helpers/SwaggerCfg.cs new file mode 100644 index 0000000..69ff2b6 --- /dev/null +++ b/Source/DealerSelection.Common/Helpers/SwaggerCfg.cs @@ -0,0 +1,8 @@ +namespace DealerSelection.Common.Helpers; + +public class SwaggerCfg +{ + public string? Name { get; set; } + public string? Title { get; set; } + public string? Description { get; set; } +} diff --git a/Source/DealerSelection.Common/Helpers/SwashbuckleSchemaHelper.cs b/Source/DealerSelection.Common/Helpers/SwashbuckleSchemaHelper.cs new file mode 100644 index 0000000..651ba58 --- /dev/null +++ b/Source/DealerSelection.Common/Helpers/SwashbuckleSchemaHelper.cs @@ -0,0 +1,38 @@ +namespace DealerSelection.Common.Helpers; + +public class SwashbuckleSchemaHelper +{ + private readonly Dictionary _schemaNameRepetition = new (); + + /// + /// Eliminate the case where more than one method returns the same type in different controllers + /// swagger documentation to fail + /// + /// + /// + public string GetSchemaId(Type modelType) + { + string id = DefaultSchemaIdSelector (modelType); + + if(!_schemaNameRepetition.ContainsKey(id)) + _schemaNameRepetition.Add(id, 0); + + int count = _schemaNameRepetition[id] + 1; + _schemaNameRepetition[id] = count; + + return $"{id}{(count > 1 ? count.ToString() : "")}"; + } + + private string DefaultSchemaIdSelector(Type modelType) + { + if (!modelType.IsConstructedGenericType) + return modelType.Name.Replace("[]", "Array"); + + string prefix = modelType.GetGenericArguments() + .Select(genericArg => DefaultSchemaIdSelector(genericArg)) + .Aggregate((previous, current) => previous + current); + + return prefix + modelType.Name.Split('`').First(); + } + +} diff --git a/Source/DealerSelection.Common/HttpClient/MyHttpClientHandler.cs b/Source/DealerSelection.Common/HttpClient/MyHttpClientHandler.cs new file mode 100644 index 0000000..191d681 --- /dev/null +++ b/Source/DealerSelection.Common/HttpClient/MyHttpClientHandler.cs @@ -0,0 +1,21 @@ +using DealerSelection.Common.Interfaces.HttpClient; + +namespace DealerSelection.Common.HttpClient; + +public class MyHttpClientHandler : IHttpClientHandler +{ + public System.Net.Http.HttpClient GetHttpClient() + { + var handler = new SocketsHttpHandler + { + PooledConnectionLifetime = TimeSpan.FromMinutes(15) // Recreate every 15 minutes + }; + + System.Net.Http.HttpClient client = new System.Net.Http.HttpClient(handler); + + client.DefaultRequestHeaders.Accept.Clear(); + client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json")); + + return client; + } +} diff --git a/Source/DealerSelection.Common/Interfaces/Data/IRepositoryDIAsync.cs b/Source/DealerSelection.Common/Interfaces/Data/IRepositoryDIAsync.cs new file mode 100644 index 0000000..0ba6315 --- /dev/null +++ b/Source/DealerSelection.Common/Interfaces/Data/IRepositoryDIAsync.cs @@ -0,0 +1,9 @@ +using System.Data.SqlClient; + +namespace DealerSelection.Common.Interfaces.Data; + +public interface IRepositoryDIAsync +{ + string CxnString { get; } + Task OpenCxnAsync(); +} diff --git a/Source/DealerSelection.Common/Interfaces/Data/IRepositoryDISync.cs b/Source/DealerSelection.Common/Interfaces/Data/IRepositoryDISync.cs new file mode 100644 index 0000000..f6f5d0b --- /dev/null +++ b/Source/DealerSelection.Common/Interfaces/Data/IRepositoryDISync.cs @@ -0,0 +1,9 @@ +using System.Data.SqlClient; + +namespace DealerSelection.Common.Interfaces.Data; + +public interface IRepositoryDISync +{ + string CxnString { get; } + SqlConnection OpenCxnSync(); +} diff --git a/Source/DealerSelection.Common/Interfaces/HttpClient/IHttpClientHandler.cs b/Source/DealerSelection.Common/Interfaces/HttpClient/IHttpClientHandler.cs new file mode 100644 index 0000000..878d9be --- /dev/null +++ b/Source/DealerSelection.Common/Interfaces/HttpClient/IHttpClientHandler.cs @@ -0,0 +1,8 @@ + + +namespace DealerSelection.Common.Interfaces.HttpClient; + +public interface IHttpClientHandler +{ + System.Net.Http.HttpClient GetHttpClient(); +} diff --git a/Source/DealerSelection.Common/Logging/ApiInfo.cs b/Source/DealerSelection.Common/Logging/ApiInfo.cs new file mode 100644 index 0000000..95ca810 --- /dev/null +++ b/Source/DealerSelection.Common/Logging/ApiInfo.cs @@ -0,0 +1,24 @@ +namespace DealerSelection.Common.Logging; + +public class ApiInfo +{ + public RequestInfo RequestInfo { get; set; } + //public CustomInfo CustomInfo { get; set; } + public ResponseInfo ResponseInfo { get; set; } + public ApiInfo(string httpMethod, string uriAccessed, string hostName, DateTime startDate) + { + RequestInfo = new RequestInfo(hostName, httpMethod, uriAccessed, startDate); + } + + public override string ToString() + { + return $"WebAPI {nameof(RequestInfo)}: {RequestInfo}, " + + //$"{nameof(CustomInfo)}: {CustomInfo}, " + + $"{nameof(ResponseInfo)}: {ResponseInfo}"; + } + + public bool IsValid() + { + return RequestInfo.BuId.GetValueOrDefault() > 0; + } +} diff --git a/Source/DealerSelection.Common/Logging/AzureLogHelper.cs b/Source/DealerSelection.Common/Logging/AzureLogHelper.cs new file mode 100644 index 0000000..cbaa555 --- /dev/null +++ b/Source/DealerSelection.Common/Logging/AzureLogHelper.cs @@ -0,0 +1,82 @@ +using DealerSelection.Common.Configuration; +using Newtonsoft.Json; +using System.Net; +using System.Security.Cryptography; +using System.Text; + +namespace DealerSelection.Common.Logging; + +public static class AzureLogHelper +{ + private static string aZureWorkspaceId = ConfigurationHelper.GetSetting("aZureWorkspaceId", true); + private static string aZureSharedKey = ConfigurationHelper.GetSetting("aZureSharedKey", true); + private static string aZureLogType = ConfigurationHelper.GetSetting("aZureLogType", true); + private static string aZureApiVersion = ConfigurationHelper.GetSetting("aZureApiVersion", true); + + public static void LogMessage(string message) + { + try + { + string azureLog = GetAzureLogFormatLog(message); + string requestUriString = $"https://{aZureWorkspaceId}.ods.opinsights.azure.com/api/logs?api-version={aZureApiVersion}"; + DateTime dateTime = DateTime.UtcNow; + string dateString = dateTime.ToString("r"); + string signature = GetSignature("POST", azureLog.Length, "application/json", dateString, "/api/logs"); + HttpWebRequest request = (HttpWebRequest)WebRequest.Create(requestUriString); + request.ContentType = "application/json"; + request.Method = "POST"; + request.Headers["Log-Type"] = aZureLogType; + request.Headers["x-ms-date"] = dateString; + request.Headers["Authorization"] = signature; + byte[] content = Encoding.UTF8.GetBytes(azureLog); + using (Stream requestStreamAsync = request.GetRequestStream()) + { + requestStreamAsync.Write(content, 0, content.Length); + } + using (HttpWebResponse responseAsync = (HttpWebResponse)request.GetResponse()) + { + if (responseAsync.StatusCode != HttpStatusCode.OK && responseAsync.StatusCode != HttpStatusCode.Accepted) + { + Stream responseStream = responseAsync.GetResponseStream(); + if (responseStream != null) + { + using (StreamReader streamReader = new StreamReader(responseStream)) + { + // throw new Exception(streamReader.ReadToEnd()); + } + } + } + } + } + catch (Exception ex) + { + // throw new UnexpectedDataException($" Bajaj Booking LogMessage: ", ex); + } + } + + private static string GetAzureLogFormatLog(string inputMessage) + { + string message = string.Empty; + if (!string.IsNullOrWhiteSpace(inputMessage)) + { + message = JsonConvert.SerializeObject( + new + { + id = Guid.NewGuid().ToString(), + datetime = DateTime.Now, + message = inputMessage + }).ToString(); + } + return message; + } + + private static string GetSignature(string method, int contentLength, string contentType, string date, string resource) + { + string message = $"{method}\n{contentLength}\n{contentType}\nx-ms-date:{date}\n{resource}"; + byte[] bytes = Encoding.UTF8.GetBytes(message); + using (HMACSHA256 encryptor = new HMACSHA256(Convert.FromBase64String(aZureSharedKey))) + { + return $"SharedKey {aZureWorkspaceId}:{Convert.ToBase64String(encryptor.ComputeHash(bytes))}"; + } + } +} diff --git a/Source/DealerSelection.Common/Logging/HttpHeaderHelper.cs b/Source/DealerSelection.Common/Logging/HttpHeaderHelper.cs new file mode 100644 index 0000000..a8fe9bc --- /dev/null +++ b/Source/DealerSelection.Common/Logging/HttpHeaderHelper.cs @@ -0,0 +1,28 @@ + +using Microsoft.Extensions.Primitives; + +namespace DealerSelection.Common.Logging; + +public class HttpHeaderHelper +{ + public static int? ExtractInt(string key, List> headers) + { + int? res = null; + string? resString = Extract(key, headers); + if (resString == null) + { + if(int.TryParse(resString, out int resTemp)) + res = resTemp; + } + return res; + } + + public static string? Extract(string key, List> headers) + { + string? res = null; + KeyValuePair header = headers.FirstOrDefault(h=> h.Key == key); + if (header.Value.Any()) + res = header.Value.FirstOrDefault(); + return res; + } +} diff --git a/Source/DealerSelection.Common/Logging/LoggingMiddleware.cs b/Source/DealerSelection.Common/Logging/LoggingMiddleware.cs new file mode 100644 index 0000000..5035cbb --- /dev/null +++ b/Source/DealerSelection.Common/Logging/LoggingMiddleware.cs @@ -0,0 +1,127 @@ + +using iTextSharp.text.log; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http.Extensions; +using Microsoft.IO; + +namespace DealerSelection.Common.Logging; + +public class LoggingMiddleware +{ + public const string Key = "LoggingMiddlewareCfg"; + private const int ReadChunkBufferLength = 4096; + private const int MaxContentLength = 10 * 1024 * 1024; //10MB + private RecyclableMemoryStreamManager MemoryStreamManager { get; set; } = null; + private readonly RequestDelegate RequestDelegate; + enum ErrorTypes + { + Validation, + Error + }; + + public LoggingMiddleware(RequestDelegate requestDelegate) + { + RequestDelegate = requestDelegate; + + MemoryStreamManager = new RecyclableMemoryStreamManager(); + } + + public async Task Invoke(HttpContext context, ILogger logger) + { + try + { + ApiInfo loggingInfo = await ExtractInfoFromRequest(context.Request); + + Stream originalBodyStream = context.Request.Body; + using MemoryStream responseBody = MemoryStreamManager.GetStream(); + context.Response.Body = responseBody; + + await RequestDelegate(context); + + ExtractMessageHeaderIntoInfo(loggingInfo, context.Request); + + if(await ExtractResponseInfo(loggingInfo, context.Response, originalBodyStream, logger)) + { + //logger.Info(loggingInfo.ToString()); + AzureLogHelper.LogMessage($"Api Incoming: {loggingInfo.ToString()}"); + } + } + catch { } + } + + private async Task ExtractInfoFromRequest(HttpRequest request) + { + ApiInfo info = new ApiInfo(request.Method, request.GetDisplayUrl(),Environment.MachineName,DateTime.Now); + + if(request.ContentLength.GetValueOrDefault() > 0) + { + request.EnableBuffering(); + + using MemoryStream requestStream = MemoryStreamManager.GetStream(); + await request.Body.CopyToAsync(requestStream); + info.RequestInfo.ContentBody = await ReadStreamInChunks(requestStream); + + request.Body.Position = 0; + } + return info; + } + + private async Task ReadStreamInChunks(Stream stream) + { + stream.Seek(0, SeekOrigin.Begin); + await using StringWriter textWriter = new StringWriter(); + using StreamReader reader = new StreamReader(stream); + char[] readChunk = new char[ReadChunkBufferLength]; + int readChunkLength; + do + { + readChunkLength = await reader.ReadBlockAsync(readChunk, 0, ReadChunkBufferLength); + await textWriter.WriteAsync(readChunk, 0, readChunkLength); + } while (readChunkLength > 0); + return textWriter.ToString(); + } + + private async Task ExtractResponseInfo(ApiInfo loggingInfo, HttpResponse response, Stream originalBodyStream, ILogger logger) + { + //loggingInfo.CustomInfo = new CustomInfo(response); + if(loggingInfo.IsValid()) + { + try + { + loggingInfo.ResponseInfo = new ResponseInfo(response); + response.Body.Seek(0, SeekOrigin.Begin); + + if(response.Body.Length < MaxContentLength) + loggingInfo.ResponseInfo.ContentBody = await new StreamReader(response.Body).ReadToEndAsync(); + else + loggingInfo.ResponseInfo.ContentBody = $"Size {response.Body.Length} too large to retrieve"; + } + catch (Exception ex) + { + logger.Error($"Exception logging request {@loggingInfo}, error {@ex}"); + return false; + } + + loggingInfo.ResponseInfo.ContentType = response.Headers.ContentType.Any() ? string.Join(",", response.Headers.ContentType) : null; + } + response.Body.Seek(0, SeekOrigin.Begin); + + await response.Body.CopyToAsync(originalBodyStream); + return loggingInfo.IsValid(); + } + + + private void ExtractMessageHeaderIntoInfo(ApiInfo apiInfo, HttpRequest request) + { + //List> headers = request.Headers.ToList(); + //apiInfo.RequestInfo.BuId = HttpHeaderHelper.ExtractInt(CustomInfo.BuId, headers); + //apiInfo.RequestInfo.RecordId = HttpHeaderHelper.ExtractInt(CustomInfo.RecordId, headers); + //apiInfo.RequestInfo.SecurityContext = HttpHeaderHelper.ExtractInt(CustomInfo.SecurityContext, headers); + //apiInfo.RequestInfo.InnerException = HttpHeaderHelper.ExtractInt(CustomInfo.InnerException, headers); + //apiInfo.RequestInfo.ExceptionStack = HttpHeaderHelper.ExtractInt(CustomInfo.ExceptionStack, headers); + //apiInfo.RequestInfo.RealException = HttpHeaderHelper.ExtractInt(CustomInfo.RealException, headers); + //apiInfo.RequestInfo.BuId = HttpHeaderHelper.ExtractInt(CustomInfo.BuId, headers); + //apiInfo.RequestInfo.BuId = HttpHeaderHelper.ExtractInt(CustomInfo.BuId, headers); + + } +} diff --git a/Source/DealerSelection.Common/Logging/RequestInfo.cs b/Source/DealerSelection.Common/Logging/RequestInfo.cs new file mode 100644 index 0000000..3394292 --- /dev/null +++ b/Source/DealerSelection.Common/Logging/RequestInfo.cs @@ -0,0 +1,42 @@ + +namespace DealerSelection.Common.Logging; + +public class RequestInfo +{ + public RequestInfo(string hostName, string httpMethod, string uri, DateTime startDate) + { + HostName = hostName; + HttpMethod = httpMethod; + Uri = uri; + StartDate = startDate; + } + + public string HostName { get; set; } + public string HttpMethod { get; set; } + public string Uri { get; set; } + public DateTime? StartDate { get; set; } + public int? RecordId { get; set; } + public int? BuId { get; set; } + public string? SecurityContext { get; set; } + public string? ContentBody { get; set; } + public string? ExceptionStack { get; set;} + public string? RealException { get; set; } + public string? InnerException { get; set; } + + public override string ToString() + { + return $"{nameof(BuId)}:{ BuId},{nameof(RecordId)}:{RecordId},{nameof(HostName)}:{HostName}," + + $"{nameof(HttpMethod)}:{HttpMethod},{nameof(Uri)}:{Uri},{nameof(StartDate)}:{StartDate}," + + $"{nameof(SecurityContext)}:{SecurityContext},{nameof(ContentBody)}:{ContentBody}," + + $"{nameof(ExceptionStack)}:{ExceptionStack},{nameof(RealException)}:{RealException},{nameof(InnerException)}:{InnerException}"; + } + + public string BuildRequestData() + { + if(string.IsNullOrWhiteSpace(ContentBody)) + { + return Uri; + } + return $"{Uri} with {ContentBody}"; + } +} diff --git a/Source/DealerSelection.Common/Logging/ResponseInfo.cs b/Source/DealerSelection.Common/Logging/ResponseInfo.cs new file mode 100644 index 0000000..aa4c878 --- /dev/null +++ b/Source/DealerSelection.Common/Logging/ResponseInfo.cs @@ -0,0 +1,37 @@ + +using Microsoft.AspNetCore.Http; +using System.Net; + +namespace DealerSelection.Common.Logging; + +public class ResponseInfo +{ + public ResponseInfo(HttpResponse response) + { + StatusCode = (HttpStatusCode)response.StatusCode; + + if (IsSuccessStatusCode) + IsSuccess = true; + else if (StatusCode >= HttpStatusCode.InternalServerError) + IsSuccess = false; + else + IsSuccess = null; + + TimeStamp = DateTime.Now; + } + + public bool IsSuccessStatusCode => (int)StatusCode >= 200 && (int)StatusCode <= 299; + public bool? IsSuccess { get; } + public HttpStatusCode StatusCode { get; } + public DateTime TimeStamp { get; } + public string? ContentBody { get; set; } + public string? ContentType { get; set; } + + public override string ToString() + { + return $"{nameof(StatusCode)}: {StatusCode}, " + + $"{nameof(TimeStamp)}: {TimeStamp}, " + + $"{nameof(ContentType)}: {ContentType} " + + (string.IsNullOrWhiteSpace(ContentBody)? null : $", {nameof(ContentBody)}: {ContentBody} "); + } +} diff --git a/Source/DealerSelection.Common/Middleware/SwaggerRootRoutingMiddleware.cs b/Source/DealerSelection.Common/Middleware/SwaggerRootRoutingMiddleware.cs new file mode 100644 index 0000000..c314540 --- /dev/null +++ b/Source/DealerSelection.Common/Middleware/SwaggerRootRoutingMiddleware.cs @@ -0,0 +1,34 @@ +using Microsoft.AspNetCore.Http; + +namespace DealerSelection.Common.Middleware; + +public class SwaggerRootRoutingMiddleware +{ + public const string SwaggerUrl = "help/ui"; + private readonly RequestDelegate _requestDelegate; + private string PathBase { get; } + + public SwaggerRootRoutingMiddleware(RequestDelegate requestDelegate) + { + _requestDelegate = requestDelegate; + PathBase = "/Booking/1.0"; + } + + public async Task Invoke(HttpContext context) + + { + if(context.Request.Method == "GET" && context.Request.Path.Value!.Contains("/index.html", StringComparison.OrdinalIgnoreCase) + && !context.Request.Path.Value.Contains($"{SwaggerUrl}/index.html", StringComparison.OrdinalIgnoreCase)) + { + +#if DEBUG + context.Response.Redirect($"{SwaggerUrl}/index.html"); +#else + context.Response.Redirect($"{PathBase}/{SwaggerUrl}/index.html"); +#endif + return; + } + + await _requestDelegate(context); + } +} diff --git a/Source/DealerSelection.Common/Profiler/PerformanceProfiler.cs b/Source/DealerSelection.Common/Profiler/PerformanceProfiler.cs new file mode 100644 index 0000000..b90ad10 --- /dev/null +++ b/Source/DealerSelection.Common/Profiler/PerformanceProfiler.cs @@ -0,0 +1,31 @@ +namespace DealerSelection.Common.Profiler +{ + public class PerformanceProfiler : IDisposable + { + private bool disposed; + + public PerformanceProfiler(string operationName) + { + Profiler.StartOperation($"Custom - {operationName}"); + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (!disposed) + { + if (disposing) + { + Profiler.EndOperation(); + } + + disposed = true; + } + } + } +} diff --git a/Source/DealerSelection.Common/Profiler/Profiler.cs b/Source/DealerSelection.Common/Profiler/Profiler.cs new file mode 100644 index 0000000..7d71df0 --- /dev/null +++ b/Source/DealerSelection.Common/Profiler/Profiler.cs @@ -0,0 +1,19 @@ +using System.Diagnostics; + +namespace DealerSelection.Common.Profiler +{ + public static class Profiler + { + private static Stopwatch watch; + public static void StartOperation(string operationName) + { + watch = System.Diagnostics.Stopwatch.StartNew(); + } + public static void EndOperation() + { + watch.Stop(); + var timeToExecute = watch.ElapsedMilliseconds; + + } + } +} diff --git a/Source/DealerSelection.DependencyInjection/ApiRegistry.cs b/Source/DealerSelection.DependencyInjection/ApiRegistry.cs new file mode 100644 index 0000000..96aff78 --- /dev/null +++ b/Source/DealerSelection.DependencyInjection/ApiRegistry.cs @@ -0,0 +1,35 @@ +using DealerSelection.Api; +using DealerSelection.Api.CommonUtil; +using DealerSelection.Api.Interface; +using DealerSelection.Common.HttpClient; +using DealerSelection.Common.Interfaces.HttpClient; +using Lamar; + +namespace DealerSelection.DependencyInjection; + +public class ApiRegistry : ServiceRegistry +{ + public ApiRegistry() + { + + For() + .Use() + .Singleton(); + + For() + .Use() + .Singleton(); + + For() + .Use() + .Singleton(); + + For() + .Use() + .Singleton(); + For() + .Use() + .Singleton(); + + } +} diff --git a/Source/DealerSelection.DependencyInjection/DealerSelection.DependencyInjection.csproj b/Source/DealerSelection.DependencyInjection/DealerSelection.DependencyInjection.csproj new file mode 100644 index 0000000..db4a522 --- /dev/null +++ b/Source/DealerSelection.DependencyInjection/DealerSelection.DependencyInjection.csproj @@ -0,0 +1,29 @@ + + + + net6.0 + enable + enable + + + + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + diff --git a/Source/DealerSelection.DependencyInjection/DependencyInjectionBootStrapper.cs b/Source/DealerSelection.DependencyInjection/DependencyInjectionBootStrapper.cs new file mode 100644 index 0000000..2d17d40 --- /dev/null +++ b/Source/DealerSelection.DependencyInjection/DependencyInjectionBootStrapper.cs @@ -0,0 +1,11 @@ +using Lamar; +namespace DealerSelection.DependencyInjection; + +public class DependencyInjectionBootStrapper : ServiceRegistry +{ + public DependencyInjectionBootStrapper() + { + IncludeRegistry(); + IncludeRegistry(); + } +} \ No newline at end of file diff --git a/Source/DealerSelection.DependencyInjection/InfrastructureRegistry.cs b/Source/DealerSelection.DependencyInjection/InfrastructureRegistry.cs new file mode 100644 index 0000000..8b8b1d2 --- /dev/null +++ b/Source/DealerSelection.DependencyInjection/InfrastructureRegistry.cs @@ -0,0 +1,37 @@ +using Lamar; + +using InfoBipRepo = DealerSelection.Api.Infrastructure.InfoBip; +using MulesoftRepo = DealerSelection.Api.Infrastructure.Mulesoft; +using AssignDealerRepo = DealerSelection.Api.Infrastructure.AssignDealer; +using Customerdetail = DealerSelection.Api.Infrastructure.CustomerDetail; +using JwtRepo = DealerSelection.Api.Infrastructure.Jwt; +namespace DealerSelection.DependencyInjection; + +public class InfrastructureRegistry : ServiceRegistry +{ + public InfrastructureRegistry() + { + + For() + .Use() + .Ctor().Is("BOOKING") + .Transient(); + + For() + .Use() + .Ctor().Is("BOOKING") + .Transient(); + + For() + .Use() + .Ctor().Is("BOOKING") + .Transient(); + + For() + .Use() + .Ctor().Is("BOOKING") + .Transient(); + + } + +} diff --git a/Source/DealerSelection.Infrastructure/AssignDealer/IAssignDealerRepository.cs b/Source/DealerSelection.Infrastructure/AssignDealer/IAssignDealerRepository.cs new file mode 100644 index 0000000..7dd09ab --- /dev/null +++ b/Source/DealerSelection.Infrastructure/AssignDealer/IAssignDealerRepository.cs @@ -0,0 +1,7 @@ + +namespace DealerSelection.Api.Infrastructure.AssignDealer; + +public interface IAssignDealerRepository +{ + +} \ No newline at end of file diff --git a/Source/DealerSelection.Infrastructure/AssignDealer/Repository.cs b/Source/DealerSelection.Infrastructure/AssignDealer/Repository.cs new file mode 100644 index 0000000..abff6b9 --- /dev/null +++ b/Source/DealerSelection.Infrastructure/AssignDealer/Repository.cs @@ -0,0 +1,17 @@ +using DealerSelection.Api.Models; +using DealerSelection.Common.Data.Dapper; +using Dapper; +using Microsoft.Extensions.Logging; +using System.Data; +using System.Data.SqlClient; +namespace DealerSelection.Api.Infrastructure.AssignDealer; + +public class Repository : RepositoryBaseDapperAsync, IAssignDealerRepository +{ + private readonly ILogger _logger; + public Repository(string cxnName, ILogger logger) : base(cxnName) + { + _logger = logger; + } + +} \ No newline at end of file diff --git a/Source/DealerSelection.Infrastructure/CustomerDetail/CustomerInfoDto.cs b/Source/DealerSelection.Infrastructure/CustomerDetail/CustomerInfoDto.cs new file mode 100644 index 0000000..a45e7c7 --- /dev/null +++ b/Source/DealerSelection.Infrastructure/CustomerDetail/CustomerInfoDto.cs @@ -0,0 +1,26 @@ +using DealerSelection.Api.Models; + +namespace DealerSelection.Api.Infrastructure.CustomerDetail; + +public class CustomerDealerInfoRequestDto +{ + public int BuId { get; set; } + public int RecordId { get; set; } + public int MobileNumber { get; set; } + public string ModelCode { get; set; } + public string ModelName { get; set; } + public string ModelVariant { get; set; } + public string DealerName { get; set; } + public string DealerCode { get; set; } + public string PinCode { get; set; } + public string Latitude { get; set; } + public string Longitude { get; set; } + public DealerSelectionJobStatus DealerSelectionJobStatus { get; set; } + + public string RequestDetail() + { + return $"BuId: {BuId}, RecordId: {RecordId}, MobileNumber: {MobileNumber}, ModelCode: {ModelCode}, " + + $"ModelName:{ModelName}, ModelVariant:{ModelVariant}, DealerName: {DealerName}, DealerCode: {DealerCode}, "+ + $"PinCode: {PinCode}, Latitude: {Latitude}, Longitude: {Longitude}, DealerSelectionJobStatus: {DealerSelectionJobStatus}"; + } +} diff --git a/Source/DealerSelection.Infrastructure/CustomerDetail/IRepository.cs b/Source/DealerSelection.Infrastructure/CustomerDetail/IRepository.cs new file mode 100644 index 0000000..0abd3cd --- /dev/null +++ b/Source/DealerSelection.Infrastructure/CustomerDetail/IRepository.cs @@ -0,0 +1,13 @@ +using DealerSelection.Api.Infrastructure.Mulesoft; +using DealerSelection.Api.Models; + +namespace DealerSelection.Api.Infrastructure.CustomerDetail; + +public interface IRepository +{ + Task UpdateDealerDetail(CustomerDealerInfoRequestDto customerInfo); + // Task GetCustomerData(); + Task GetCustomerData(int buid, int recordId); + Task IsDuplicateMobileNumber(int mobileNumber); + Task UpdateDealerSelectionJobStatus(int buId, int recordId, int mobileNumber, DealerSelectionJobStatus dealerSelectionJobStatus); +} \ No newline at end of file diff --git a/Source/DealerSelection.Infrastructure/CustomerDetail/Repository.cs b/Source/DealerSelection.Infrastructure/CustomerDetail/Repository.cs new file mode 100644 index 0000000..8196f16 --- /dev/null +++ b/Source/DealerSelection.Infrastructure/CustomerDetail/Repository.cs @@ -0,0 +1,116 @@ +using Dapper; +using DealerSelection.Api.Infrastructure.Mulesoft; +using DealerSelection.Api.Models; +using DealerSelection.Common.Data.Dapper; +using DealerSelection.Common.Exceptions; +using Microsoft.Extensions.Logging; +using System.Data; +using System.Data.SqlClient; + +namespace DealerSelection.Api.Infrastructure.CustomerDetail; + +public class Repository : RepositoryBaseDapperAsync, IRepository +{ + private readonly ILogger _logger; + public Repository(string cxnName, ILogger logger) : base(cxnName) + { + _logger = logger; + } + + + public async Task UpdateDealerDetail(CustomerDealerInfoRequestDto dto) + { + try + { + using (SqlConnection cxn = await OpenCxnAsync()) + { + int receivedBookingId = await cxn.ExecuteScalarAsync(Procedure.UpdateDealerDetails, + new + { + dto.BuId, + dto.RecordId, + dto.MobileNumber, + dto.ModelCode, + dto.ModelName, + dto.ModelVariant, + dto.DealerName, + dto.DealerCode, + dto.PinCode, + dto.Latitude, + dto.Longitude, + dto.DealerSelectionJobStatus + }, + commandType: CommandType.StoredProcedure); + return receivedBookingId; + } + } + catch (Exception ex) + { + _logger.LogError($"BU:- {dto.BuId}. Error at Repository:CustomerDetail in UpdateDealerDetail for Request: {dto.RequestDetail()}.", ex.StackTrace); + throw new UnexpectedDataException($"Error at Repository:CustomerDetail in UpdateDealerDetail for Request: {dto.RequestDetail()}.", ex); + } + } + + public async Task GetCustomerData(int buId, int recordId) + { + try + { + using (SqlConnection cxn = await OpenCxnAsync()) + { + IEnumerable cusotmerInfo = await cxn.QueryAsync(Procedure.GetCustomerDataForJob, + commandType: CommandType.StoredProcedure); + return cusotmerInfo.ToList().FirstOrDefault(); + } + } + catch (Exception ex) + { + _logger.LogError("Error at Repository:CustomerDetail in UpdateDealerDetail for Request: {customerInfo.RequestDetail()}.", ex.StackTrace); + throw new UnexpectedDataException($"Error at Repository:CustomerDetail in UpdateDealerDetail for Request: ", ex); + } + } + + public async Task IsDuplicateMobileNumber(int mobileNumber) + { + try + { + using (SqlConnection cxn = await OpenCxnAsync()) + { + bool isDuplicate = await cxn.QueryFirstAsync(Procedure.IsDuplicateMobileNumber, + new + { + mobileNumber + }, + commandType: CommandType.StoredProcedure); + return isDuplicate; + } + } + catch (Exception ex) + { + _logger.LogError($"Error at Repository:CustomerDetail in IsDuplicateMobileNumber for MobileNumber: {mobileNumber}. ErrorMessage", ex.StackTrace); + throw new DuplicateException($"Error at Repository:CustomerDetail in IsDuplicateMobileNumber for MobileNumber: {mobileNumber}."); + } + } + + + public async Task UpdateDealerSelectionJobStatus(int buId, int recordId, int mobileNumber, DealerSelectionJobStatus dealerSelectionJobStatus) + { + try + { + using (SqlConnection cxn = await OpenCxnAsync()) + { + await cxn.QueryFirstAsync(Procedure.UpdateDealerSelectionJobStatus, + new + { + buId, recordId, mobileNumber, dealerSelectionJobStatus + }, + commandType: CommandType.StoredProcedure); + } + } + catch (Exception ex) + { + _logger.LogError($"Error at Repository:CustomerDetail in UpdateDealerSelectionJobStatus for BuId: {buId}, RecordId: {recordId}, MobileNumber: {mobileNumber}, DealerSelectionJobStatus: {dealerSelectionJobStatus}. ErrorMessage", ex.StackTrace); + throw new DuplicateException($"Error at Repository:CustomerDetail in UpdateDealerSelectionJobStatus for BuId: {buId}, RecordId: {recordId}, MobileNumber: {mobileNumber}, DealerSelectionJobStatus: {dealerSelectionJobStatus}"); + } + } + +} \ No newline at end of file diff --git a/Source/DealerSelection.Infrastructure/DealerSelection.Api.Infrastructure.csproj b/Source/DealerSelection.Infrastructure/DealerSelection.Api.Infrastructure.csproj new file mode 100644 index 0000000..cc1c4f4 --- /dev/null +++ b/Source/DealerSelection.Infrastructure/DealerSelection.Api.Infrastructure.csproj @@ -0,0 +1,37 @@ + + + + net6.0 + enable + enable + + + + 1701;1702;8618;8603 + + + + 1701;1702;8618;8603 + + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + diff --git a/Source/DealerSelection.Infrastructure/InfoBip/IRepository.cs b/Source/DealerSelection.Infrastructure/InfoBip/IRepository.cs new file mode 100644 index 0000000..3f626a1 --- /dev/null +++ b/Source/DealerSelection.Infrastructure/InfoBip/IRepository.cs @@ -0,0 +1,6 @@ +namespace DealerSelection.Api.Infrastructure.InfoBip; + +public interface IRepository +{ + Task SaveResponse(int buId, string strMobile, string request_name, string api_request, string api_response, string error_message); +} \ No newline at end of file diff --git a/Source/DealerSelection.Infrastructure/InfoBip/Repository.cs b/Source/DealerSelection.Infrastructure/InfoBip/Repository.cs new file mode 100644 index 0000000..1bfb404 --- /dev/null +++ b/Source/DealerSelection.Infrastructure/InfoBip/Repository.cs @@ -0,0 +1,45 @@ +using DealerSelection.Api.Models; +using DealerSelection.Common.Data.Dapper; +using Dapper; +using Microsoft.Extensions.Logging; +using System.Data; +using System.Data.SqlClient; + + +namespace DealerSelection.Api.Infrastructure.InfoBip; + +public class Repository : RepositoryBaseDapperAsync, IRepository +{ + private readonly ILogger _logger; + public Repository(string cxnName, ILogger logger) : base(cxnName) + { + _logger = logger; + } + + public async Task SaveResponse(int buId, string strMobile, string request_name, string api_request, string api_response, string error_message) + { + try + { + using (SqlConnection cxn = await OpenCxnAsync()) + { + await cxn.ExecuteScalarAsync(@"insert into tbl_infobip_api_response(request_name,api_request,api_response,error_message) + values(@request_name,@api_request,@api_response,@error_message)", + new + { + request_name, + api_request, + api_response, + error_message + }, + commandType: CommandType.Text); + } + } + catch (Exception ex) + { + _logger.LogError("BU:- " + buId.ToString() + $"Error at Repository:InfoBip in SaveResponse for BuId: {buId}, Mobile: {strMobile}," + + $"request_name: {request_name}, api_request: {api_request}, api_response: {api_response}, error_message: {error_message}." + ex.Message.ToString()); + throw new UnexpectedDataException($"Error at Repository:InfoBip in SaveResponse for BuId: {buId}, Mobile: {strMobile}," + + $"request_name: {request_name}, api_request: {api_request}, api_response: {api_response}, error_message: {error_message}.", ex); + } + } +} \ No newline at end of file diff --git a/Source/DealerSelection.Infrastructure/Jwt/AuthValidateModelDto.cs b/Source/DealerSelection.Infrastructure/Jwt/AuthValidateModelDto.cs new file mode 100644 index 0000000..dc4110a --- /dev/null +++ b/Source/DealerSelection.Infrastructure/Jwt/AuthValidateModelDto.cs @@ -0,0 +1,14 @@ + +namespace DealerSelection.Api.Infrastructure.Jwt; + +public class AuthValidateModelDto +{ + public string ClientId { get; set; } + public string SecretId { get; set; } + public string BuId { get; set; } +} + +public class TokenModel +{ + public string Token { get; set; } +} diff --git a/Source/DealerSelection.Infrastructure/Jwt/IJwtRepository.cs b/Source/DealerSelection.Infrastructure/Jwt/IJwtRepository.cs new file mode 100644 index 0000000..d9b732e --- /dev/null +++ b/Source/DealerSelection.Infrastructure/Jwt/IJwtRepository.cs @@ -0,0 +1,9 @@ +using DealerSelection.Api.Models; +namespace DealerSelection.Api.Infrastructure.Jwt; + +public interface IJwtRepository +{ + Task GenerateToken(AuthModel user); + Task Authenticate(AuthValidateModelDto userLogin); + Task IsTokenExpired(string tokenValue); +} \ No newline at end of file diff --git a/Source/DealerSelection.Infrastructure/Jwt/JwtRepository.cs b/Source/DealerSelection.Infrastructure/Jwt/JwtRepository.cs new file mode 100644 index 0000000..1e00bce --- /dev/null +++ b/Source/DealerSelection.Infrastructure/Jwt/JwtRepository.cs @@ -0,0 +1,23 @@ +using DealerSelection.Api.Models; + + +namespace DealerSelection.Api.Infrastructure.Jwt; + +public class JwtRepository : IJwtRepository +{ + + public Task Authenticate(AuthValidateModelDto userLogin) + { + throw new NotImplementedException(); + } + + public Task GenerateToken(AuthModel user) + { + throw new NotImplementedException(); + } + + public Task IsTokenExpired(string tokenValue) + { + throw new NotImplementedException(); + } +} \ No newline at end of file diff --git a/Source/DealerSelection.Infrastructure/Mulesoft/DealerDetailDto.cs b/Source/DealerSelection.Infrastructure/Mulesoft/DealerDetailDto.cs new file mode 100644 index 0000000..27b4f04 --- /dev/null +++ b/Source/DealerSelection.Infrastructure/Mulesoft/DealerDetailDto.cs @@ -0,0 +1,26 @@ + +namespace DealerSelection.Api.Infrastructure.Mulesoft; + +public class DealerDetailDto +{ + public int BuId { get; set; } + public string DealerCode { get; set; } + public string Address1 { get; set; } + public string Address2 { get; set; } + public string City { get; set; } + public string State { get; set; } + public string Zip { get; set; } + public string DisplayName { get; set; } + public string ContactCard { get; set; } + public string SalesPersonMail { get; set; } + public string SaleMobileNumber { get; set; } + public string EcomSalesAddress { get; set; } + + public string RequestDetail() + { + return $"BuId: {BuId}, DealerCode: {DealerCode}, Address1: {Address1}, Address2: {Address2}, City: {City}, State: {State}, " + + $"Zip: {Zip}, DisplayName: {DisplayName}, ContactCard: {ContactCard}, SalesPersonMail: {SalesPersonMail}, " + + $"SaleMobileNumber: {SaleMobileNumber}, EcomSalesAddress: {EcomSalesAddress}."; + } +} + diff --git a/Source/DealerSelection.Infrastructure/Mulesoft/IRepository.cs b/Source/DealerSelection.Infrastructure/Mulesoft/IRepository.cs new file mode 100644 index 0000000..3a33a17 --- /dev/null +++ b/Source/DealerSelection.Infrastructure/Mulesoft/IRepository.cs @@ -0,0 +1,10 @@ + +namespace DealerSelection.Api.Infrastructure.Mulesoft; + +public interface IRepository +{ + Task GetCustomerInfo(int buId, string bookingId); + Task UpdateMulesoftResponse(int buId,int recordId,string bookingId,string message,string isSuccessBooking, LeadData leadData); + Task InsertAndUpdateDealerRecord(DealerDetailDto dto); + Task> GetDataForLsqPush(int buId); +} \ No newline at end of file diff --git a/Source/DealerSelection.Infrastructure/Mulesoft/MulesoftCustomerInfoDto.cs b/Source/DealerSelection.Infrastructure/Mulesoft/MulesoftCustomerInfoDto.cs new file mode 100644 index 0000000..00ca14f --- /dev/null +++ b/Source/DealerSelection.Infrastructure/Mulesoft/MulesoftCustomerInfoDto.cs @@ -0,0 +1,46 @@ + +using System; + +namespace DealerSelection.Api.Infrastructure.Mulesoft; + +public class MulesoftCustomerInfoDto +{ + public int BuId { get; set; } + public string BuName { get; set; } + public int RecordId { get; set; } + public string BookingId { get; set; } + public string CustomerName { get; set; } + public string MobileNumber { get; set; } + public string ModelCode { get; set; } + public string ModelName { get; set; } + public string ColorCode { get; set; } + public string DealerCode { get; set; } + public string DealerName { get; set; } + public bool IsRegisterInterestRequest { get; set; } + public string PinCode { get; set; } + public string UtmCustomDetails1 { get; set; } + public string UtmCustomDetails2 { get; set; } + public string Status { get; set; } + public string CCTransactionId { get; set; } + public string ReceiptId { get; set; } + public string AmountPaid { get; set; } + public string ReferralUrl { get; set; } + + public bool IsWhatsappOptIn { get; set; } + public int LeadTransferred { get; set; } + public string CustomerLat { get; set; } + public string CustomerLong { get; set; } + + +} + +public class LeadData +{ + public string Lead_transferred { get; set; } + public string Lead_status { get; set; } + public string Opportunity_id { get; set; } + public string Prospect_id { get; set; } + public string ApiResponse { get; set; } + public string LeadResponseStatus { get; set; } +} + diff --git a/Source/DealerSelection.Infrastructure/Mulesoft/Repository.cs b/Source/DealerSelection.Infrastructure/Mulesoft/Repository.cs new file mode 100644 index 0000000..601fe7f --- /dev/null +++ b/Source/DealerSelection.Infrastructure/Mulesoft/Repository.cs @@ -0,0 +1,134 @@ +using DealerSelection.Api.Models; +using DealerSelection.Common.Data.Dapper; +using Dapper; +using Microsoft.Extensions.Logging; +using System.Data; +using System.Data.SqlClient; +namespace DealerSelection.Api.Infrastructure.Mulesoft; + +public class Repository : RepositoryBaseDapperAsync, IRepository +{ + private readonly ILogger _logger; + public Repository(string cxnName, ILogger logger) : base(cxnName) + { + _logger = logger; + } + + public async Task GetCustomerInfo(int buId, string bookingId) + { + try + { + using (SqlConnection cxn = await OpenCxnWithMappingAsync()) + { + IEnumerable cusotmerInfo = await cxn.QueryAsync(Procedure.GetCustomerInfoOnBookingId, + new + { + buId, + bookingId + }, + commandType: CommandType.StoredProcedure); + return cusotmerInfo.ToList().FirstOrDefault(); + } + } + catch (Exception ex) + { + _logger.LogError("BU:- " + buId.ToString() + " Error at Repository:Mulesoft in GetCustomerInfo." + ex.Message.ToString()); + throw new UnexpectedDataException($"Error at Repository:Mulesoft in GetCustomerInfo for BuId: {buId} and BookingId: {bookingId}.", ex); + } + } + + public async Task UpdateMulesoftResponse(int buId, int recordId, string bookingId, string message, string isSuccessBooking, LeadData leadData) + { + try + { + using (SqlConnection cxn = await OpenCxnWithMappingAsync()) + { + await cxn.QueryAsync(Procedure.InsertLSQDetail, + new + { + buId, + recordId, + bookingId, + lead_Transferred = leadData.Lead_transferred, + lead_Status = leadData.Lead_status, + api_Request = message, + api_Response = leadData.ApiResponse, + lSQProspectId = leadData.Prospect_id, + lSQOpportunityId = leadData.Opportunity_id, + isSuccessBooking + }, + commandType: CommandType.StoredProcedure); + } + } + catch (Exception ex) + { + + _logger.LogError("BU:- " + buId.ToString() + $"Error at Repository:Mulesoft in UpdateMulesoftResponse for buId: {buId}, recordId: {recordId}, " + + $"leadData.Lead_transferred: {leadData.Lead_transferred}, message: {message},leadData.ApiResponse: {leadData.ApiResponse}, " + + $"leadData.Prospect_id:{leadData.Prospect_id}, leadData.Opportunity_id: {leadData.Opportunity_id}, " + + $"isSuccessBooking: {isSuccessBooking} " + ex.Message.ToString()); + + throw new UnexpectedDataException($"Error at Repository:Mulesoft in UpdateMulesoftResponse for buId: {buId}, recordId: {recordId}, " + + $"leadData.Lead_transferred: {leadData.Lead_transferred}, message: {message},leadData.ApiResponse: {leadData.ApiResponse}, " + + $"leadData.Prospect_id:{leadData.Prospect_id}, leadData.Opportunity_id: {leadData.Opportunity_id}, " + + $"isSuccessBooking: {isSuccessBooking} ", ex); + } + } + + public async Task InsertAndUpdateDealerRecord(DealerDetailDto dto) + { + try + { + using (SqlConnection cxn = await OpenCxnWithMappingAsync()) + { + await cxn.QueryAsync(Procedure.InsertUpdateDealerDetail, + new + { + dto.BuId, + dto.DealerCode, + dto.Address1, + dto.Address2, + dto.City, + dto.State, + dto.Zip, + dto.DisplayName, + dto.ContactCard, + dto.SalesPersonMail, + dto.SaleMobileNumber, + dto.EcomSalesAddress + + }, + commandType: CommandType.StoredProcedure); + + } + } + catch (Exception ex) + { + _logger.LogError("BU:- " + dto.BuId.ToString() + " Error at Repository:Mulesoft in InsertAndUpdateDealerRecord for InfoBip Request: {dto.RequestDetail()}" + ex.Message.ToString()); + throw new UnexpectedDataException($"Error at Repository:Mulesoft in InsertAndUpdateDealerRecord for InfoBip Request: {dto.RequestDetail()}", ex); + } + } + + public async Task> GetDataForLsqPush(int buId) + { + try + { + using (SqlConnection cxn = await OpenCxnAsync()) + { + IEnumerable lsqDto = await cxn.QueryAsync(Procedure.GetDataForLsqPush, + new + { + buId + }, + commandType: CommandType.StoredProcedure); + return lsqDto.ToList(); + } + } + catch (Exception ex) + { + _logger.LogError("BU:- " + buId.ToString() + "Error at Repository:Mulesoft in GetDataForLsqPush " + ex.Message.ToString()); + throw new UnexpectedDataException($"Error at Repository:Mulesoft in GetDataForLsqPush for BuId: {buId}.", ex); + } + + } +} \ No newline at end of file diff --git a/Source/DealerSelection.Interface/DealerSelection.Api.Interface.csproj b/Source/DealerSelection.Interface/DealerSelection.Api.Interface.csproj new file mode 100644 index 0000000..860db1c --- /dev/null +++ b/Source/DealerSelection.Interface/DealerSelection.Api.Interface.csproj @@ -0,0 +1,27 @@ + + + + net6.0 + enable + enable + + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + diff --git a/Source/DealerSelection.Interface/IAssignDealerApi.cs b/Source/DealerSelection.Interface/IAssignDealerApi.cs new file mode 100644 index 0000000..ba86ea9 --- /dev/null +++ b/Source/DealerSelection.Interface/IAssignDealerApi.cs @@ -0,0 +1,7 @@ +namespace DealerSelection.Api.Interface; + +public interface IAssignDealerApi +{ + Task GetCustomerDataForJob(int buId, int recordId); + +} \ No newline at end of file diff --git a/Source/DealerSelection.Interface/IInfoBipSmsServiceApi.cs b/Source/DealerSelection.Interface/IInfoBipSmsServiceApi.cs new file mode 100644 index 0000000..d95ec7a --- /dev/null +++ b/Source/DealerSelection.Interface/IInfoBipSmsServiceApi.cs @@ -0,0 +1,9 @@ +using Newtonsoft.Json.Linq; +namespace DealerSelection.Api.Interface; + +public interface IInfoBipSmsServiceApi +{ + Task sendOTP(int buId, string strMobile); + Task resendOTP(int buId, string strMobile, string strOtpPinId); + Task verifyOTP(int buId, string strMobile, string strOtpPinId, string otpPin); +} \ No newline at end of file diff --git a/Source/DealerSelection.Interface/IJwtTokenApi.cs b/Source/DealerSelection.Interface/IJwtTokenApi.cs new file mode 100644 index 0000000..38bcae3 --- /dev/null +++ b/Source/DealerSelection.Interface/IJwtTokenApi.cs @@ -0,0 +1,9 @@ +using DealerSelection.Api.Models; +namespace DealerSelection.Api.Interface; + +public interface IJwtTokenApi +{ + Task GenerateToken(AuthValidateModel user); + Task Authenticate(AuthValidateModel userLogin); + Task IsTokenExpired(string tokenValue); +} \ No newline at end of file diff --git a/Source/DealerSelection.Interface/IMulesoftApi.cs b/Source/DealerSelection.Interface/IMulesoftApi.cs new file mode 100644 index 0000000..e1cefd4 --- /dev/null +++ b/Source/DealerSelection.Interface/IMulesoftApi.cs @@ -0,0 +1,20 @@ +using DealerSelection.Api.Infrastructure.Mulesoft; +using DealerSelection.Api.Models; + +namespace DealerSelection.Api.Interface; + +public interface IMulesoftApi +{ + Task GetDealers(int buId, string buUnit, string strlat, string strLong); + Task GetAndInsertDealerDetails(int buId, string dealerCode); + Task GetStateWisePrice(int buId, string stateCode, string itemId); + Task GetModelOnBrand(int buId, string brand); + Task CallLSQBookingApi( MulesoftCustomerInfoDto customerInfo); + Task GetCustomerInfo(int buId, string bookingId); + Task> GetDataForLsqPush (int buId); + Task GetActiveState(int buId); + + Task GetActiveCity(int buId, string stateCode); + + Task ModelDetailsByItemCode(int buId, string itemId); +} \ No newline at end of file diff --git a/Source/DealerSelection.Interface/IMulesoftTokenApi.cs b/Source/DealerSelection.Interface/IMulesoftTokenApi.cs new file mode 100644 index 0000000..da20d80 --- /dev/null +++ b/Source/DealerSelection.Interface/IMulesoftTokenApi.cs @@ -0,0 +1,7 @@ + +namespace DealerSelection.Api.Interface; + +public interface IMulesoftTokenApi +{ + Task FetchToken(); +} diff --git a/Source/DealerSelection.Interface/IYellowAIApi.cs b/Source/DealerSelection.Interface/IYellowAIApi.cs new file mode 100644 index 0000000..df6082f --- /dev/null +++ b/Source/DealerSelection.Interface/IYellowAIApi.cs @@ -0,0 +1,10 @@ + +using DealerSelection.Api.Models; + +namespace DealerSelection.Api.Interface; + +public interface IYellowAIApi +{ + Task UpdateSelectedDealer(CustomerDealerInfoRequest request); + +} \ No newline at end of file diff --git a/Source/DealerSelection.WebApi.Models/BikeResponse.cs b/Source/DealerSelection.WebApi.Models/BikeResponse.cs new file mode 100644 index 0000000..5015c6a --- /dev/null +++ b/Source/DealerSelection.WebApi.Models/BikeResponse.cs @@ -0,0 +1,14 @@ +namespace DealerSelection.WebApi.Models; + +public class BikeResponse +{ + public string ItemId { get; set; } + public string ModelCode { get; set; } + public string ModelName { get; set; } + public string ModelDisplayName { get; set; } + public string ColorCode { get; set; } + public string ColorName { get; set; } + public string SKUCode { get; set; } + public string MasterCode { get; set; } + public string ImagePath { get; set; } +} \ No newline at end of file diff --git a/Source/DealerSelection.WebApi.Models/BookingConfirmationRequest.cs b/Source/DealerSelection.WebApi.Models/BookingConfirmationRequest.cs new file mode 100644 index 0000000..d3417ea --- /dev/null +++ b/Source/DealerSelection.WebApi.Models/BookingConfirmationRequest.cs @@ -0,0 +1,14 @@ + +namespace DealerSelection.WebApi.Models; + +public class BookingConfirmationRequest +{ + public int BuId { get; set; } + public int RecordId { get; set; } + public string BookingId { get; set; } + public string PaymentTransactionStatus { get; set; } + public string AmountPaid { get; set; } + public string PaymentTransactionId { get; set; } + public string PaymentType { get; set; } + public string CardName { get; set; } +} diff --git a/Source/DealerSelection.WebApi.Models/CityResponse.cs b/Source/DealerSelection.WebApi.Models/CityResponse.cs new file mode 100644 index 0000000..e9c29b8 --- /dev/null +++ b/Source/DealerSelection.WebApi.Models/CityResponse.cs @@ -0,0 +1,9 @@ +namespace DealerSelection.WebApi.Models; + +public class CityResponse +{ + public string CityName { get; set; } + public string IsUnionTerritory { get; set; } + public string StateName { get; set; } + +} \ No newline at end of file diff --git a/Source/DealerSelection.WebApi.Models/CustomerInfoMappingResponse.cs b/Source/DealerSelection.WebApi.Models/CustomerInfoMappingResponse.cs new file mode 100644 index 0000000..4a62e89 --- /dev/null +++ b/Source/DealerSelection.WebApi.Models/CustomerInfoMappingResponse.cs @@ -0,0 +1,26 @@ +namespace DealerSelection.WebApi.Models; + +public class CustomerInfoMappingResponse +{ + + public int Id { get; set; } + public int BuId { get; set; } + public string CustomerName { get; set; } + public string MobileNumber { get; set; } + public string ModelCode { get; set; } + public string ModelName { get; set; } + public string DealerLat { get; set; } + public string DealerLong { get; set; } + public string DealerCode { get; set; } + public string DealerAddress { get; set; } + public string DealerDisplayName { get; set; } + public string DealerMobileNumber { get; set; } + public string ColorCode { get; set; } + public string Location { get; set; } + public string PinCode { get; set; } + public string BikeImgPath { get; set; } + public bool IsWhatsappOptIn { get; set; } + public DateTime BookingDate { get; set; } + + +} diff --git a/Source/DealerSelection.WebApi.Models/CustomerInfoRequest.cs b/Source/DealerSelection.WebApi.Models/CustomerInfoRequest.cs new file mode 100644 index 0000000..277386d --- /dev/null +++ b/Source/DealerSelection.WebApi.Models/CustomerInfoRequest.cs @@ -0,0 +1,17 @@ + +namespace DealerSelection.WebApi.Models; + +public class CustomerDealerInfoRequest +{ + public int BuId { get; set; } + public int RecordId { get; set; } + public int MobileNumber { get; set; } + public string ModelCode { get; set; } + public string ModelName { get; set; } + public string ModelVariant { get; set; } + public string DealerName { get; set; } + public string DealerCode { get; set; } + public string PinCode { get; set; } + public string Latitude { get; set; } + public string Longitude { get; set; } +} diff --git a/Source/DealerSelection.WebApi.Models/DealerSelection.WebApi.Models.csproj b/Source/DealerSelection.WebApi.Models/DealerSelection.WebApi.Models.csproj new file mode 100644 index 0000000..5e3830f --- /dev/null +++ b/Source/DealerSelection.WebApi.Models/DealerSelection.WebApi.Models.csproj @@ -0,0 +1,20 @@ + + + + net6.0 + enable + enable + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + diff --git a/Source/DealerSelection.WebApi.Models/MulesoftResponse.cs b/Source/DealerSelection.WebApi.Models/MulesoftResponse.cs new file mode 100644 index 0000000..34c7cf3 --- /dev/null +++ b/Source/DealerSelection.WebApi.Models/MulesoftResponse.cs @@ -0,0 +1,34 @@ + +namespace DealerSelection.WebApi.Models; + +public class MulesoftResponse +{ + public int StatusCode { get; set; } + public bool IsRequestSuccessfull { get; set; } + public List Data { get; set; } + +} +public class MulesoftPriceResponse +{ + public int StatusCode { get; set; } + public bool IsRequestSuccessfull { get; set; } + public string ExPrice { get; set; } + +} + +public class Data +{ + public string DocumentId { get; set; } + public string Code { get; set; } + public bool IsBookingActive { get; set; } + public bool IsTestRideActive { get; set; } + public string Latitude { get; set; } + public string Longitude { get; set; } + public string DisplayName { get; set; } + public string CompanyName { get; set; } + public string CompanyCode { get; set; } + public bool IsActive { get; set; } + public string BranchName { get; set; } + public double Distance { get; set; } +} + diff --git a/Source/DealerSelection.WebApi.Models/PaymentLinkResponse.cs b/Source/DealerSelection.WebApi.Models/PaymentLinkResponse.cs new file mode 100644 index 0000000..53c17e6 --- /dev/null +++ b/Source/DealerSelection.WebApi.Models/PaymentLinkResponse.cs @@ -0,0 +1,7 @@ + +namespace DealerSelection.WebApi.Models; + +public class PaymentLinkResponse : Response +{ + public string SourceUrl { get; set; } +} diff --git a/Source/DealerSelection.WebApi.Models/RegisterInterestSuccessfulResponse.cs b/Source/DealerSelection.WebApi.Models/RegisterInterestSuccessfulResponse.cs new file mode 100644 index 0000000..b558df9 --- /dev/null +++ b/Source/DealerSelection.WebApi.Models/RegisterInterestSuccessfulResponse.cs @@ -0,0 +1,16 @@ + +namespace DealerSelection.WebApi.Models; + +public class RegisterInterestSuccessfullResponse +{ + public int BuId { get; set; } + public int RecordId { get; set; } + public string CustomerName { get; set; } + public string MobileNumber { get; set; } + public string ModelCode { get; set; } + public string ModelName { get; set; } + public string ColorCode { get; set; } + public string BikeImgPath { get; set; } + public string Location { get; set; } + +} diff --git a/Source/DealerSelection.WebApi.Models/Response.cs b/Source/DealerSelection.WebApi.Models/Response.cs new file mode 100644 index 0000000..24267eb --- /dev/null +++ b/Source/DealerSelection.WebApi.Models/Response.cs @@ -0,0 +1,12 @@ + +namespace DealerSelection.WebApi.Models; + +public class Response +{ + public int BuId { get; set; } + public int RecordId { get; set; } + public bool IsRequestSuccessfull { get; set; } + public string Result { get; set; } + public string Message { get; set; } + public string ErrorCode { get; set; } +} diff --git a/Source/DealerSelection.WebApi.Models/ReviewPayCustomerInfoResponse.cs b/Source/DealerSelection.WebApi.Models/ReviewPayCustomerInfoResponse.cs new file mode 100644 index 0000000..7162b7a --- /dev/null +++ b/Source/DealerSelection.WebApi.Models/ReviewPayCustomerInfoResponse.cs @@ -0,0 +1,24 @@ + +namespace DealerSelection.WebApi.Models; + +public class ReviewPayCustomerInfoResponse +{ + + public int BuId { get; set; } + public int RecordId { get; set; } + public string CustomerName { get; set; } + public string MobileNumber { get; set; } + public string ModelCode { get; set; } + public string ModelName { get; } + public string ColorCode { get; set; } + public string Location { get; } + public string DealerName { get; set; } + public string Amount { get; set; } + public string DealerCode { get; set; } + public string BikeImgPath { get; set; } + public string IsBookingDone { get; set; } + public string IsExpired { get; set; } + public string DealerAddress { get; set; } + public string DealerMobileNumber { get; set; } + public string DealerSalesEmail { get; set; } +} \ No newline at end of file diff --git a/Source/DealerSelection.WebApi.Models/StateResponse.cs b/Source/DealerSelection.WebApi.Models/StateResponse.cs new file mode 100644 index 0000000..aa497ca --- /dev/null +++ b/Source/DealerSelection.WebApi.Models/StateResponse.cs @@ -0,0 +1,8 @@ +namespace DealerSelection.WebApi.Models; + +public class StateResponse +{ + public string State { get; set; } + public string StateCode { get; set; } + +} \ No newline at end of file diff --git a/Source/DealerSelection.WebApi/.config/dotnet-tools.json b/Source/DealerSelection.WebApi/.config/dotnet-tools.json new file mode 100644 index 0000000..2be6730 --- /dev/null +++ b/Source/DealerSelection.WebApi/.config/dotnet-tools.json @@ -0,0 +1,12 @@ +{ + "version": 1, + "isRoot": true, + "tools": { + "dotnet-ef": { + "version": "7.0.9", + "commands": [ + "dotnet-ef" + ] + } + } +} \ No newline at end of file diff --git a/Source/DealerSelection.WebApi/App_Start/Mapper.cs b/Source/DealerSelection.WebApi/App_Start/Mapper.cs new file mode 100644 index 0000000..5231cd2 --- /dev/null +++ b/Source/DealerSelection.WebApi/App_Start/Mapper.cs @@ -0,0 +1,36 @@ +using AutoMapper; +using DealerSelection.WebApi.Models; + +namespace DealerSelection.WebApi; + +public static class MapperConfig +{ + private static MapperConfiguration Config { get; set; } + + public static void Register() + { + Config = new MapperConfiguration( + cfg => + { + cfg.CreateMap(); + cfg.CreateMap(); + cfg.CreateMap(); + }); + } + + public static Response MapResponse(Api.Models.Response from) + { + return Config.CreateMapper().Map(from); + } + + public static MulesoftResponse MapMulesoftResponse(Api.Models.MulesoftResponse from) + { + return Config.CreateMapper().Map(from); + } + + public static Api.Models.CustomerDealerInfoRequest MapCustomerDealerInfoRequest(CustomerDealerInfoRequest from) + { + return Config.CreateMapper().Map(from); + } + +} diff --git a/Source/DealerSelection.WebApi/App_Start/Startup.cs b/Source/DealerSelection.WebApi/App_Start/Startup.cs new file mode 100644 index 0000000..8dc41d7 --- /dev/null +++ b/Source/DealerSelection.WebApi/App_Start/Startup.cs @@ -0,0 +1,21 @@ +using DealerSelection.DependencyInjection; +using Lamar; +using Owin; + +namespace DealerSelection.WebApi; + +public class Startup : Common.CommonBaseClass.StartupBase +{ + protected override ServiceRegistry CreateDIRegistry() + { + MapperConfig.Register(); + return new DependencyInjectionBootStrapper(); + } + + public void Configuration(IAppBuilder app) + { + + } + + +} diff --git a/Source/DealerSelection.WebApi/App_Start/WebApiConfig.cs b/Source/DealerSelection.WebApi/App_Start/WebApiConfig.cs new file mode 100644 index 0000000..933a81a --- /dev/null +++ b/Source/DealerSelection.WebApi/App_Start/WebApiConfig.cs @@ -0,0 +1,26 @@ +using Microsoft.Owin.Security.OAuth; +using System.Web.Http; + +namespace DealerSelection.WebApi.App_Start; + +public class WebApiConfig +{ + public static void Register(HttpConfiguration config) + { + // Web API configuration and services + config.SuppressDefaultHostAuthentication(); + config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType)); + + // Web API routes + config.MapHttpAttributeRoutes(); + + config.Routes.MapHttpRoute( + name: "DefaultApi", + routeTemplate: "api/{controller}/{action}/{id}", + defaults: new + { + id = RouteParameter.Optional + } + ); + } +} diff --git a/Source/DealerSelection.WebApi/Controllers/DealerSelectionController.cs b/Source/DealerSelection.WebApi/Controllers/DealerSelectionController.cs new file mode 100644 index 0000000..9e86bba --- /dev/null +++ b/Source/DealerSelection.WebApi/Controllers/DealerSelectionController.cs @@ -0,0 +1,34 @@ +using DealerSelection.Api.Interface; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Swashbuckle.AspNetCore.Annotations; + +namespace DealerSelection.WebApi.Controllers; + +[ApiController] +[Route("DealerSelection")] +public class DealerSelectionController : ControllerBase +{ + + private IAssignDealerApi Api { get; } + public DealerSelectionController(IAssignDealerApi api) + { + Api = api; + } + + /// + /// + /// + /// + [Authorize] + [HttpPost] + [ProducesResponseType(StatusCodes.Status200OK)] + [SwaggerOperation(Tags = new[] { "DealerSelection" })] + [Route("DealerSelection")] + public async Task AssignDealer(int buId,int recordId) + { + // return 1; + + await Api.GetCustomerDataForJob( buId, recordId); + } +} \ No newline at end of file diff --git a/Source/DealerSelection.WebApi/Controllers/JWTAuthController.cs b/Source/DealerSelection.WebApi/Controllers/JWTAuthController.cs new file mode 100644 index 0000000..bbdc9b1 --- /dev/null +++ b/Source/DealerSelection.WebApi/Controllers/JWTAuthController.cs @@ -0,0 +1,48 @@ +using DealerSelection.Api.Interface; +using DealerSelection.Api.Models; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Swashbuckle.AspNetCore.Annotations; + +namespace BajajAutoBooking.WebApi.Controllers +{ + [ApiController] + [Route("JWTAuth")] + public class JWTAuthController : ControllerBase + { + private readonly ILogger _logger; + private IJwtTokenApi Api { get; } + + public JWTAuthController(IJwtTokenApi api, ILogger logger) + { + Api = api; + _logger = logger; + } + + /// + /// GetAuthToken + /// + /// + /// + [AllowAnonymous] + [HttpPost] + [SwaggerOperation(Tags = new[] { "JWTAuth" })] + [Route("GetAuthToken")] + public async Task> GetAuthToken(AuthValidateModel userLogin) + { + string token = await Api.GenerateToken(userLogin); + + return token; + } + + [HttpPost] + [Route("IsValid")] + public async Task> IsValid(TokenModel request) + { + TokenValidProperty tokenValid = await Api.IsTokenExpired(request.Token); + return tokenValid; + } + + + } +} diff --git a/Source/DealerSelection.WebApi/Controllers/JWTAuthController.cs.bak b/Source/DealerSelection.WebApi/Controllers/JWTAuthController.cs.bak new file mode 100644 index 0000000..5f0d3e8 --- /dev/null +++ b/Source/DealerSelection.WebApi/Controllers/JWTAuthController.cs.bak @@ -0,0 +1,43 @@ +using BajajAutoBooking.Api.Interface; +using BajajAutoBooking.Common.Authentication; +using iTextSharp.tool.xml.html; +using Microsoft.AspNetCore.Mvc; +using Swashbuckle.AspNetCore.Annotations; +using System.Web.Http; + +namespace BajajAutoBooking.WebApi.Controllers +{ + [ApiController] + [Microsoft.AspNetCore.Mvc.Route("JWTAuth")] + public class JWTAuthController : ControllerBase + { + private readonly IConfiguration _config; + + public JWTAuthController(IConfiguration configuration) + { + _config = configuration; + } + + /// + /// GetAuthToken + /// + /// + /// + [AllowAnonymous] + [Microsoft.AspNetCore.Mvc.HttpPost] + [SwaggerOperation(Tags = new[] { "JWTAuth" })] + [Microsoft.AspNetCore.Mvc.Route("GetAuthToken")] + public ActionResult GetAuthToken(AuthValidateModel userLogin) + { + string token = string.Empty; + AuthenticationHelper helper = new AuthenticationHelper(_config); + AuthModel userInfo = helper.Authenticate(userLogin); + if (userInfo != null) + { + token = helper.GenerateToken(userInfo); + } + return token; + } + + } +} diff --git a/Source/DealerSelection.WebApi/Controllers/MulesoftController.cs b/Source/DealerSelection.WebApi/Controllers/MulesoftController.cs new file mode 100644 index 0000000..9ab5f87 --- /dev/null +++ b/Source/DealerSelection.WebApi/Controllers/MulesoftController.cs @@ -0,0 +1,87 @@ +using DealerSelection.Api.Interface; +using DealerSelection.WebApi.Models; +using Microsoft.AspNetCore.Mvc; +using Swashbuckle.AspNetCore.Annotations; +using System.ComponentModel.DataAnnotations; +using Model = DealerSelection.Api.Models; +using Microsoft.AspNetCore.Authorization; +using DealerSelection.Api.Infrastructure.Mulesoft; +using Microsoft.Extensions.Caching.Memory; + +namespace DealerSelection.WebApi.Controllers; + +[ApiController] +[Route("Mulesoft")] +public class MulesoftController : ControllerBase +{ + + private readonly ILogger _logger; + private readonly IMemoryCache _memoryCache; + private IMulesoftApi Api { get; } + public MulesoftController(IMemoryCache memoryCache, IMulesoftApi api, + ILogger logger) + { + Api = api; + _memoryCache = memoryCache; + _logger = logger; + } + + /// + /// Get Dealers + /// + /// + /// + /// + /// + /// + [Authorize] + [HttpGet] + [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(string))] + [SwaggerOperation(Tags = new[] { "Mulesoft" })] + [Route("GetDealers")] + public async Task> GetDealers([Required] int buId,[Required] string buUnit,[Required] string latitude,[Required] string longitude) + { + Model.MulesoftResponse responseApi = await Api.GetDealers(buId, buUnit, latitude, longitude); + return responseApi.Result; + } + + /// + /// Get Delear Master Details + /// + /// + /// + /// + [Authorize] + [HttpGet] + [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(string))] + [SwaggerOperation(Tags = new[] { "Mulesoft" })] + [Route("GetDealersDetail")] + public async Task> GetDealersDetail([Required] int buId,[Required] string dealerCode) + { + Model.MulesoftResponse responseApi = await Api.GetAndInsertDealerDetails(buId, dealerCode); + return responseApi.Result; + } + + + + /// + /// Call Booking API + /// + /// + /// + /// + [Authorize] + [HttpGet] + [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(MulesoftResponse))] + [SwaggerOperation(Tags = new[] { "Mulesoft" })] + [Route("MulesoftBookingApi")] + public async Task> CallBookingApi([Required] int buId, [Required] string bookingId) + { + MulesoftCustomerInfoDto customerInfo = await Api.GetCustomerInfo(buId, bookingId); + var responseApi = await Api.CallLSQBookingApi(customerInfo); + Response response = MapperConfig.MapResponse(responseApi); + return response; + } + + +} \ No newline at end of file diff --git a/Source/DealerSelection.WebApi/Controllers/TestController.cs b/Source/DealerSelection.WebApi/Controllers/TestController.cs new file mode 100644 index 0000000..83e9aaa --- /dev/null +++ b/Source/DealerSelection.WebApi/Controllers/TestController.cs @@ -0,0 +1,22 @@ +using DealerSelection.Api.Interface; +using DealerSelection.WebApi.Models; +using Microsoft.AspNetCore.Mvc; +using Swashbuckle.AspNetCore.Annotations; +using Model = DealerSelection.Api.Models; +using Microsoft.AspNetCore.Authorization; + +namespace DealerSelection.WebApi.Controllers; + +[ApiController] +[Route("")] +public class TestController : ControllerBase +{ + + public TestController() + { + + } + + + +} diff --git a/Source/DealerSelection.WebApi/Controllers/YellowController.cs b/Source/DealerSelection.WebApi/Controllers/YellowController.cs new file mode 100644 index 0000000..7f541c5 --- /dev/null +++ b/Source/DealerSelection.WebApi/Controllers/YellowController.cs @@ -0,0 +1,34 @@ +using DealerSelection.Api.Interface; +using DealerSelection.WebApi.Models; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Swashbuckle.AspNetCore.Annotations; + +namespace DealerSelection.WebApi.Controllers; + +[ApiController] +[Route("YellowAI")] +public class YellowController : ControllerBase +{ + + private IYellowAIApi Api { get; } + public YellowController(IYellowAIApi api) + { + Api = api; + } + + /// + /// + /// + /// + [Authorize] + [HttpGet] + [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(string))] + [SwaggerOperation(Tags = new[] { "YellowAI" })] + [Route("UpdateSelectedDealer")] + public async Task UpdateSelectedDealer(CustomerDealerInfoRequest customerDealerInfoRequest) + { + Api.Models.CustomerDealerInfoRequest request = MapperConfig.MapCustomerDealerInfoRequest(customerDealerInfoRequest); + await Api.UpdateSelectedDealer(request); + } +} \ No newline at end of file diff --git a/Source/DealerSelection.WebApi/DealerSelection.WebApi.csproj b/Source/DealerSelection.WebApi/DealerSelection.WebApi.csproj new file mode 100644 index 0000000..e063550 --- /dev/null +++ b/Source/DealerSelection.WebApi/DealerSelection.WebApi.csproj @@ -0,0 +1,171 @@ + + + + net6.0 + enable + enable + True + + + + 1701;1702;1591 + + + + 1701;1702;1591 + + + + + + + + + + + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + + diff --git a/Source/DealerSelection.WebApi/Program.cs b/Source/DealerSelection.WebApi/Program.cs new file mode 100644 index 0000000..fe86498 --- /dev/null +++ b/Source/DealerSelection.WebApi/Program.cs @@ -0,0 +1,11 @@ +using DealerSelection.Common.Configuration; +using DealerSelection.WebApi; + +ConfigurationHelper.SetEnvironmentVariables("appsettings.json"); +var startup = new Startup(); + +WebApplication app = startup.CreateHostBuilder(args); +//WebHost.CreateDefaultBuilder().UseStartup().Build().Run(); + + +app.Run(); diff --git a/Source/DealerSelection.WebApi/Properties/launchSettings.json b/Source/DealerSelection.WebApi/Properties/launchSettings.json new file mode 100644 index 0000000..2676ddf --- /dev/null +++ b/Source/DealerSelection.WebApi/Properties/launchSettings.json @@ -0,0 +1,31 @@ +{ + "profiles": { + "DealerSelectionAPI": { + "commandName": "Project", + "launchBrowser": true, + "launchUrl": "help/ui", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "dotnetRunMessages": true, + "applicationUrl": "https://localhost:7122;http://localhost:5081" + }, + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "launchUrl": "help/ui", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + }, + "$schema": "https://json.schemastore.org/launchsettings.json", + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:38064", + "sslPort": 44393 + } + } +} \ No newline at end of file diff --git a/Source/DealerSelection.WebApi/appsettings-PreProd.Development.json b/Source/DealerSelection.WebApi/appsettings-PreProd.Development.json new file mode 100644 index 0000000..0c208ae --- /dev/null +++ b/Source/DealerSelection.WebApi/appsettings-PreProd.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/Source/DealerSelection.WebApi/appsettings-PreProd.json b/Source/DealerSelection.WebApi/appsettings-PreProd.json new file mode 100644 index 0000000..9a86239 --- /dev/null +++ b/Source/DealerSelection.WebApi/appsettings-PreProd.json @@ -0,0 +1,134 @@ +{ + "BrowseSwagger": true, + "CCAvenuePayUrl": "https://test.ccavenue.com", + "CCAvenueApiPayUrl": "https://apitest.ccavenue.com", + "WebsiteDomain": "https://ktm-preprod.bajajauto.com", + "aZureWorkspaceId": "4247310d-8a93-4d54-8da5-505aa28817f1", + "aZureSharedKey": "Rzbo3gQ6Y/ltNuWITVkhQKnlNolNxKzXSQLWYy9BNjFvClTXOByXqxyNmoGVp2QWXZlf9eWBiew1VnNj1jb3Eg==", + "aZureLogType": "ASP_CL", + "aZureApiVersion": "2016-04-01", + "pdfBaseUrl": "https://booking-preprod.bajajauto.com/", + "masterSchemaId": "609ea70c-2e28-472e-bad4-bd5fab0ed5c3", + "masterDealerDetailSchemaId": "419620e3-e716-488e-ac07-12b3bbcc6032", + "muleSoftAPIClientID": "4153b3740b224f32a1067cc57b0e155a", + "muleSoftAIPClientSecret": "117DC02882284F93a0b541a7151C9aE2", + "muleSoftGenerateTokenURL": "https://apiqa.bajajauto.com/oauth-app-qa/api/v1", + "muleSoftAPIDomain": "https://apiqa.bajajauto.com/aggregator/dealer/api/v1/cdms/nearest-dealers", + "muleSoftDealerDetail": "https://apiqa.bajajauto.com/aggregator/dealer/api/v1/cdms/dealer-by-branch-code", + "muleSoftBookingAPILeadSquareDomain": "https://apiqa.bajajauto.com/web/booking/api/v1/lsq/create", + "muleSoftAPILeadSquareDomain": "https://apiqa.bajajauto.com/web/lead/api/v1", + "muleSoftStateWisePrice": "https://apiqa.bajajauto.com/aggregator/pricing/api/v1/cdms/model-price-by-state", + "muleSoftStateWisePricemasterSchemaId": "24349d3f-aa51-45a1-b322-9171250c4266", + "muleSoftBrandWiseModel": "https://apiqa.bajajauto.com/aggregator/product/api/v1/cdms/models-by-brand", + "muleSoftBrandWiseModelmasterSchemaId": "f87246d2-a5e1-4b3c-912d-6925034da347", + "muleSoftStateMasterSchemaId": "dfb36d56-7640-4b8b-a4a6-3849716140b4", + "muleSoftStateMasterSchemaApi": "https://apiqa.bajajauto.com/aggregator-xapi-qa/api/v1/cdms/get-active-states", + "muleSoftCityMasterSchemaId": "dfb36d56-7640-4b8b-a4a6-3849716140b4", + "muleSoftCityMasterSchemaApi": "https://apiqa.bajajauto.com/aggregator-xapi-qa/api/v1/cdms/get-active-cities", + "muleSoftModelMasterSchemaItemId": "f87246d2-a5e1-4b3c-912d-6925034da347", + "muleSoftModelMasterSchemaItemApi": "https://apiqa.bajajauto.com/aggregator/product/api/v1/cdms/model-details-by-item-code", + "MuleSoftCacheGetDealers": "30", + "MuleSoftCacheGetDealersDetail": "30", + "MuleSoftCacheGetPriceOnState": "30", + "MuleSoftCacheGetModelOnBrand": "30", + "MuleSoftCacheMulesoftBookingApi": "30", + "MuleSoftCacheGetActiveState": "30", + "MuleSoftCacheGetActiveCity": "30", + "MuleSoftCacheModelDetails": "30", + "KtmCfg": { + "Buid": 1, + "BuCode": "PB", + "ValidateDuplicate": "true", + "ValidateDuplicateHr": 1, + "CCAvenueAccessCode": "AVMM05KI16AB01MMBA", + "CCAvenueMerchantCode": "350479", + "CCAvenueBaseUrl": "https://ktm-preprod.bajajauto.com/booking-payment-confirmation", + "BookingPrice": "4499", + "CCAvenueWorkingKey": "DBE1BE94DE347D8CEA2BBE3AD546DF52", + "InfoBipAppilcationId": "60F6C124CF5046E4C3ABCBD6FBB1ADDF", + "InfoBipMessageId": "124F63476054C62171E6A7967C11140E", + "InfoBipFrom": "KTMIND", + "LandingPageUrl": "https://ktm-preprod.bajajauto.com/booking", + "WebengageEventName": "KTM Booking Status", + "WebEngageLicenseCode": "~71680635", + "WebEngageAuthToken": "3b5e4004-cef4-4bde-86c6-c8a9944cd846", + "WebengageApiHost": "https://api.webengage.com/v1/accounts/", + "ClientId": "ee12e3d9cb9a4dc6af3599934cc4152b", + "ClientSecret": "92a2bede7b414cb19861efa3cc3a8c0d", + "Key": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9", + "Audience": "https://ktm-preprod.bajajauto.com", + "Issuer": "https://booking-dev.bajajauto.com/", + "Role": "Admin", + "ExpireMinutes": "30" + }, + "BajajCfg": { + "Buid": 2, + "BuCode": "MC", + "ValidateDuplicate": "true", + "ValidateDuplicateHr": 1, + "CCAvenueAccessCode": "AVNL05KI17AO75LNOA", + "CCAvenueMerchantCode": "350479", + "CCAvenueBaseUrl": "https://bajaj-preprod.bajajauto.com/booking-payment-confirmation", + "BookingPrice": "4499", + "CCAvenueWorkingKey": "A381A69AA83B8A13E92310E85CEA0937", + "InfoBipAppilcationId": "A9947BEB79BC4E081D2D75F69D32E180", + "InfoBipMessageId": "71589CC8ABEB0F5B17CCF7D32E970A0A", + "InfoBipFrom": "BAJAUT", + "LandingPageUrl": "https://bajaj-preprod.bajajauto.com/booking", + "WebengageEventName": "BA - Booking Status", + "WebEngageLicenseCode": "~71680635", + "WebEngageAuthToken": "3b5e4004-cef4-4bde-86c6-c8a9944cd846", + "WebengageApiHost": "https://api.webengage.com/v1/accounts/", + "ClientId": "ee12e3d9cb9a4dc6af3599934cc4152b", + "ClientSecret": "92a2bede7b414cb19861efa3cc3a8c0d", + "Key": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9", + "Audience": "https://bajaj-preprod.bajajauto.com", + "Issuer": "https://booking-dev.bajajauto.com/", + "Role": "Admin", + "ExpireMinutes": "30" + }, + "TriumphCfg": { + "Buid": 3, + "BuCode": "TRM", + "ValidateDuplicate": "false", + "ValidateDuplicateHr": 1, + "CCAvenueAccessCode": "AVEB04KE93CJ71BEJC", + "CCAvenueMerchantCode": "284786", + "CCAvenueBaseUrl": "https://www.ktm-uat2.bajajauto.com/booking-payment-confirmation", + "BookingPrice": "10000", + "CCAvenueWorkingKey": "C3673417B0712B2A4FE9618F7723C850", + "InfoBipAppilcationId": "5285F0C5B69C6BE6329E28388ABC47B7", + "InfoBipMessageId": "79A55D0C9D2B603193792064435F2F3D", + "InfoBipFrom": "TRIUMF", + "LandingPageUrl": "https://www.triumphindia-preprod.bajajauto.com", + "WebengageEventName": "TH Booking Status", + "WebEngageLicenseCode": "~71680635", + "WebEngageAuthToken": "3b5e4004-cef4-4bde-86c6-c8a9944cd846", + "WebengageApiHost": "https://api.webengage.com/v1/accounts/", + "ClientId": "ee12e3d9cb9a4dc6af3599934cc4152b", + "ClientSecret": "92a2bede7b414cb19861efa3cc3a8c0d", + "Key": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9", + "Audience": "https://www.triumphindia-preprod.bajajauto.com", + "Issuer": "https://booking-dev.bajajauto.com/", + "Role": "Admin", + "ExpireMinutes": "30" + }, + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*", + "IncludeErrorInResponse": true, + "ConnectionStrings": { + "AZURE_LOGGING": "InstrumentationKey=2fead737-737a-4241-9e66-dfc5391583ba;IngestionEndpoint=https://centralindia-0.in.applicationinsights.azure.com/;LiveEndpoint=https://centralindia.livediagnostics.monitor.azure.com/" + }, + "Jwt": { + "ExpireMinutes": "30", + "Key": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9", + "Issuer": "https://booking-dev.bajajauto.com/", + "Audience": "https://ktm-preprod.bajajauto.com/,https://bajaj-preprod.bajajauto.com/,https://www.triumphindia-preprod.bajajauto.com/" + + } +} diff --git a/Source/DealerSelection.WebApi/appsettings-Prod.Development.json b/Source/DealerSelection.WebApi/appsettings-Prod.Development.json new file mode 100644 index 0000000..0c208ae --- /dev/null +++ b/Source/DealerSelection.WebApi/appsettings-Prod.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/Source/DealerSelection.WebApi/appsettings-Prod.json b/Source/DealerSelection.WebApi/appsettings-Prod.json new file mode 100644 index 0000000..0b7515b --- /dev/null +++ b/Source/DealerSelection.WebApi/appsettings-Prod.json @@ -0,0 +1,139 @@ +{ + "BrowseSwagger": false, + "CCAvenuePayUrl": "https://secure.ccavenue.com", + "CCAvenueApiPayUrl": "https://api.ccavenue.com", + "WebsiteDomain": "https://www.ktmindia.com", + "aZureWorkspaceId": "ce325602-2461-42bd-8d00-8cbabdef6115", + "aZureSharedKey": "sHmJvWK++IruJAnJV7kaRN9MaIFmg6u8MLoeFnU5IS2jmrxnFQUdPqtZitOq9wctisHy2wrX5yxCcGvRCe2AHQ==", + "aZureLogType": "ASP_CL", + "aZureApiVersion": "2016-04-01", + + "pdfBaseUrl": "https://booking.bajajauto.com/", + "masterSchemaId": "609ea70c-2e28-472e-bad4-bd5fab0ed5c3", + "masterDealerDetailSchemaId": "419620e3-e716-488e-ac07-12b3bbcc6032", + + "muleSoftAPIClientID": "bf659e9b99db4f468d2c525ac9fd60ab", + "muleSoftAIPClientSecret": "Aa6362a22f544161BbD2322d3f1aDDdF", + "muleSoftStateWisePricemasterSchemaId": "24349d3f-aa51-45a1-b322-9171250c4266", + "muleSoftBrandWiseModelmasterSchemaId": "f87246d2-a5e1-4b3c-912d-6925034da347", + "muleSoftStateMasterSchemaId": "dfb36d56-7640-4b8b-a4a6-3849716140b4", + "muleSoftCityMasterSchemaId": "dfb36d56-7640-4b8b-a4a6-3849716140b4", + "muleSoftModelMasterSchemaItemId": "f87246d2-a5e1-4b3c-912d-6925034da347", + "muleSoftGenerateTokenURL": "https://api.bajajauto.com/oauth-app/api/v1", + "muleSoftAPIDomain": "https://api.bajajauto.com/aggregator/dealer/api/v1/cdms/nearest-dealers", + "muleSoftDealerDetail": "https://api.bajajauto.com/aggregator/dealer/api/v1/cdms/dealer-by-branch-code", + "muleSoftBookingAPILeadSquareDomain": "https://api.bajajauto.com/web/booking/api/v1/lsq/create", + "muleSoftAPILeadSquareDomain": "https://apiqa.bajajauto.com/web/lead/api/v1", + "muleSoftStateWisePrice": "https://api.bajajauto.com/aggregator/pricing/api/v1/cdms/model-price-by-state", + "muleSoftBrandWiseModel": "https://api.bajajauto.com/aggregator/product/api/v1/cdms/models-by-brand", + "muleSoftStateMasterSchemaApi": "https://api.bajajauto.com/aggregator/product/api/v1/cdms/get-active-states", + "muleSoftCityMasterSchemaApi": "https://api.bajajauto.com/aggregator/product/api/v1/cdms/get-active-cities", + "muleSoftModelMasterSchemaItemApi": "https://api.bajajauto.com/aggregator/product/api/v1/cdms/model-details-by-item-code", + "MuleSoftCacheGetDealers": "30", + "MuleSoftCacheGetDealersDetail": "30", + "MuleSoftCacheGetPriceOnState": "30", + "MuleSoftCacheGetModelOnBrand": "30", + "MuleSoftCacheMulesoftBookingApi": "30", + "MuleSoftCacheGetActiveState": "30", + "MuleSoftCacheGetActiveCity": "30", + "MuleSoftCacheModelDetails": "30", + "KtmCfg": { + "Buid": 1, + "BuCode": "PB", + "ValidateDuplicate": "true", + "ValidateDuplicateHr": 1, + "CCAvenueAccessCode": "AVBO09KI17AB45OBBA", + "CCAvenueMerchantCode": "350479", + "CCAvenueBaseUrl": "https://www.ktmindia.com/booking-payment-confirmation", + "BookingPrice": "4499", + "CCAvenueWorkingKey": "E35D39B2330BC9CB33C382EDE60FB9CE", + "InfoBipAppilcationId": "60F6C124CF5046E4C3ABCBD6FBB1ADDF", + "InfoBipMessageId": "124F63476054C62171E6A7967C11140E", + "InfoBipFrom": "KTMIND", + "LandingPageUrl": "https://www.ktmindia.com/booking", + "WebengageEventName": "KTM Booking Status", + "WebEngageLicenseCode": "~99198ab8", + "WebEngageAuthToken": "bc44d779-3920-4dfd-a12b-5a9c63550e2e", + "WebengageApiHost": "https://api.webengage.com/v1/accounts/", + "ClientId": "18aa3b842faa445caacc0a8e14c4f15b", + "ClientSecret": "a2e74e3a828248eca26146e14427666e", + "Key": "e8b16571598147329f71bba4a6b09639", + "Issuer": "https://booking.bajajauto.com/", + "Audience": "https://www.ktmindia.com/", + "Role": "Admin", + "ExpireMinutes": "30" + }, + "BajajCfg": { + "Buid": 2, + "BuCode": "MC", + "ValidateDuplicate": "true", + "ValidateDuplicateHr": 1, + "CCAvenueAccessCode": "AVCY04IC46AW64YCWA", + "CCAvenueMerchantCode": "350479", + "CCAvenueBaseUrl": "https://www.bajajauto.com/booking-payment-confirmation", + "BookingPrice": "4499", + "CCAvenueWorkingKey": "A9E1939F1456D3A29B2A076A350F19A2", + "InfoBipAppilcationId": "A9947BEB79BC4E081D2D75F69D32E180", + "InfoBipMessageId": "71589CC8ABEB0F5B17CCF7D32E970A0A", + "InfoBipFrom": "BAJAUT", + "LandingPageUrl": "https://www.bajajauto.com/booking", + "WebengageEventName": "BAJAJ Booking Status", + "WebEngageLicenseCode": "~99198ab8", + "WebEngageAuthToken": "bc44d779-3920-4dfd-a12b-5a9c63550e2e", + "WebengageApiHost": "https://api.webengage.com/v1/accounts/", + "ClientId": "18aa3b842faa445caacc0a8e14c4f15b", + "ClientSecret": "a2e74e3a828248eca26146e14427666e", + "Key": "e8b16571598147329f71bba4a6b09639", + "Issuer": "https://booking.bajajauto.com/", + "Audience": "https://www.ktmindia.com/", + "Role": "Admin", + "ExpireMinutes": "30" + + }, + "TriumphCfg": { + "Buid": 3, + "BuCode": "TRM", + "ValidateDuplicate": "true", + "ValidateDuplicateHr": 1, + "CCAvenueAccessCode": "AVEB04KE93CJ71BEJC", + "CCAvenueMerchantCode": "284786", + //"CCAvenueBaseUrl": "https://www.triumphindia-preprod.bajajauto.com", + "CCAvenueBaseUrl": "https://www.ktm-uat2.bajajauto.com/booking-payment-confirmation", + "BookingPrice": "10000", + "CCAvenueWorkingKey": "C3673417B0712B2A4FE9618F7723C850", + "InfoBipAppilcationId": "5285F0C5B69C6BE6329E28388ABC47B7", + "InfoBipMessageId": "79A55D0C9D2B603193792064435F2F3D", + "InfoBipFrom": "TRIUMF", + "LandingPageUrl": "https://www.triumphindia-preprod.bajajauto.com", + "WebengageEventName": "TH Booking Status", + "WebEngageLicenseCode": "~99198ab8", + "WebEngageAuthToken": "bc44d779-3920-4dfd-a12b-5a9c63550e2e", + "WebengageApiHost": "https://api.webengage.com/v1/accounts/", + "ClientId": "18aa3b842faa445caacc0a8e14c4f15b", + "ClientSecret": "a2e74e3a828248eca26146e14427666e", + "Key": "e8b16571598147329f71bba4a6b09639", + "Issuer": "https://booking.bajajauto.com/", + "Audience": "https://www.ktmindia.com/", + "Role": "Admin", + "ExpireMinutes": "30" + + }, + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*", + "IncludeErrorInResponse": true, + "ConnectionStrings": { + "AZURE_LOGGING": "InstrumentationKey=65f520ac-20e4-4db7-bdf6-aa8cc225c7ce;IngestionEndpoint=https://centralindia-0.in.applicationinsights.azure.com/;LiveEndpoint=https://centralindia.livediagnostics.monitor.azure.com/" + }, + "Jwt": { + "ExpireMinutes": "30", + "Key": "e8b16571598147329f71bba4a6b09639", + "Issuer": "https://booking.bajajauto.com/", + "Audience": "https://www.ktmindia.com/" + + } +} diff --git a/Source/DealerSelection.WebApi/appsettings.Development.json b/Source/DealerSelection.WebApi/appsettings.Development.json new file mode 100644 index 0000000..0c208ae --- /dev/null +++ b/Source/DealerSelection.WebApi/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/Source/DealerSelection.WebApi/appsettings.json b/Source/DealerSelection.WebApi/appsettings.json new file mode 100644 index 0000000..4a6dabf --- /dev/null +++ b/Source/DealerSelection.WebApi/appsettings.json @@ -0,0 +1,78 @@ +{ + "BrowseSwagger": true, + "WebsiteDomain": "https://www.ktm-uat2.bajajauto.com", + "aZureWorkspaceId": "4247310d-8a93-4d54-8da5-505aa28817f1", + "aZureSharedKey": "Rzbo3gQ6Y/ltNuWITVkhQKnlNolNxKzXSQLWYy9BNjFvClTXOByXqxyNmoGVp2QWXZlf9eWBiew1VnNj1jb3Eg==", + "aZureLogType": "ASP_CL", + "aZureApiVersion": "2016-04-01", + "masterSchemaId": "609ea70c-2e28-472e-bad4-bd5fab0ed5c3", + "masterDealerDetailSchemaId": "419620e3-e716-488e-ac07-12b3bbcc6032", + "muleSoftAPIClientID": "4153b3740b224f32a1067cc57b0e155a", + "muleSoftAIPClientSecret": "117DC02882284F93a0b541a7151C9aE2", + "muleSoftGenerateTokenURL": "https://apiqa.bajajauto.com/oauth-app-qa/api/v1", + "muleSoftAPIDomain": "https://apiqa.bajajauto.com/aggregator/dealer/api/v1/cdms/nearest-dealers", + "muleSoftDealerDetail": "https://apiqa.bajajauto.com/aggregator/dealer/api/v1/cdms/dealer-by-branch-code", + "muleSoftBookingAPILeadSquareDomain": "https://apiqa.bajajauto.com/web/booking/api/v1/lsq/create", + "muleSoftAPILeadSquareDomain": "https://apiqa.bajajauto.com/web/lead/api/v1", + "muleSoftStateWisePrice": "https://apiqa.bajajauto.com/aggregator/pricing/api/v1/cdms/model-price-by-state", + "muleSoftStateWisePricemasterSchemaId": "24349d3f-aa51-45a1-b322-9171250c4266", + "muleSoftBrandWiseModel": "https://apiqa.bajajauto.com/aggregator/product/api/v1/cdms/models-by-brand", + "muleSoftBrandWiseModelmasterSchemaId": "f87246d2-a5e1-4b3c-912d-6925034da347", + "muleSoftStateMasterSchemaId": "dfb36d56-7640-4b8b-a4a6-3849716140b4", + "muleSoftStateMasterSchemaApi": "https://apiqa.bajajauto.com/aggregator-xapi-qa/api/v1/cdms/get-active-states", + "muleSoftCityMasterSchemaId": "dfb36d56-7640-4b8b-a4a6-3849716140b4", + "muleSoftCityMasterSchemaApi": "https://apiqa.bajajauto.com/aggregator-xapi-qa/api/v1/cdms/get-active-cities", + "muleSoftModelMasterSchemaItemId": "f87246d2-a5e1-4b3c-912d-6925034da347", + "muleSoftModelMasterSchemaItemApi": "https://apiqa.bajajauto.com/aggregator/product/api/v1/cdms/model-details-by-item-code", + "MuleSoftCacheGetDealers": "30", + "MuleSoftCacheGetDealersDetail": "30", + "MuleSoftCacheGetPriceOnState": "30", + "MuleSoftCacheGetModelOnBrand": "30", + "MuleSoftCacheMulesoftBookingApi": "30", + "MuleSoftCacheGetActiveState": "30", + "MuleSoftCacheGetActiveCity": "30", + "MuleSoftCacheModelDetails": "30", + "KtmCfg": { + "Buid": 1, + "BuCode": "PB", + "ValidateDuplicate": "false", + "ValidateDuplicateHr": 1, + "CCAvenueAccessCode": "AVLM05KI16AB00MLBA", + "CCAvenueMerchantCode": "350479", + "CCAvenueBaseUrl": "https://www.ktm-uat2.bajajauto.com/booking-payment-confirmation", + "BookingPrice": "4499", + "CCAvenueWorkingKey": "F40694C5358CF9D2826C4545D6FAE337", + "InfoBipAppilcationId": "60F6C124CF5046E4C3ABCBD6FBB1ADDF", + "InfoBipMessageId": "124F63476054C62171E6A7967C11140E", + "InfoBipFrom": "KTMIND", + "LandingPageUrl": "https://www.ktm-uat2.bajajauto.com/booking", + "WebengageEventName": "KTM Booking Status", + "WebEngageLicenseCode": "~71680635", + "WebEngageAuthToken": "3b5e4004-cef4-4bde-86c6-c8a9944cd846", + "WebengageApiHost": "https://api.webengage.com/v1/accounts/", + "ClientId": "ee12e3d9cb9a4dc6af3599934cc4152b", + "ClientSecret": "92a2bede7b414cb19861efa3cc3a8c0d", + "Key": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9", + "Audience": "https://www.ktm-uat2.bajajauto.com", + "Issuer": "https://booking-dev.bajajauto.com/", + "Role": "Admin", + "ExpireMinutes": "30" + }, + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*", + "IncludeErrorInResponse": true, + "ConnectionStrings": { + "AZURE_LOGGING": "InstrumentationKey=2fead737-737a-4241-9e66-dfc5391583ba;IngestionEndpoint=https://centralindia-0.in.applicationinsights.azure.com/;LiveEndpoint=https://centralindia.livediagnostics.monitor.azure.com/" + }, + "Jwt": { + "ExpireMinutes": "30", + "Key": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9", + "Issuer": "https://booking-dev.bajajauto.com/", + "Audience": "https://www.ktm-uat2.bajajauto.com/,https://www.bajaj-uat2.bajajauto.com/,https://www.triumphindia-uat2.bajajauto.com/" + } +} diff --git a/Source/DealerSelection.WebApi/connectionString-PreProd.json b/Source/DealerSelection.WebApi/connectionString-PreProd.json new file mode 100644 index 0000000..b41b501 --- /dev/null +++ b/Source/DealerSelection.WebApi/connectionString-PreProd.json @@ -0,0 +1,8 @@ +{ + + "ConnectionStrings": { + "BOOKING": "user id=sqlAdmin;password=bFLW43%p40^;Data Source=mc-5f2bf602-449a-48b2-ae5a-5901-sql.database.windows.net,1433;Database=BookingStaging;", + "BAJAJ": "user id=sqlAdmin;password=bFLW43%p40^;Data Source=mc-5f2bf602-449a-48b2-ae5a-5901-sql.database.windows.net,1433;Database=bajaj;", + "AZURE_LOGGING": "InstrumentationKey=2fead737-737a-4241-9e66-dfc5391583ba;IngestionEndpoint=https://centralindia-0.in.applicationinsights.azure.com/;LiveEndpoint=https://centralindia.livediagnostics.monitor.azure.com/" + } +} \ No newline at end of file diff --git a/Source/DealerSelection.WebApi/connectionString-Prod.json b/Source/DealerSelection.WebApi/connectionString-Prod.json new file mode 100644 index 0000000..88a931b --- /dev/null +++ b/Source/DealerSelection.WebApi/connectionString-Prod.json @@ -0,0 +1,9 @@ +{ + + "ConnectionStrings": { + + "BAJAJ": "user id=sqlAdmin;password=bFLW43%p40^;Data Source=mc-5f2bf602-449a-48b2-ae5a-5901-sql.database.windows.net,1433;Database=bajaj;", + "BOOKING": "user id=sqlAdmin;password=xAw01%M%t2R;Data Source=mc-a85c8764-3d51-42b1-8600-7409-sql.database.windows.net,1433;Database=Booking;" + + } +} \ No newline at end of file diff --git a/Source/DealerSelection.WebApi/connectionString.json b/Source/DealerSelection.WebApi/connectionString.json new file mode 100644 index 0000000..f344134 --- /dev/null +++ b/Source/DealerSelection.WebApi/connectionString.json @@ -0,0 +1,8 @@ +{ + + "ConnectionStrings": { + "BOOKING": "user id=sqlAdmin;password=bFLW43%p40^;Data Source=mc-5f2bf602-449a-48b2-ae5a-5901-sql.database.windows.net,1433;Database=Booking;", + "BAJAJ": "user id=sqlAdmin;password=bFLW43%p40^;Data Source=mc-5f2bf602-449a-48b2-ae5a-5901-sql.database.windows.net,1433;Database=bajaj;", + "AZURE_LOGGING": "InstrumentationKey=2fead737-737a-4241-9e66-dfc5391583ba;IngestionEndpoint=https://centralindia-0.in.applicationinsights.azure.com/;LiveEndpoint=https://centralindia.livediagnostics.monitor.azure.com/" + } +} \ No newline at end of file diff --git a/Source/DealerSelection.WebApi/wwwroot/CustomContent/SwaggerHeader.css b/Source/DealerSelection.WebApi/wwwroot/CustomContent/SwaggerHeader.css new file mode 100644 index 0000000..3d00d12 --- /dev/null +++ b/Source/DealerSelection.WebApi/wwwroot/CustomContent/SwaggerHeader.css @@ -0,0 +1,32 @@ +/* swagger ui customization */ +img[alt="Swagger UI"] { + display: block; + -moz-box-sizing: border-box; + box-sizing: border-box; + content: url(../CustomContent/logo.png); + max-width: 100%; + max-height: 100%; + position: absolute; + left: 100px; +} + +.swagger-ui .topbar{ + background-color: white; +} + +.swagger-ui .topbar .download-url-wrapper .select-label { + color: black; +} + +.swagger-ui .info { + margin: 10px 0; +} + +.swagger-ui .scheme-container { + margin: -40px 0 0px; + padding: 10px 0; +} + +body { + background-color: white; +} \ No newline at end of file diff --git a/Source/DealerSelection.WebApi/wwwroot/CustomContent/logo.png b/Source/DealerSelection.WebApi/wwwroot/CustomContent/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..12902dfd565d4b1002afd58a7d9ef386902c7bf7 GIT binary patch literal 965 zcmV;$13LVPP)a4gAmD#Ny>weDIst`0{aySxDZw)v`nNIHSrvrP|ZC)HBk@xBy>eW z52#E;;AaXS#Og;5$1XEXi(j0>&^-Tx&;~Vi*%>B8z7FnHZQnb6loQ(KQw#MWCWR2! zTNei1ft_Pnln;auXs#rOv``nUJUe$x=7~)3`r4A%-%|aaZ9y>ibVFfrBHhhO7;+P_hQ23e8mU7Y^9X%f0Xpl` zS?Tqr1ncYMh8WpTjU@tQjwP+Y8VNkx1Cpr2!JAme zUc-aHtbMdT{#^oH8)1V^w^`D6WC)->ENtH0vx@!y;(*R1eMSrQ!dZcHjuYk{zCA`U zN~15oi?1i;SFXV2N6s%%8x8cla>WW2xcVWy%8{aCU2%*0!hNL3Z2{i~658V2?|8=> zfNel@zBFpJ3GPp8P;#Q%)!!TT)R~;baRWxvm=QFQ>ke-9|A zGa)CZCPYhe;7)Q$KJ>jkM{;HLS>^LKFx`j1>OxOU%a0WNosPxR2_<8Wg}lCNrWz`k zRW$=m^QtMmkSW~2q%n%cPWWV?Lc()V(s6r|>}BxR`XtluPPr(4@WViNYU zGG;zPH7=LK(mX#=t9DY^Q*+rrCUuq}g=RKPoOLkWO}2Pxo1kirQ@L!r5Ub__YB=k( n0zF@Id_;4ttG~_G`hf5sZpOHC?MOi?00000NkvXXu0mjfs|BWh literal 0 HcmV?d00001 diff --git a/Source/Tests/DealerSelection.WebApi.IntegrationTests/DealerSelection.WebApi.IntegrationTests.csproj b/Source/Tests/DealerSelection.WebApi.IntegrationTests/DealerSelection.WebApi.IntegrationTests.csproj new file mode 100644 index 0000000..f90732a --- /dev/null +++ b/Source/Tests/DealerSelection.WebApi.IntegrationTests/DealerSelection.WebApi.IntegrationTests.csproj @@ -0,0 +1,31 @@ + + + + net6.0 + enable + enable + + false + + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + ..\..\..\..\..\..\..\..\..\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.8\System.Data.Linq.dll + + + + diff --git a/Source/Tests/DealerSelection.WebApi.IntegrationTests/DetailsRequestController/BookingConfirmation/BookingConfirmationTest.cs b/Source/Tests/DealerSelection.WebApi.IntegrationTests/DetailsRequestController/BookingConfirmation/BookingConfirmationTest.cs new file mode 100644 index 0000000..e82d79e --- /dev/null +++ b/Source/Tests/DealerSelection.WebApi.IntegrationTests/DetailsRequestController/BookingConfirmation/BookingConfirmationTest.cs @@ -0,0 +1,90 @@ +using Microsoft.ApplicationBlocks.Data; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System.Data; +using System.Diagnostics; +using System.Text; + +namespace DealerSelection.WebApi.IntegrationTests.DetailsRequestController.BookingConfirmation; + +[TestClass] +public class BookingConfirmationTest +{ + [TestMethod] + public void TestMethod1() + { + var val = GetUTMDetails("", "utm_source"); + val = GetUTMDetails("", "utm_medium"); + val = GetUTMDetails("", "utm_campaign"); + val = GetUTMDetails("", "utm_content"); + + return; + + string apiUrl = "https://booking-dev.bajajauto.com/Details/BookingConfirmation"; + var handler = new SocketsHttpHandler + { + PooledConnectionLifetime = TimeSpan.FromMinutes(15) // Recreate every 15 minutes + }; + + HttpClient client = new HttpClient(handler); + client.DefaultRequestHeaders.Accept.Clear(); + client.DefaultRequestHeaders.Add("Authorization", "Bearer " + "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1laWRlbnRpZmllciI6ImVlMTJlM2Q5Y2I5YTRkYzZhZjM1OTk5MzRjYzQxNTJiIiwiaHR0cDovL3NjaGVtYXMubWljcm9zb2Z0LmNvbS93cy8yMDA4LzA2L2lkZW50aXR5L2NsYWltcy9yb2xlIjoiQWRtaW4iLCJleHAiOjE2OTQzNDM5NzYsImlzcyI6Imh0dHBzOi8vYm9va2luZy1kZXYuYmFqYWphdXRvLmNvbS8iLCJhdWQiOiJodHRwczovL3d3dy5rdG0tdWF0Mi5iYWphamF1dG8uY29tLyJ9.Rg5miSU6IVPNpGDNwW3tQwoEVHw_Dr0iMgZQI5ArM7c"); + client.DefaultRequestHeaders.Add("cache-control", "no-cache"); + client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json")); + Uri requestUri = new Uri(apiUrl); + + string bookConnectionString = "user id=sqlAdmin;password=bFLW43%p40^;Data Source=mc-5f2bf602-449a-48b2-ae5a-5901-sql.database.windows.net,1433;Database=Booking;"; + int buId = 1; + string transactionalsql = $"select BookingId, RecordId from tbl_transaction_details where Buid={buId} AND BookingId <>'0' AND Status <> 'Successful' order by RecordId asc"; + DataTable bookingobjDataTable = SqlHelper.ExecuteDataset(bookConnectionString, CommandType.Text, transactionalsql).Tables[0]; + + var stopwatch = new Stopwatch(); + stopwatch.Start(); + Console.WriteLine($"Bulk Testing started at : {DateTime.Now}."); + List tasks = new List(); + + if (bookingobjDataTable != null & bookingobjDataTable.Rows != null) + { + foreach (DataRow row in bookingobjDataTable.Rows) + { + string recordId = Convert.ToString(row["RecordId"]); + string bookingId = Convert.ToString(row["BookingId"]); + string data = "{\r\n \"buId\": "+buId+",\r\n \"recordId\": "+ recordId + ",\r\n \"bookingId\": \""+ bookingId + "\",\r\n \"paymentTransactionStatus\": \"success\",\r\n \"amountPaid\": \"1\",\r\n \"paymentTransactionId\": \"Test-"+ recordId + "\",\r\n \"paymentType\": \"Card\",\r\n \"cardName\": \"VISA\"\r\n}"; + Console.WriteLine($"BuId: {buId} , BookingId: {bookingId} , RecordId: {recordId} Processed"); + + BookingController(client, requestUri, data); + + //tasks.Add(BookingController(client, requestUri, data)); + } + } + + //It will execute all the tasks concurrently + Task.WhenAll(tasks); + stopwatch.Stop(); + Console.WriteLine($"Processing of {bookingobjDataTable.Rows.Count} BookingId Done in {stopwatch.ElapsedMilliseconds / 1000.0} Seconds"); + } + + public static async Task BookingController(HttpClient client, Uri requestUri, string data) + { + var response = await client.PostAsync(requestUri, new StringContent(data, Encoding.UTF8, "application/json")); + + } + + private string GetUTMDetails(string referrerUrl, string utmName) + { + referrerUrl = "https://www.triumphmotorcyclesindia.com/?utm_medium=cpc&utm_campaign=Sok_TriumphSpeed400_PMAX_Leads_02082023&utm_id=20423312638&adgroup=&utm_customdetails=AssetGroup1&utm_term=&utm_source_platform=x&utm_customdetails1=Speed_Booking_D2C&utm_customdetails2=Display_Google&gad=1&gclid=CjwKCAjwsKqoBhBPEiwALrrqiP8FJ2m-dbUdgg7GRZE2t71BmNcCQ3q6mHce20EP24Yg3iikzk1ceRoCW18QAvD_BwE"; + + Uri bUri = new Uri(referrerUrl); + + var query = bUri.Query.Replace("?", ""); + + var queryValues = query.Split('&').Select(q => q.Split('=')) + .ToDictionary(k => k[0], v => v[1]); + if (queryValues.ContainsKey(utmName)) + return queryValues[utmName]; + + + return ""; + + + } +} \ No newline at end of file diff --git a/Source/Tests/DealerSelection.WebApi.IntegrationTests/GivenRoot.cs b/Source/Tests/DealerSelection.WebApi.IntegrationTests/GivenRoot.cs new file mode 100644 index 0000000..e69de29 diff --git a/Source/WebJobService/IService.cs b/Source/WebJobService/IService.cs new file mode 100644 index 0000000..759152e --- /dev/null +++ b/Source/WebJobService/IService.cs @@ -0,0 +1,15 @@ +using Dapper; +using DealerSelection.Common.Data.Dapper; +using Microsoft.Extensions.Logging; +using Newtonsoft.Json.Linq; +using Newtonsoft.Json; + +namespace WebJobService; + +public interface IService +{ + + + public void Run(); + +} \ No newline at end of file diff --git a/Source/WebJobService/Program.cs b/Source/WebJobService/Program.cs new file mode 100644 index 0000000..c411e8a --- /dev/null +++ b/Source/WebJobService/Program.cs @@ -0,0 +1,35 @@ +using DealerSelection.Common.HttpClient; +using DealerSelection.Common.Interfaces.HttpClient; +using Lamar; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; + +namespace WebJobService; + + +public class Program : ServiceRegistry +{ + private IHttpClientHandler HttpClientHandler { get; set; } + private ILogger logger; + private IServiceProvider serviceProvider; + static void Main() + { + var container=new Container(x=> + { + x.AddSingleton(); + x.AddSingleton(); + x.For().Use().Ctor("cxnName").Is("BOOKING").Singleton(); + }); + //IHttpClientHandler clientHandler = container.GetInstance(); + //ILogger logger = container.GetInstance(); + IService service = container.GetInstance(); + // IHttpClientHandler clientHandler = container.GetInstance(); + //ILogger logger = container.GetInstance(); + + + service.Run(); + + } + + +} diff --git a/Source/WebJobService/Service.cs b/Source/WebJobService/Service.cs new file mode 100644 index 0000000..4bff25c --- /dev/null +++ b/Source/WebJobService/Service.cs @@ -0,0 +1,160 @@ +using Dapper; +using DealerSelection.Common.Data.Dapper; +using Microsoft.Extensions.Logging; +using Newtonsoft.Json.Linq; +using Newtonsoft.Json; +using System.Configuration; +using System.Data; +using System.Data.SqlClient; +using System.Net; +using System.Text; +using System.Net.Http.Headers; +using DealerSelection.Common.Interfaces.HttpClient; +using static System.Net.Mime.MediaTypeNames; +using System.Net.Http; + +namespace WebJobService; + +public class Service : RepositoryBaseDapperAsync, IService +{ + private readonly ILogger _logger; + private IHttpClientHandler ClientHandler { get; } + private string connectionString = Convert.ToString(ConfigurationManager.ConnectionStrings["NoDealerBooking"]); + public Service(string cxnName, IHttpClientHandler clientHandler) : base(cxnName) + { + //_logger = logger; + ClientHandler = clientHandler; + } + + public void Run() + { + ////_logger.LogInformation($"Service Started: {DateTime.Now}."); + GetRecordToProcess().Wait(); + ////_logger.LogInformation($"Service Completed: {DateTime.Now}."); + } + + private async Task GetRecordToProcess() + { + try + { + using (SqlConnection cxn = await OpenCxnAsync()) + { + IEnumerable recordsToProcess = await cxn.QueryAsync("usp_get_dealer_selection_for_job", + commandType: CommandType.StoredProcedure); + var recordList = recordsToProcess.ToList(); + //_logger.LogInformation($"Records to Process: {recordList.Count}."); + foreach (var item in recordList) + { + HitDeleareSelectionApi(item); + } + //_logger.LogInformation($"Records processed sucessfully: {recordList.Count}."); + } + + } + catch (Exception exp) + { + throw exp; + } + //sqlConnection1.Close(); + } + + private async Task HitDeleareSelectionApi(SelectedData item) + { + //item.BuId, item.RecorId + + string jwtToken = GenerateToken(); + string url = $"https://localhost:7122/DealerSelection/DealerSelection?buId={item.BuId}&recordId={item.RecordId}"; + //string resultJson = string.Empty; + + //string modelDetailsApi = string.Format("https://booking-preprod.bajajauto.com/DealerSelection/DealerSelection?buId=1&recordId=123"); + try + { + //using (var webClient = new WebClient { Encoding = Encoding.UTF8 }) + //{ + // webClient.Headers.Add("Content-Type", "application/json"); + // webClient.Headers.Add("Authorization", "Bearer " + jwtToken); + // resultJson = webClient.DownloadString(modelDetailsApi); + //} + //var resultObject = JObject.Parse(resultJson); + //if (resultObject.Value("IsRequestSuccessfull")) + //{ + // var response = (JObject)resultObject.Value("Data")[0]; + // Console.WriteLine(response.ToString()); + //} + + + //var data = "{\"buId\": \"" + item.BuId + "\"}"; + + //var data = new + //{ + // item.BuId, + // item.RecorId, + //}; + + //string requestJson = JsonConvert.SerializeObject(data); + + + HttpClient request = ClientHandler.GetHttpClient(); + Uri requestUri = new (url); + var httpContent = new MultipartFormDataContent(); + httpContent.Headers.ContentType = new MediaTypeHeaderValue("application/json"); + request.DefaultRequestHeaders.Add("Authorization", "Bearer " + jwtToken); + HttpResponseMessage response = request.PostAsync(url, null).Result; + var contents = await response.Content.ReadAsStringAsync(); + Console.WriteLine(contents); + } + catch (Exception ex) + { + Console.WriteLine(ex.StackTrace); + } + } + + private string GenerateToken() + { + string jwtTokenApiUrl = string.Format("{0}/JWTAuth/GetAuthToken", "https://localhost:7122"); + + var requestBody = new + { + clientId = "ee12e3d9cb9a4dc6af3599934cc4152b", + secretId = "92a2bede7b414cb19861efa3cc3a8c0d", + buId = 1 + }; + + string requestJson = JsonConvert.SerializeObject(requestBody); + byte[] bodyBytes = Encoding.UTF8.GetBytes(requestJson); + + HttpWebRequest request = WebRequest.Create(jwtTokenApiUrl) as HttpWebRequest; + request.Method = "POST"; + request.ContentType = "application/json"; + request.ContentLength = bodyBytes.Length; + + string jwtToken = string.Empty; + try + { + using (var dataStream = request.GetRequestStream()) + { + dataStream.Write(bodyBytes, 0, bodyBytes.Length); + dataStream.Close(); + } + + HttpWebResponse response = request.GetResponse() as HttpWebResponse; + Stream responseStream = response.GetResponseStream(); + + using (StreamReader reader = new StreamReader(responseStream)) + { + jwtToken = reader.ReadToEnd(); + } + } + catch (Exception e) + { + } + return jwtToken; + } + + + class SelectedData + { + public int BuId { get; set; } + public int RecordId { get; set; } + } +} \ No newline at end of file diff --git a/Source/WebJobService/WebJobService.csproj b/Source/WebJobService/WebJobService.csproj new file mode 100644 index 0000000..4593667 --- /dev/null +++ b/Source/WebJobService/WebJobService.csproj @@ -0,0 +1,31 @@ + + + + Exe + net6.0 + enable + enable + + + + + + + + + Always + true + PreserveNewest + + + + + + + + + + + + + diff --git a/Source/WebJobService/app.config b/Source/WebJobService/app.config new file mode 100644 index 0000000..4880127 --- /dev/null +++ b/Source/WebJobService/app.config @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/Source/WebJobService/connectionString.json b/Source/WebJobService/connectionString.json new file mode 100644 index 0000000..1c239b5 --- /dev/null +++ b/Source/WebJobService/connectionString.json @@ -0,0 +1,8 @@ +{ + + "ConnectionStrings": { + "BOOKING": "user id=sqlAdmin;password=bFLW43%p40^;Data Source=mc-5f2bf602-449a-48b2-ae5a-5901-sql.database.windows.net,1433;Database=NoDealerBooking;", + "BAJAJ": "user id=sqlAdmin;password=bFLW43%p40^;Data Source=mc-5f2bf602-449a-48b2-ae5a-5901-sql.database.windows.net,1433;Database=bajaj;", + "AZURE_LOGGING": "InstrumentationKey=2fead737-737a-4241-9e66-dfc5391583ba;IngestionEndpoint=https://centralindia-0.in.applicationinsights.azure.com/;LiveEndpoint=https://centralindia.livediagnostics.monitor.azure.com/" + } +} \ No newline at end of file diff --git a/Web.config b/Web.config new file mode 100644 index 0000000..32c7375 --- /dev/null +++ b/Web.config @@ -0,0 +1,1052 @@ + + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file