132 changed files with 6799 additions and 0 deletions
-
98DealerSelectionAPI.sln
-
14Source/DealerSelection.Api.Models/AuthModel.cs
-
14Source/DealerSelection.Api.Models/AuthValidateModel.cs
-
48Source/DealerSelection.Api.Models/CustomerDealerInfoRequest.cs
-
28Source/DealerSelection.Api.Models/DealerSelection.Api.Models.csproj
-
10Source/DealerSelection.Api.Models/DealerSelectionJobStatus.cs
-
21Source/DealerSelection.Api.Models/MulesoftResponse.cs
-
8Source/DealerSelection.Api.Models/MulesoftToken.cs
-
15Source/DealerSelection.Api.Models/Procedure.cs
-
31Source/DealerSelection.Api.Models/Response.cs
-
10Source/DealerSelection.Api.Models/TokenValidProperty.cs
-
9Source/DealerSelection.Api.Models/UnexpectedDataException.cs
-
70Source/DealerSelection.Api.Models/WebEngageEvent.cs
-
190Source/DealerSelection.Api/AssignDealerApi.cs
-
151Source/DealerSelection.Api/CommonUtil/AESEncryption.cs
-
132Source/DealerSelection.Api/CommonUtil/CustomConfig.cs
-
28Source/DealerSelection.Api/CommonUtil/GenerateRandomString.cs
-
86Source/DealerSelection.Api/CommonUtil/MuleSoftTokenGenerate.cs
-
42Source/DealerSelection.Api/DealerSelection.Api.csproj
-
143Source/DealerSelection.Api/InfoBipSmsServiceApi.cs
-
112Source/DealerSelection.Api/JwtTokenApi.cs
-
722Source/DealerSelection.Api/MulesoftApi.cs
-
68Source/DealerSelection.Api/MulesoftTokenApi.cs
-
77Source/DealerSelection.Api/YellowAIApi.cs
-
9Source/DealerSelection.Common/CommonBaseClass/ExceptionBase.cs
-
92Source/DealerSelection.Common/CommonBaseClass/ExceptionFilterBase.cs
-
235Source/DealerSelection.Common/CommonBaseClass/StartupBase.cs
-
6Source/DealerSelection.Common/CommonBaseClass/WebApiConfigurationCfgBase.cs
-
102Source/DealerSelection.Common/Configuration/ConfigurationHelper.cs
-
36Source/DealerSelection.Common/Data/ConnectionHelper.cs
-
25Source/DealerSelection.Common/Data/Dapper/RepositoryBaseDapperAsync.cs
-
25Source/DealerSelection.Common/Data/Dapper/RepositoryBaseDapperSync.cs
-
30Source/DealerSelection.Common/Data/Dapper/TypeMapHelper.cs
-
35Source/DealerSelection.Common/Data/RepositoryBaseDIAsync.cs
-
35Source/DealerSelection.Common/Data/RepositoryBaseDISync.cs
-
11Source/DealerSelection.Common/Data/RepositoryDIBase.cs
-
56Source/DealerSelection.Common/DealerSelection.Common.csproj
-
24Source/DealerSelection.Common/Entity/FieldMapAttribute.cs
-
8Source/DealerSelection.Common/Exceptions/AuthorizationException.cs
-
8Source/DealerSelection.Common/Exceptions/DataNotFoundException.cs
-
15Source/DealerSelection.Common/Exceptions/DbConnectionException.cs
-
8Source/DealerSelection.Common/Exceptions/DuplicateException.cs
-
8Source/DealerSelection.Common/Exceptions/NullValueException.cs
-
8Source/DealerSelection.Common/Exceptions/PartialSuccessException.cs
-
8Source/DealerSelection.Common/Exceptions/ValidationException.cs
-
8Source/DealerSelection.Common/Helpers/SwaggerCfg.cs
-
38Source/DealerSelection.Common/Helpers/SwashbuckleSchemaHelper.cs
-
21Source/DealerSelection.Common/HttpClient/MyHttpClientHandler.cs
-
9Source/DealerSelection.Common/Interfaces/Data/IRepositoryDIAsync.cs
-
9Source/DealerSelection.Common/Interfaces/Data/IRepositoryDISync.cs
-
8Source/DealerSelection.Common/Interfaces/HttpClient/IHttpClientHandler.cs
-
24Source/DealerSelection.Common/Logging/ApiInfo.cs
-
82Source/DealerSelection.Common/Logging/AzureLogHelper.cs
-
28Source/DealerSelection.Common/Logging/HttpHeaderHelper.cs
-
127Source/DealerSelection.Common/Logging/LoggingMiddleware.cs
-
42Source/DealerSelection.Common/Logging/RequestInfo.cs
-
37Source/DealerSelection.Common/Logging/ResponseInfo.cs
-
34Source/DealerSelection.Common/Middleware/SwaggerRootRoutingMiddleware.cs
-
31Source/DealerSelection.Common/Profiler/PerformanceProfiler.cs
-
19Source/DealerSelection.Common/Profiler/Profiler.cs
-
35Source/DealerSelection.DependencyInjection/ApiRegistry.cs
-
29Source/DealerSelection.DependencyInjection/DealerSelection.DependencyInjection.csproj
-
11Source/DealerSelection.DependencyInjection/DependencyInjectionBootStrapper.cs
-
37Source/DealerSelection.DependencyInjection/InfrastructureRegistry.cs
-
7Source/DealerSelection.Infrastructure/AssignDealer/IAssignDealerRepository.cs
-
17Source/DealerSelection.Infrastructure/AssignDealer/Repository.cs
-
26Source/DealerSelection.Infrastructure/CustomerDetail/CustomerInfoDto.cs
-
13Source/DealerSelection.Infrastructure/CustomerDetail/IRepository.cs
-
116Source/DealerSelection.Infrastructure/CustomerDetail/Repository.cs
-
37Source/DealerSelection.Infrastructure/DealerSelection.Api.Infrastructure.csproj
-
6Source/DealerSelection.Infrastructure/InfoBip/IRepository.cs
-
45Source/DealerSelection.Infrastructure/InfoBip/Repository.cs
-
14Source/DealerSelection.Infrastructure/Jwt/AuthValidateModelDto.cs
-
9Source/DealerSelection.Infrastructure/Jwt/IJwtRepository.cs
-
23Source/DealerSelection.Infrastructure/Jwt/JwtRepository.cs
-
26Source/DealerSelection.Infrastructure/Mulesoft/DealerDetailDto.cs
-
10Source/DealerSelection.Infrastructure/Mulesoft/IRepository.cs
-
46Source/DealerSelection.Infrastructure/Mulesoft/MulesoftCustomerInfoDto.cs
-
134Source/DealerSelection.Infrastructure/Mulesoft/Repository.cs
-
27Source/DealerSelection.Interface/DealerSelection.Api.Interface.csproj
-
7Source/DealerSelection.Interface/IAssignDealerApi.cs
-
9Source/DealerSelection.Interface/IInfoBipSmsServiceApi.cs
-
9Source/DealerSelection.Interface/IJwtTokenApi.cs
-
20Source/DealerSelection.Interface/IMulesoftApi.cs
-
7Source/DealerSelection.Interface/IMulesoftTokenApi.cs
-
10Source/DealerSelection.Interface/IYellowAIApi.cs
-
14Source/DealerSelection.WebApi.Models/BikeResponse.cs
-
14Source/DealerSelection.WebApi.Models/BookingConfirmationRequest.cs
-
9Source/DealerSelection.WebApi.Models/CityResponse.cs
-
26Source/DealerSelection.WebApi.Models/CustomerInfoMappingResponse.cs
-
17Source/DealerSelection.WebApi.Models/CustomerInfoRequest.cs
-
20Source/DealerSelection.WebApi.Models/DealerSelection.WebApi.Models.csproj
-
34Source/DealerSelection.WebApi.Models/MulesoftResponse.cs
-
7Source/DealerSelection.WebApi.Models/PaymentLinkResponse.cs
-
16Source/DealerSelection.WebApi.Models/RegisterInterestSuccessfulResponse.cs
-
12Source/DealerSelection.WebApi.Models/Response.cs
-
24Source/DealerSelection.WebApi.Models/ReviewPayCustomerInfoResponse.cs
-
8Source/DealerSelection.WebApi.Models/StateResponse.cs
-
12Source/DealerSelection.WebApi/.config/dotnet-tools.json
-
36Source/DealerSelection.WebApi/App_Start/Mapper.cs
@ -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 |
@ -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; } |
|||
} |
|||
} |
@ -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; } |
|||
} |
|||
} |
@ -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}"; |
|||
} |
|||
|
|||
} |
@ -0,0 +1,28 @@ |
|||
<Project Sdk="Microsoft.NET.Sdk"> |
|||
|
|||
<PropertyGroup> |
|||
<TargetFramework>net6.0</TargetFramework> |
|||
<ImplicitUsings>enable</ImplicitUsings> |
|||
<Nullable>enable</Nullable> |
|||
</PropertyGroup> |
|||
|
|||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'"> |
|||
<NoWarn>1701;1702;8618</NoWarn> |
|||
</PropertyGroup> |
|||
|
|||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'"> |
|||
<NoWarn>1701;1702;8618</NoWarn> |
|||
</PropertyGroup> |
|||
|
|||
<ItemGroup> |
|||
<PackageReference Include="BouncyCastle.NetCore" Version="1.9.0" /> |
|||
<PackageReference Include="iTextSharp" Version="5.5.13.3" /> |
|||
<PackageReference Include="itextsharp.xmlworker" Version="5.5.13.3" /> |
|||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" /> |
|||
<PackageReference Include="SecurityCodeScan.VS2019" Version="5.6.7"> |
|||
<PrivateAssets>all</PrivateAssets> |
|||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> |
|||
</PackageReference> |
|||
</ItemGroup> |
|||
|
|||
</Project> |
@ -0,0 +1,10 @@ |
|||
namespace DealerSelection.Api.Models; |
|||
|
|||
public enum DealerSelectionJobStatus |
|||
{ |
|||
OldData = -1, |
|||
ReadyForJob = 0, |
|||
Picked = 1, |
|||
SentToBot = 2, |
|||
Complete = 3, |
|||
} |
@ -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; } |
|||
|
|||
} |
@ -0,0 +1,8 @@ |
|||
|
|||
namespace DealerSelection.Api.Models; |
|||
|
|||
public class MulesoftToken |
|||
{ |
|||
public string Value { get; set; } |
|||
public int ExpiresIn { get; set; } |
|||
} |
@ -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
|
|||
} |
@ -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 |
|||
|
|||
} |
|||
|
|||
|
@ -0,0 +1,10 @@ |
|||
namespace DealerSelection.Api.Models |
|||
{ |
|||
public class TokenValidProperty |
|||
{ |
|||
public bool isValid { get; set; } |
|||
|
|||
public double Ttl { get; set; } |
|||
|
|||
} |
|||
} |
@ -0,0 +1,9 @@ |
|||
namespace DealerSelection.Api.Models |
|||
{ |
|||
public class UnexpectedDataException : Exception |
|||
{ |
|||
public UnexpectedDataException(string message, Exception innerException) : base(message, innerException) |
|||
{ |
|||
} |
|||
} |
|||
} |
@ -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; } |
|||
} |
@ -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<string>("muleSoftAPIDomain", true); |
|||
public static string dealerDetailApiUrl = ConfigurationHelper.GetSetting<string>("muleSoftDealerDetail", true); |
|||
public static string bookingApiUrl = ConfigurationHelper.GetSetting<string>("muleSoftBookingAPILeadSquareDomain", true); |
|||
public static string masterSchemaId = ConfigurationHelper.GetSetting<string>("masterSchemaId", true); |
|||
public static string masterDealerDetailSchemaId = ConfigurationHelper.GetSetting<string>("masterDealerDetailSchemaId", true); |
|||
public static string muleSoftStateWisePrice = ConfigurationHelper.GetSetting<string>("muleSoftStateWisePrice", true); |
|||
public static string muleSoftBrandWiseModel = ConfigurationHelper.GetSetting<string>("muleSoftBrandWiseModel", true); |
|||
public static string muleSoftPricemasterSchemaId = ConfigurationHelper.GetSetting<string>("muleSoftStateWisePricemasterSchemaId", true); |
|||
public static string muleSoftModelmasterSchemaId = ConfigurationHelper.GetSetting<string>("muleSoftBrandWiseModelmasterSchemaId", true); |
|||
|
|||
public static string muleSoftStateMasterSchemaId = ConfigurationHelper.GetSetting<string>("muleSoftStateMasterSchemaId", true); |
|||
public static string muleSoftStateMasterSchemaApi = ConfigurationHelper.GetSetting<string>("muleSoftStateMasterSchemaApi", true); |
|||
public static string muleSoftCityMasterSchemaId = ConfigurationHelper.GetSetting<string>("muleSoftCityMasterSchemaId", true); |
|||
public static string muleSoftCityMasterSchemaApi = ConfigurationHelper.GetSetting<string>("muleSoftCityMasterSchemaApi", true); |
|||
public static string muleSoftModelMasterSchemaItemId = ConfigurationHelper.GetSetting<string>("muleSoftModelMasterSchemaItemId", true); |
|||
public static string muleSoftModelMasterSchemaItemApi = ConfigurationHelper.GetSetting<string>("muleSoftModelMasterSchemaItemApi", true); |
|||
|
|||
#endregion
|
|||
|
|||
|
|||
#region Caching
|
|||
|
|||
public static string CacheGetDealersDetail = ConfigurationHelper.GetSetting<string>("MuleSoftCacheGetDealersDetail", true); |
|||
private int _cacheGetDealersDetail = !string.IsNullOrEmpty(CacheGetDealersDetail) ? int.Parse(CacheGetDealersDetail) : 10; |
|||
|
|||
public static string CacheGetPriceOnState = ConfigurationHelper.GetSetting<string>("MuleSoftCacheGetPriceOnState", true); |
|||
private int _cacheGetPriceOnState = !string.IsNullOrEmpty(CacheGetPriceOnState) ? int.Parse(CacheGetPriceOnState) : 10; |
|||
|
|||
public static string CacheGetModelOnBrand = ConfigurationHelper.GetSetting<string>("MuleSoftCacheGetModelOnBrand", true); |
|||
private int _cacheGetModelOnBrand = !string.IsNullOrEmpty(CacheGetModelOnBrand) ? int.Parse(CacheGetModelOnBrand) : 10; |
|||
|
|||
public static string CacheGetActiveState = ConfigurationHelper.GetSetting<string>("MuleSoftCacheGetActiveState", true); |
|||
private int _cacheGetActiveState = !string.IsNullOrEmpty(CacheGetActiveState) ? int.Parse(CacheGetActiveState) : 10; |
|||
|
|||
public static string CacheGetActiveCity = ConfigurationHelper.GetSetting<string>("MuleSoftCacheGetActiveCity", true); |
|||
private int _cacheGetActiveCity = !string.IsNullOrEmpty(CacheGetActiveCity) ? int.Parse(CacheGetActiveCity) : 10; |
|||
|
|||
public static string CacheModelDetails = ConfigurationHelper.GetSetting<string>("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<MulesoftApi> 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); |
|||
} |
|||
|
|||
} |
@ -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; |
|||
} |
|||
|
|||
} |
|||
|
|||
} |
@ -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<string>("KtmCfg:InfoBipAppilcationId", true); |
|||
cfg.InfoBipMessageId = ConfigurationHelper.GetSetting<string>("KtmCfg:InfoBipMessageId", true); |
|||
cfg.InfoBipFroms = ConfigurationHelper.GetSetting<string>("KtmCfg:InfoBipFrom", true); |
|||
|
|||
cfg.CCAvenueAccessCode = ConfigurationHelper.GetSetting<string>("KtmCfg:CCAvenueAccessCode", true); |
|||
cfg.CCAvenueMerchantCode = ConfigurationHelper.GetSetting<string>("KtmCfg:CCAvenueMerchantCode", true); |
|||
cfg.CCAvenueBaseUrl = ConfigurationHelper.GetSetting<string>("KtmCfg:CCAvenueBaseUrl", true); |
|||
cfg.BookingPrice = ConfigurationHelper.GetSetting<string>("KtmCfg:BookingPrice", true); |
|||
cfg.CCAvenueWorkingKey = ConfigurationHelper.GetSetting<string>("KtmCfg:CCAvenueWorkingKey", true); |
|||
cfg.BuCode= ConfigurationHelper.GetSetting<string>("KtmCfg:BuCode", true); |
|||
cfg.WebengageLandingPageUrl= ConfigurationHelper.GetSetting<string>("KtmCfg:LandingPageUrl", true); |
|||
cfg.WebengageEventName = ConfigurationHelper.GetSetting<string>("KtmCfg:WebengageEventName", true); |
|||
cfg.WebEngageLicenseCode = ConfigurationHelper.GetSetting<string>("KtmCfg:WebEngageLicenseCode", true); |
|||
cfg.WebEngageAuthToken = ConfigurationHelper.GetSetting<string>("KtmCfg:WebEngageAuthToken", true); |
|||
cfg.WebengageApiHost = ConfigurationHelper.GetSetting<string>("KtmCfg:WebengageApiHost", true); |
|||
cfg.ValidateDuplicate = ConfigurationHelper.GetSetting<string>("KtmCfg:ValidateDuplicate", true); |
|||
cfg.ValidateDuplicateHour = ConfigurationHelper.GetSetting<int>("KtmCfg:ValidateDuplicateHr", true); |
|||
cfg.BuId = buId; |
|||
|
|||
cfg.ClientId = ConfigurationHelper.GetSetting<string>("KtmCfg:ClientId", true); |
|||
cfg.ClientSecret = ConfigurationHelper.GetSetting<string>("KtmCfg:ClientSecret", true); |
|||
cfg.Key = ConfigurationHelper.GetSetting<string>("KtmCfg:Key", true); |
|||
cfg.Audience = ConfigurationHelper.GetSetting<string>("KtmCfg:Audience", true); |
|||
cfg.Issuer = ConfigurationHelper.GetSetting<string>("KtmCfg:Issuer", true); |
|||
cfg.Role = ConfigurationHelper.GetSetting<string>("KtmCfg:Role", true); |
|||
cfg.ExpireMinutes = ConfigurationHelper.GetSetting<string>("KtmCfg:ExpireMinutes", true); |
|||
break; |
|||
case 2: |
|||
cfg.InfoBipAppilcationId = ConfigurationHelper.GetSetting<string>("BajajCfg:InfoBipAppilcationId", true); |
|||
cfg.InfoBipMessageId = ConfigurationHelper.GetSetting<string>("BajajCfg:InfoBipMessageId", true); |
|||
cfg.InfoBipFroms = ConfigurationHelper.GetSetting<string>("BajajCfg:InfoBipFrom", true); |
|||
cfg.CCAvenueAccessCode = ConfigurationHelper.GetSetting<string>("BajajCfg:CCAvenueAccessCode", true); |
|||
cfg.CCAvenueMerchantCode = ConfigurationHelper.GetSetting<string>("BajajCfg:CCAvenueMerchantCode", true); |
|||
cfg.CCAvenueBaseUrl = ConfigurationHelper.GetSetting<string>("BajajCfg:CCAvenueBaseUrl", true); |
|||
cfg.BookingPrice = ConfigurationHelper.GetSetting<string>("BajajCfg:BookingPrice", true); |
|||
cfg.CCAvenueWorkingKey = ConfigurationHelper.GetSetting<string>("BajajCfg:CCAvenueWorkingKey", true); |
|||
cfg.BuCode = ConfigurationHelper.GetSetting<string>("BajajCfg:BuCode", true); |
|||
cfg.WebengageLandingPageUrl = ConfigurationHelper.GetSetting<string>("BajajCfg:LandingPageUrl", true); |
|||
cfg.WebengageEventName = ConfigurationHelper.GetSetting<string>("BajajCfg:WebengageEventName", true); |
|||
cfg.WebEngageLicenseCode = ConfigurationHelper.GetSetting<string>("BajajCfg:WebEngageLicenseCode", true); |
|||
cfg.WebEngageAuthToken = ConfigurationHelper.GetSetting<string>("BajajCfg:WebEngageAuthToken", true); |
|||
cfg.WebengageApiHost = ConfigurationHelper.GetSetting<string>("BajajCfg:WebengageApiHost", true); |
|||
cfg.ValidateDuplicate = ConfigurationHelper.GetSetting<string>("BajajCfg:ValidateDuplicate", true); |
|||
cfg.ValidateDuplicateHour = ConfigurationHelper.GetSetting<int>("BajajCfg:ValidateDuplicateHr", true); |
|||
cfg.BuId = buId; |
|||
|
|||
cfg.ClientId = ConfigurationHelper.GetSetting<string>("BajajCfg:ClientId", true); |
|||
cfg.ClientSecret = ConfigurationHelper.GetSetting<string>("BajajCfg:ClientSecret", true); |
|||
cfg.Key = ConfigurationHelper.GetSetting<string>("BajajCfg:Key", true); |
|||
cfg.Audience = ConfigurationHelper.GetSetting<string>("BajajCfg:Audience", true); |
|||
cfg.Issuer = ConfigurationHelper.GetSetting<string>("BajajCfg:Issuer", true); |
|||
cfg.Role = ConfigurationHelper.GetSetting<string>("BajajCfg:Role", true); |
|||
cfg.ExpireMinutes = ConfigurationHelper.GetSetting<string>("BajajCfg:ExpireMinutes", true); |
|||
break; |
|||
case 3: |
|||
cfg.InfoBipAppilcationId = ConfigurationHelper.GetSetting<string>("TriumphCfg:InfoBipAppilcationId", true); |
|||
cfg.InfoBipMessageId = ConfigurationHelper.GetSetting<string>("TriumphCfg:InfoBipMessageId", true); |
|||
cfg.InfoBipFroms = ConfigurationHelper.GetSetting<string>("TriumphCfg:InfoBipFrom", true); |
|||
cfg.CCAvenueAccessCode = ConfigurationHelper.GetSetting<string>("TriumphCfg:CCAvenueAccessCode", true); |
|||
cfg.CCAvenueMerchantCode = ConfigurationHelper.GetSetting<string>("TriumphCfg:CCAvenueMerchantCode", true); |
|||
cfg.CCAvenueBaseUrl = ConfigurationHelper.GetSetting<string>("TriumphCfg:CCAvenueBaseUrl", true); |
|||
cfg.BookingPrice = ConfigurationHelper.GetSetting<string>("TriumphCfg:BookingPrice", true); |
|||
cfg.CCAvenueWorkingKey = ConfigurationHelper.GetSetting<string>("TriumphCfg:CCAvenueWorkingKey", true); |
|||
cfg.BuCode = ConfigurationHelper.GetSetting<string>("TriumphCfg:BuCode", true); |
|||
cfg.WebengageLandingPageUrl = ConfigurationHelper.GetSetting<string>("TriumphCfg:LandingPageUrl", true); |
|||
cfg.WebengageEventName = ConfigurationHelper.GetSetting<string>("TriumphCfg:WebengageEventName", true); |
|||
cfg.WebEngageLicenseCode = ConfigurationHelper.GetSetting<string>("TriumphCfg:WebEngageLicenseCode", true); |
|||
cfg.WebEngageAuthToken = ConfigurationHelper.GetSetting<string>("TriumphCfg:WebEngageAuthToken", true); |
|||
cfg.WebengageApiHost = ConfigurationHelper.GetSetting<string>("TriumphCfg:WebengageApiHost", true); |
|||
cfg.ValidateDuplicate = ConfigurationHelper.GetSetting<string>("TriumphCfg:ValidateDuplicate", true); |
|||
cfg.ValidateDuplicateHour = ConfigurationHelper.GetSetting<int>("TriumphCfg:ValidateDuplicateHr", true); |
|||
cfg.BuId = buId; |
|||
|
|||
cfg.ClientId = ConfigurationHelper.GetSetting<string>("TriumphCfg:ClientId", true); |
|||
cfg.ClientSecret = ConfigurationHelper.GetSetting<string>("TriumphCfg:ClientSecret", true); |
|||
cfg.Key = ConfigurationHelper.GetSetting<string>("TriumphCfg:Key", true); |
|||
cfg.Audience = ConfigurationHelper.GetSetting<string>("TriumphCfg:Audience", true); |
|||
cfg.Issuer = ConfigurationHelper.GetSetting<string>("TriumphCfg:Issuer", true); |
|||
cfg.Role = ConfigurationHelper.GetSetting<string>("TriumphCfg:Role", true); |
|||
cfg.ExpireMinutes = ConfigurationHelper.GetSetting<string>("TriumphCfg:ExpireMinutes", true); |
|||
break; |
|||
default: |
|||
cfg.InfoBipAppilcationId = ""; |
|||
cfg.InfoBipMessageId = ""; |
|||
cfg.InfoBipFroms = ""; |
|||
cfg.BuId = buId; |
|||
break; |
|||
} |
|||
return cfg; |
|||
|
|||
} |
|||
} |
|||
|
|||
} |
@ -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; |
|||
} |
|||
} |
|||
|
|||
} |
@ -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>
|
|||
/// Summary description for TestRideExcellon
|
|||
/// </summary>
|
|||
public static class MuleSoftIntegration |
|||
{ |
|||
public static string ClientId = ConfigurationHelper.GetSetting<string>("muleSoftAPIClientID", true); |
|||
public static string ClientSecret = ConfigurationHelper.GetSetting<string>("muleSoftAIPClientSecret", true); |
|||
public static string TokenGenerateUrl = ConfigurationHelper.GetSetting<string>("muleSoftGenerateTokenURL", true); |
|||
|
|||
public static async Task<MulesoftToken> 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<HttpResponseMessage> 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; |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,42 @@ |
|||
<Project Sdk="Microsoft.NET.Sdk"> |
|||
|
|||
<PropertyGroup> |
|||
<TargetFramework>net6.0</TargetFramework> |
|||
<ImplicitUsings>enable</ImplicitUsings> |
|||
<Nullable>enable</Nullable> |
|||
</PropertyGroup> |
|||
|
|||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'"> |
|||
<NoWarn>1701;1702;8618;8601;8600;8602;8603;CA2254</NoWarn> |
|||
</PropertyGroup> |
|||
|
|||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'"> |
|||
<NoWarn>1701;1702;8618;8601;8600;8602;8603;CA2254</NoWarn> |
|||
</PropertyGroup> |
|||
|
|||
<ItemGroup> |
|||
<PackageReference Include="BouncyCastle.NetCore" Version="1.9.0" /> |
|||
<PackageReference Include="iTextSharp" Version="5.5.13.3" /> |
|||
<PackageReference Include="itextsharp.xmlworker" Version="5.5.13.3" /> |
|||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="7.0.1" /> |
|||
<PackageReference Include="Microsoft.Extensions.Logging.ApplicationInsights" Version="2.21.0" /> |
|||
<PackageReference Include="RestSharp.Serializers.NewtonsoftJson" Version="110.2.0" /> |
|||
<PackageReference Include="SecurityCodeScan.VS2019" Version="5.6.7"> |
|||
<PrivateAssets>all</PrivateAssets> |
|||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> |
|||
</PackageReference> |
|||
</ItemGroup> |
|||
|
|||
<ItemGroup> |
|||
<ProjectReference Include="..\DealerSelection.Infrastructure\DealerSelection.Api.Infrastructure.csproj" /> |
|||
<ProjectReference Include="..\DealerSelection.Interface\DealerSelection.Api.Interface.csproj" /> |
|||
</ItemGroup> |
|||
|
|||
<ItemGroup> |
|||
<Reference Include="MCPG.CCA.Util"> |
|||
<HintPath>CCAvenue\MCPG.CCA.Util.dll</HintPath> |
|||
<Private>True</Private> |
|||
</Reference> |
|||
</ItemGroup> |
|||
|
|||
</Project> |
@ -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>
|
|||
/// Summary description for KarixSmsService
|
|||
/// </summary>
|
|||
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<InfoBipSmsServiceApi> logger) |
|||
{ |
|||
Repository = repository; |
|||
ClientHandler = clientHandler; |
|||
_logger = logger; |
|||
} |
|||
public InfoBipSmsServiceApi() |
|||
{ |
|||
|
|||
} |
|||
|
|||
public async Task<JObject> 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<JObject> 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<JObject> 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<JObject> 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; } |
|||
} |
@ -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<JwtTokenApi> logger) |
|||
{ |
|||
Repository = repository; |
|||
_logger = logger; |
|||
} |
|||
|
|||
public async Task<string> 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<bool> 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<TokenValidProperty> 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; |
|||
} |
|||
|
|||
} |
@ -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<string>("muleSoftAPIDomain", true); |
|||
public static string dealerDetailApiUrl = ConfigurationHelper.GetSetting<string>("muleSoftDealerDetail", true); |
|||
public static string bookingApiUrl = ConfigurationHelper.GetSetting<string>("muleSoftBookingAPILeadSquareDomain", true); |
|||
public static string masterSchemaId = ConfigurationHelper.GetSetting<string>("masterSchemaId", true); |
|||
public static string masterDealerDetailSchemaId = ConfigurationHelper.GetSetting<string>("masterDealerDetailSchemaId", true); |
|||
public static string muleSoftStateWisePrice = ConfigurationHelper.GetSetting<string>("muleSoftStateWisePrice", true); |
|||
public static string muleSoftBrandWiseModel = ConfigurationHelper.GetSetting<string>("muleSoftBrandWiseModel", true); |
|||
public static string muleSoftPricemasterSchemaId = ConfigurationHelper.GetSetting<string>("muleSoftStateWisePricemasterSchemaId", true); |
|||
public static string muleSoftModelmasterSchemaId = ConfigurationHelper.GetSetting<string>("muleSoftBrandWiseModelmasterSchemaId", true); |
|||
|
|||
public static string muleSoftStateMasterSchemaId = ConfigurationHelper.GetSetting<string>("muleSoftStateMasterSchemaId", true); |
|||
public static string muleSoftStateMasterSchemaApi = ConfigurationHelper.GetSetting<string>("muleSoftStateMasterSchemaApi", true); |
|||
public static string muleSoftCityMasterSchemaId = ConfigurationHelper.GetSetting<string>("muleSoftCityMasterSchemaId", true); |
|||
public static string muleSoftCityMasterSchemaApi = ConfigurationHelper.GetSetting<string>("muleSoftCityMasterSchemaApi", true); |
|||
public static string muleSoftModelMasterSchemaItemId = ConfigurationHelper.GetSetting<string>("muleSoftModelMasterSchemaItemId", true); |
|||
public static string muleSoftModelMasterSchemaItemApi = ConfigurationHelper.GetSetting<string>("muleSoftModelMasterSchemaItemApi", true); |
|||
|
|||
#endregion
|
|||
|
|||
|
|||
#region Caching
|
|||
|
|||
public static string CacheGetDealersDetail = ConfigurationHelper.GetSetting<string>("MuleSoftCacheGetDealersDetail", true); |
|||
private int _cacheGetDealersDetail = !string.IsNullOrEmpty(CacheGetDealersDetail) ? int.Parse(CacheGetDealersDetail) : 10; |
|||
|
|||
public static string CacheGetPriceOnState = ConfigurationHelper.GetSetting<string>("MuleSoftCacheGetPriceOnState", true); |
|||
private int _cacheGetPriceOnState = !string.IsNullOrEmpty(CacheGetPriceOnState) ? int.Parse(CacheGetPriceOnState) : 10; |
|||
|
|||
public static string CacheGetModelOnBrand = ConfigurationHelper.GetSetting<string>("MuleSoftCacheGetModelOnBrand", true); |
|||
private int _cacheGetModelOnBrand = !string.IsNullOrEmpty(CacheGetModelOnBrand) ? int.Parse(CacheGetModelOnBrand) : 10; |
|||
|
|||
public static string CacheGetActiveState = ConfigurationHelper.GetSetting<string>("MuleSoftCacheGetActiveState", true); |
|||
private int _cacheGetActiveState = !string.IsNullOrEmpty(CacheGetActiveState) ? int.Parse(CacheGetActiveState) : 10; |
|||
|
|||
public static string CacheGetActiveCity = ConfigurationHelper.GetSetting<string>("MuleSoftCacheGetActiveCity", true); |
|||
private int _cacheGetActiveCity = !string.IsNullOrEmpty(CacheGetActiveCity) ? int.Parse(CacheGetActiveCity) : 10; |
|||
|
|||
public static string CacheModelDetails = ConfigurationHelper.GetSetting<string>("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<MulesoftApi> logger) |
|||
{ |
|||
Repository = repository; |
|||
MulesoftTokenApi = mulesoftTokenApi; |
|||
ClientHandler = clientHandler; |
|||
_memoryCache = memoryCache; |
|||
_logger = logger; |
|||
} |
|||
|
|||
|
|||
public async Task<MulesoftResponse> 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<MulesoftResponse> 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<MulesoftResponse> 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<MulesoftResponse> 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<MulesoftResponse> 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<MulesoftResponse> 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<MulesoftResponse> 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<MulesoftCustomerInfoDto> GetCustomerInfo(int buId, string bookingId) |
|||
{ |
|||
return await Repository.GetCustomerInfo(buId, bookingId); |
|||
} |
|||
|
|||
public async Task<Response> 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<List<MulesoftCustomerInfoDto>> 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<MulesoftResponse> 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<MulesoftResponse> 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 ""; |
|||
} |
|||
} |
@ -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<MulesoftTokenApi> logger) |
|||
{ |
|||
this.cache = cache; |
|||
ClientHandler = clientHandler; |
|||
_logger = logger; |
|||
} |
|||
|
|||
public async Task<string> 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<MulesoftToken> 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; |
|||
} |
|||
} |
@ -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<YellowAIApi> 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<bool> IsDuplicateMobileNumber(int mobileNumber) |
|||
{ |
|||
return await CustomerDetailRepository.IsDuplicateMobileNumber(mobileNumber); |
|||
} |
|||
|
|||
} |
@ -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) |
|||
{ } |
|||
} |
@ -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<Type, HttpStatusCode> Mappings { get; } |
|||
public ExceptionFilterBase() |
|||
{ |
|||
Mappings = new Dictionary<Type, HttpStatusCode> |
|||
{ |
|||
{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<Type, HttpStatusCode> 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", " "); |
|||
} |
|||
} |
@ -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<string>("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<UserAgentBlackListMiddleware>();
|
|||
app.UseMiddleware<SwaggerRootRoutingMiddleware>(); |
|||
//app.UseMiddleware<AuthenticationMiddleware>();
|
|||
// app.UseMiddleware<LoggingMiddleware>();
|
|||
|
|||
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<IHttpContextAccessor, HttpContextAccessor>(); |
|||
services.AddMvc(options => options.Filters.Add(new ExceptionFilterBase())); |
|||
services.AddMvc(options => options.OutputFormatters.Add(new XmlSerializerOutputFormatter())); |
|||
|
|||
services.AddResponseCompression(options => |
|||
{ |
|||
options.Providers.Add<BrotliCompressionProvider>(); |
|||
options.EnableForHttps = true; |
|||
}); |
|||
|
|||
services.Configure<GzipCompressionProviderOptions>(options => |
|||
{ |
|||
options.Level = CompressionLevel.Optimal; |
|||
}); |
|||
|
|||
services.AddResponseCompression(options => |
|||
{ |
|||
options.Providers.Add<GzipCompressionProvider>(); |
|||
options.EnableForHttps = true; |
|||
}); |
|||
|
|||
services.AddEndpointsApiExplorer(); |
|||
services.AddControllers().AddXmlDataContractSerializerFormatters(); |
|||
services.AddHealthChecks(); |
|||
services.Configure<JsonOptions>(options => |
|||
{ |
|||
options.SerializerOptions.Converters.Add(new JsonStringEnumConverter()); |
|||
}); |
|||
services.Configure<Microsoft.AspNetCore.Mvc.JsonOptions>(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<ApplicationInsightsLoggerProvider>("traces", LogLevel.Trace); |
|||
} |
|||
|
|||
|
|||
private void JWTAuthentication(WebApplicationBuilder builder) |
|||
{ |
|||
List<string> audiences = new List<string>(); |
|||
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<string>(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<HideMethodsExternallyFilter>();
|
|||
// options.OperationFilter<SecurityRequirementsOperationFilter>();
|
|||
|
|||
#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(); |
|||
} |
@ -0,0 +1,6 @@ |
|||
namespace DealerSelection.Common.CommonBaseClass; |
|||
|
|||
public abstract class WebApiConfigurationCfgBase |
|||
{ |
|||
|
|||
} |
@ -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<string, string?> 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<T>(string key, bool mustExist) |
|||
{ |
|||
return GetSetting(key, default(T), mustExist); |
|||
} |
|||
|
|||
public static T? GetSetting<T>(string key, T? defaultValue = default) |
|||
{ |
|||
return GetSetting(key, defaultValue, false); |
|||
} |
|||
|
|||
public static T GetSetting<T>(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); |
|||
} |
|||
} |
|||
} |
@ -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; |
|||
} |
|||
} |
@ -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<SqlConnection> OpenCxnWithMappingAsync<T>() |
|||
{ |
|||
Task<SqlConnection> cxnTask = OpenCxnAsync(); |
|||
SetTypeMap<T>(); |
|||
|
|||
return await cxnTask; |
|||
} |
|||
|
|||
protected void SetTypeMap<T>() |
|||
{ |
|||
TypeMapHelper.SetTypeMap<T>(); |
|||
} |
|||
|
|||
} |
@ -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<T>() |
|||
{ |
|||
SqlConnection cxn = OpenCxnSync(); |
|||
SetTypeMap<T>(); |
|||
|
|||
return cxn; |
|||
} |
|||
|
|||
protected void SetTypeMap<T>() |
|||
{ |
|||
TypeMapHelper.SetTypeMap<T>(); |
|||
} |
|||
|
|||
} |
@ -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<T>() |
|||
{ |
|||
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; |
|||
} |
|||
} |
@ -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<SqlConnection> 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; |
|||
} |
|||
} |
@ -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; |
|||
} |
|||
} |
@ -0,0 +1,11 @@ |
|||
|
|||
namespace DealerSelection.Common.Data; |
|||
|
|||
public abstract class RepositoryDIBase |
|||
{ |
|||
public string CxnString { get; } |
|||
protected RepositoryDIBase(string cxnName) |
|||
{ |
|||
CxnString = ConnectionHelper.GetConnectionString(cxnName); |
|||
} |
|||
} |
@ -0,0 +1,56 @@ |
|||
<Project Sdk="Microsoft.NET.Sdk"> |
|||
|
|||
<PropertyGroup> |
|||
<TargetFramework>net6.0</TargetFramework> |
|||
<ImplicitUsings>enable</ImplicitUsings> |
|||
<Nullable>enable</Nullable> |
|||
</PropertyGroup> |
|||
|
|||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'"> |
|||
<NoWarn>1701;1702;8603;1822;8602;8604</NoWarn> |
|||
</PropertyGroup> |
|||
|
|||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'"> |
|||
<NoWarn>1701;1702;8603;1822;8602;8604</NoWarn> |
|||
</PropertyGroup> |
|||
|
|||
<ItemGroup> |
|||
<PackageReference Include="BouncyCastle.NetCore" Version="1.9.0" /> |
|||
<PackageReference Include="Dapper" Version="2.1.15" /> |
|||
<PackageReference Include="iTextSharp" Version="5.5.13.3" /> |
|||
<PackageReference Include="itextsharp.xmlworker" Version="5.5.13.3" /> |
|||
<PackageReference Include="Lamar" Version="12.0.2" /> |
|||
<PackageReference Include="Lamar.Microsoft.DependencyInjection" Version="12.0.0" /> |
|||
<PackageReference Include="Microsoft.AspNet.WebApi.Owin" Version="5.2.9" /> |
|||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="6.0.0" /> |
|||
<PackageReference Include="Microsoft.Extensions.Configuration" Version="7.0.0" /> |
|||
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="7.0.0" /> |
|||
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="7.0.4" /> |
|||
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="7.0.0" /> |
|||
<PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="7.0.0" /> |
|||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="7.0.0" /> |
|||
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="7.0.0" /> |
|||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="7.0.1" /> |
|||
<PackageReference Include="Microsoft.Extensions.Logging.ApplicationInsights" Version="2.21.0" /> |
|||
<PackageReference Include="Microsoft.IO.RecyclableMemoryStream" Version="2.3.2" /> |
|||
<PackageReference Include="Microsoft.Owin.Cors" Version="4.2.2" /> |
|||
<PackageReference Include="Microsoft.Owin.Host.SystemWeb" Version="4.2.2" /> |
|||
<PackageReference Include="Microsoft.Owin.Security.Jwt" Version="4.2.2" /> |
|||
<PackageReference Include="Microsoft.Owin.Security.OAuth" Version="4.2.2" /> |
|||
<PackageReference Include="SecurityCodeScan.VS2019" Version="5.6.7"> |
|||
<PrivateAssets>all</PrivateAssets> |
|||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> |
|||
</PackageReference> |
|||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" /> |
|||
<PackageReference Include="Swashbuckle.AspNetCore.Annotations" Version="6.5.0" /> |
|||
<PackageReference Include="System.Configuration.ConfigurationManager" Version="7.0.0" /> |
|||
<PackageReference Include="System.Data.SqlClient" Version="4.8.5" /> |
|||
</ItemGroup> |
|||
|
|||
<ItemGroup> |
|||
<Compile Update="Logging\AzureLogHelper.cs"> |
|||
<CopyToOutputDirectory>Never</CopyToOutputDirectory> |
|||
</Compile> |
|||
</ItemGroup> |
|||
|
|||
</Project> |
@ -0,0 +1,24 @@ |
|||
namespace DealerSelection.Common.Entity; |
|||
|
|||
/// <summary>
|
|||
/// An Attribute that provides a mapping between a property on an object and a fields in a database table.
|
|||
/// </summary>
|
|||
[AttributeUsage(AttributeTargets.Property)] |
|||
public sealed class FieldMapAttribute : Attribute |
|||
{ |
|||
readonly string _dbFieldName; |
|||
|
|||
/// <summary>
|
|||
/// Initialize a new FieldMapAttribute
|
|||
/// </summary>
|
|||
/// <param name="dbFieldName">Name of database field that this property represents</param>
|
|||
public FieldMapAttribute(string dbFieldName) |
|||
{ |
|||
_dbFieldName = dbFieldName; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Name of field that the perperty this attribute is attached to is mapped to.
|
|||
/// </summary>
|
|||
public string DbFieldName => _dbFieldName; |
|||
} |
@ -0,0 +1,8 @@ |
|||
using DealerSelection.Common.CommonBaseClass; |
|||
|
|||
namespace DealerSelection.Common.Exceptions; |
|||
|
|||
public class AuthorizationException : ExceptionBase |
|||
{ |
|||
public AuthorizationException(string message) : base(message) { } |
|||
} |
@ -0,0 +1,8 @@ |
|||
using DealerSelection.Common.CommonBaseClass; |
|||
|
|||
namespace DealerSelection.Common.Exceptions; |
|||
|
|||
public class DataNotFoundException : ExceptionBase |
|||
{ |
|||
public DataNotFoundException(string message) : base(message) { } |
|||
} |
@ -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) |
|||
{ |
|||
} |
|||
} |
@ -0,0 +1,8 @@ |
|||
using DealerSelection.Common.CommonBaseClass; |
|||
|
|||
namespace DealerSelection.Common.Exceptions; |
|||
|
|||
public class DuplicateException : ExceptionBase |
|||
{ |
|||
public DuplicateException(string message) : base(message) { } |
|||
} |
@ -0,0 +1,8 @@ |
|||
using DealerSelection.Common.CommonBaseClass; |
|||
|
|||
namespace DealerSelection.Common.Exceptions; |
|||
|
|||
public class NullValueException : ExceptionBase |
|||
{ |
|||
public NullValueException(string message) : base(message) { } |
|||
} |
@ -0,0 +1,8 @@ |
|||
using DealerSelection.Common.CommonBaseClass; |
|||
|
|||
namespace DealerSelection.Common.Exceptions; |
|||
|
|||
public class PartialSuccessException : ExceptionBase |
|||
{ |
|||
public PartialSuccessException(string message) : base(message) { } |
|||
} |
@ -0,0 +1,8 @@ |
|||
using DealerSelection.Common.CommonBaseClass; |
|||
|
|||
namespace DealerSelection.Common.Exceptions; |
|||
|
|||
public class ValidationException : ExceptionBase |
|||
{ |
|||
public ValidationException(string message) : base(message) { } |
|||
} |
@ -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; } |
|||
} |
@ -0,0 +1,38 @@ |
|||
namespace DealerSelection.Common.Helpers; |
|||
|
|||
public class SwashbuckleSchemaHelper |
|||
{ |
|||
private readonly Dictionary<string, int> _schemaNameRepetition = new (); |
|||
|
|||
/// <summary>
|
|||
/// Eliminate the case where more than one method returns the same type in different controllers
|
|||
/// swagger documentation to fail
|
|||
/// </summary>
|
|||
/// <param name="modelType"></param>
|
|||
/// <returns></returns>
|
|||
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(); |
|||
} |
|||
|
|||
} |
@ -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; |
|||
} |
|||
} |
@ -0,0 +1,9 @@ |
|||
using System.Data.SqlClient; |
|||
|
|||
namespace DealerSelection.Common.Interfaces.Data; |
|||
|
|||
public interface IRepositoryDIAsync |
|||
{ |
|||
string CxnString { get; } |
|||
Task<SqlConnection> OpenCxnAsync(); |
|||
} |
@ -0,0 +1,9 @@ |
|||
using System.Data.SqlClient; |
|||
|
|||
namespace DealerSelection.Common.Interfaces.Data; |
|||
|
|||
public interface IRepositoryDISync |
|||
{ |
|||
string CxnString { get; } |
|||
SqlConnection OpenCxnSync(); |
|||
} |
@ -0,0 +1,8 @@ |
|||
|
|||
|
|||
namespace DealerSelection.Common.Interfaces.HttpClient; |
|||
|
|||
public interface IHttpClientHandler |
|||
{ |
|||
System.Net.Http.HttpClient GetHttpClient(); |
|||
} |
@ -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; |
|||
} |
|||
} |
@ -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<string>("aZureWorkspaceId", true); |
|||
private static string aZureSharedKey = ConfigurationHelper.GetSetting<string>("aZureSharedKey", true); |
|||
private static string aZureLogType = ConfigurationHelper.GetSetting<string>("aZureLogType", true); |
|||
private static string aZureApiVersion = ConfigurationHelper.GetSetting<string>("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))}"; |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,28 @@ |
|||
|
|||
using Microsoft.Extensions.Primitives; |
|||
|
|||
namespace DealerSelection.Common.Logging; |
|||
|
|||
public class HttpHeaderHelper |
|||
{ |
|||
public static int? ExtractInt(string key, List<KeyValuePair<string, StringValues>> 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<KeyValuePair<string, StringValues>> headers) |
|||
{ |
|||
string? res = null; |
|||
KeyValuePair<string, StringValues> header = headers.FirstOrDefault(h=> h.Key == key); |
|||
if (header.Value.Any()) |
|||
res = header.Value.FirstOrDefault(); |
|||
return res; |
|||
} |
|||
} |
@ -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<ApiInfo> 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<string> 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<bool> 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<KeyValuePair<string, StringValues>> 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);
|
|||
|
|||
} |
|||
} |
@ -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}"; |
|||
} |
|||
} |
@ -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} "); |
|||
} |
|||
} |
@ -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); |
|||
} |
|||
} |
@ -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; |
|||
} |
|||
} |
|||
} |
|||
} |
@ -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; |
|||
|
|||
} |
|||
} |
|||
} |
@ -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<IJwtTokenApi>() |
|||
.Use<JwtTokenApi>() |
|||
.Singleton(); |
|||
|
|||
For<IAssignDealerApi>() |
|||
.Use<AssignDealerApi>() |
|||
.Singleton(); |
|||
|
|||
For<IMulesoftApi>() |
|||
.Use<MulesoftApi>() |
|||
.Singleton(); |
|||
|
|||
For<IHttpClientHandler>() |
|||
.Use<MyHttpClientHandler>() |
|||
.Singleton(); |
|||
For<IMulesoftTokenApi>() |
|||
.Use<MulesoftTokenApi>() |
|||
.Singleton(); |
|||
|
|||
} |
|||
} |
@ -0,0 +1,29 @@ |
|||
<Project Sdk="Microsoft.NET.Sdk"> |
|||
|
|||
<PropertyGroup> |
|||
<TargetFramework>net6.0</TargetFramework> |
|||
<ImplicitUsings>enable</ImplicitUsings> |
|||
<Nullable>enable</Nullable> |
|||
</PropertyGroup> |
|||
|
|||
<ItemGroup> |
|||
<None Include="..\..\.editorconfig" Link=".editorconfig" /> |
|||
</ItemGroup> |
|||
|
|||
<ItemGroup> |
|||
<PackageReference Include="BouncyCastle.NetCore" Version="1.9.0" /> |
|||
<PackageReference Include="iTextSharp" Version="5.5.13.3" /> |
|||
<PackageReference Include="itextsharp.xmlworker" Version="5.5.13.3" /> |
|||
<PackageReference Include="Lamar" Version="12.0.2" /> |
|||
<PackageReference Include="SecurityCodeScan.VS2019" Version="5.6.7"> |
|||
<PrivateAssets>all</PrivateAssets> |
|||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> |
|||
</PackageReference> |
|||
</ItemGroup> |
|||
|
|||
<ItemGroup> |
|||
<ProjectReference Include="..\DealerSelection.Api\DealerSelection.Api.csproj" /> |
|||
<ProjectReference Include="..\DealerSelection.Interface\DealerSelection.Api.Interface.csproj" /> |
|||
</ItemGroup> |
|||
|
|||
</Project> |
@ -0,0 +1,11 @@ |
|||
using Lamar; |
|||
namespace DealerSelection.DependencyInjection; |
|||
|
|||
public class DependencyInjectionBootStrapper : ServiceRegistry |
|||
{ |
|||
public DependencyInjectionBootStrapper() |
|||
{ |
|||
IncludeRegistry<InfrastructureRegistry>(); |
|||
IncludeRegistry<ApiRegistry>(); |
|||
} |
|||
} |
@ -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<MulesoftRepo.IRepository>() |
|||
.Use<MulesoftRepo.Repository>() |
|||
.Ctor<string>().Is("BOOKING") |
|||
.Transient(); |
|||
|
|||
For<JwtRepo.IJwtRepository>() |
|||
.Use<JwtRepo.JwtRepository>() |
|||
.Ctor<string>().Is("BOOKING") |
|||
.Transient(); |
|||
|
|||
For<AssignDealerRepo.IAssignDealerRepository>() |
|||
.Use<AssignDealerRepo.Repository>() |
|||
.Ctor<string>().Is("BOOKING") |
|||
.Transient(); |
|||
|
|||
For<Customerdetail.IRepository>() |
|||
.Use<Customerdetail.Repository>() |
|||
.Ctor<string>().Is("BOOKING") |
|||
.Transient(); |
|||
|
|||
} |
|||
|
|||
} |
@ -0,0 +1,7 @@ |
|||
|
|||
namespace DealerSelection.Api.Infrastructure.AssignDealer; |
|||
|
|||
public interface IAssignDealerRepository |
|||
{ |
|||
|
|||
} |
@ -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<Repository> logger) : base(cxnName) |
|||
{ |
|||
_logger = logger; |
|||
} |
|||
|
|||
} |
@ -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}"; |
|||
} |
|||
} |
@ -0,0 +1,13 @@ |
|||
using DealerSelection.Api.Infrastructure.Mulesoft; |
|||
using DealerSelection.Api.Models; |
|||
|
|||
namespace DealerSelection.Api.Infrastructure.CustomerDetail; |
|||
|
|||
public interface IRepository |
|||
{ |
|||
Task<int> UpdateDealerDetail(CustomerDealerInfoRequestDto customerInfo); |
|||
// Task<MulesoftCustomerInfoDto> GetCustomerData();
|
|||
Task<MulesoftCustomerInfoDto> GetCustomerData(int buid, int recordId); |
|||
Task<bool> IsDuplicateMobileNumber(int mobileNumber); |
|||
Task UpdateDealerSelectionJobStatus(int buId, int recordId, int mobileNumber, DealerSelectionJobStatus dealerSelectionJobStatus); |
|||
} |
@ -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<Repository> logger) : base(cxnName) |
|||
{ |
|||
_logger = logger; |
|||
} |
|||
|
|||
|
|||
public async Task<int> UpdateDealerDetail(CustomerDealerInfoRequestDto dto) |
|||
{ |
|||
try |
|||
{ |
|||
using (SqlConnection cxn = await OpenCxnAsync()) |
|||
{ |
|||
int receivedBookingId = await cxn.ExecuteScalarAsync<int>(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<MulesoftCustomerInfoDto> GetCustomerData(int buId, int recordId) |
|||
{ |
|||
try |
|||
{ |
|||
using (SqlConnection cxn = await OpenCxnAsync()) |
|||
{ |
|||
IEnumerable<MulesoftCustomerInfoDto> cusotmerInfo = await cxn.QueryAsync<MulesoftCustomerInfoDto>(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<bool> IsDuplicateMobileNumber(int mobileNumber) |
|||
{ |
|||
try |
|||
{ |
|||
using (SqlConnection cxn = await OpenCxnAsync()) |
|||
{ |
|||
bool isDuplicate = await cxn.QueryFirstAsync<bool>(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}"); |
|||
} |
|||
} |
|||
|
|||
} |
@ -0,0 +1,37 @@ |
|||
<Project Sdk="Microsoft.NET.Sdk"> |
|||
|
|||
<PropertyGroup> |
|||
<TargetFramework>net6.0</TargetFramework> |
|||
<ImplicitUsings>enable</ImplicitUsings> |
|||
<Nullable>enable</Nullable> |
|||
</PropertyGroup> |
|||
|
|||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'"> |
|||
<NoWarn>1701;1702;8618;8603</NoWarn> |
|||
</PropertyGroup> |
|||
|
|||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'"> |
|||
<NoWarn>1701;1702;8618;8603</NoWarn> |
|||
</PropertyGroup> |
|||
|
|||
<ItemGroup> |
|||
<PackageReference Include="BouncyCastle.NetCore" Version="1.9.0" /> |
|||
<PackageReference Include="iTextSharp" Version="5.5.13.3" /> |
|||
<PackageReference Include="itextsharp.xmlworker" Version="5.5.13.3" /> |
|||
<PackageReference Include="Microsoft.ApplicationBlocks.Data" Version="2.0.0" /> |
|||
<PackageReference Include="Microsoft.SqlServer.Server" Version="1.0.0" /> |
|||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" /> |
|||
<PackageReference Include="SecurityCodeScan.VS2019" Version="5.6.7"> |
|||
<PrivateAssets>all</PrivateAssets> |
|||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> |
|||
</PackageReference> |
|||
<PackageReference Include="System.Configuration.ConfigurationManager" Version="7.0.0" /> |
|||
<PackageReference Include="System.Data.SqlClient" Version="4.8.5" /> |
|||
</ItemGroup> |
|||
|
|||
<ItemGroup> |
|||
<ProjectReference Include="..\DealerSelection.Api.Models\DealerSelection.Api.Models.csproj" /> |
|||
<ProjectReference Include="..\DealerSelection.Common\DealerSelection.Common.csproj" /> |
|||
</ItemGroup> |
|||
|
|||
</Project> |
@ -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); |
|||
} |
@ -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<Repository> 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); |
|||
} |
|||
} |
|||
} |
@ -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; } |
|||
} |
@ -0,0 +1,9 @@ |
|||
using DealerSelection.Api.Models; |
|||
namespace DealerSelection.Api.Infrastructure.Jwt; |
|||
|
|||
public interface IJwtRepository |
|||
{ |
|||
Task<string> GenerateToken(AuthModel user); |
|||
Task<bool> Authenticate(AuthValidateModelDto userLogin); |
|||
Task<TokenValidProperty> IsTokenExpired(string tokenValue); |
|||
} |
@ -0,0 +1,23 @@ |
|||
using DealerSelection.Api.Models; |
|||
|
|||
|
|||
namespace DealerSelection.Api.Infrastructure.Jwt; |
|||
|
|||
public class JwtRepository : IJwtRepository |
|||
{ |
|||
|
|||
public Task<bool> Authenticate(AuthValidateModelDto userLogin) |
|||
{ |
|||
throw new NotImplementedException(); |
|||
} |
|||
|
|||
public Task<string> GenerateToken(AuthModel user) |
|||
{ |
|||
throw new NotImplementedException(); |
|||
} |
|||
|
|||
public Task<TokenValidProperty> IsTokenExpired(string tokenValue) |
|||
{ |
|||
throw new NotImplementedException(); |
|||
} |
|||
} |
@ -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}."; |
|||
} |
|||
} |
|||
|
@ -0,0 +1,10 @@ |
|||
|
|||
namespace DealerSelection.Api.Infrastructure.Mulesoft; |
|||
|
|||
public interface IRepository |
|||
{ |
|||
Task<MulesoftCustomerInfoDto> GetCustomerInfo(int buId, string bookingId); |
|||
Task UpdateMulesoftResponse(int buId,int recordId,string bookingId,string message,string isSuccessBooking, LeadData leadData); |
|||
Task InsertAndUpdateDealerRecord(DealerDetailDto dto); |
|||
Task<List<MulesoftCustomerInfoDto>> GetDataForLsqPush(int buId); |
|||
} |
@ -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; } |
|||
} |
|||
|
@ -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<Repository> logger) : base(cxnName) |
|||
{ |
|||
_logger = logger; |
|||
} |
|||
|
|||
public async Task<MulesoftCustomerInfoDto> GetCustomerInfo(int buId, string bookingId) |
|||
{ |
|||
try |
|||
{ |
|||
using (SqlConnection cxn = await OpenCxnWithMappingAsync<MulesoftCustomerInfoDto>()) |
|||
{ |
|||
IEnumerable<MulesoftCustomerInfoDto> cusotmerInfo = await cxn.QueryAsync<MulesoftCustomerInfoDto>(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<int>()) |
|||
{ |
|||
await cxn.QueryAsync<int>(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<int>()) |
|||
{ |
|||
await cxn.QueryAsync<int>(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<List<MulesoftCustomerInfoDto>> GetDataForLsqPush(int buId) |
|||
{ |
|||
try |
|||
{ |
|||
using (SqlConnection cxn = await OpenCxnAsync()) |
|||
{ |
|||
IEnumerable<MulesoftCustomerInfoDto> lsqDto = await cxn.QueryAsync<MulesoftCustomerInfoDto>(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); |
|||
} |
|||
|
|||
} |
|||
} |
@ -0,0 +1,27 @@ |
|||
<Project Sdk="Microsoft.NET.Sdk"> |
|||
|
|||
<PropertyGroup> |
|||
<TargetFramework>net6.0</TargetFramework> |
|||
<ImplicitUsings>enable</ImplicitUsings> |
|||
<Nullable>enable</Nullable> |
|||
</PropertyGroup> |
|||
|
|||
<ItemGroup> |
|||
<PackageReference Include="BouncyCastle.NetCore" Version="1.9.0" /> |
|||
<PackageReference Include="iTextSharp" Version="5.5.13.3" /> |
|||
<PackageReference Include="itextsharp.xmlworker" Version="5.5.13.3" /> |
|||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="7.0.1" /> |
|||
<PackageReference Include="Microsoft.Extensions.Logging.ApplicationInsights" Version="2.21.0" /> |
|||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" /> |
|||
<PackageReference Include="SecurityCodeScan.VS2019" Version="5.6.7"> |
|||
<PrivateAssets>all</PrivateAssets> |
|||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> |
|||
</PackageReference> |
|||
</ItemGroup> |
|||
|
|||
<ItemGroup> |
|||
<ProjectReference Include="..\DealerSelection.Api.Models\DealerSelection.Api.Models.csproj" /> |
|||
<ProjectReference Include="..\DealerSelection.Infrastructure\DealerSelection.Api.Infrastructure.csproj" /> |
|||
</ItemGroup> |
|||
|
|||
</Project> |
@ -0,0 +1,7 @@ |
|||
namespace DealerSelection.Api.Interface; |
|||
|
|||
public interface IAssignDealerApi |
|||
{ |
|||
Task GetCustomerDataForJob(int buId, int recordId); |
|||
|
|||
} |
@ -0,0 +1,9 @@ |
|||
using Newtonsoft.Json.Linq; |
|||
namespace DealerSelection.Api.Interface; |
|||
|
|||
public interface IInfoBipSmsServiceApi |
|||
{ |
|||
Task<JObject> sendOTP(int buId, string strMobile); |
|||
Task<JObject> resendOTP(int buId, string strMobile, string strOtpPinId); |
|||
Task<JObject> verifyOTP(int buId, string strMobile, string strOtpPinId, string otpPin); |
|||
} |
@ -0,0 +1,9 @@ |
|||
using DealerSelection.Api.Models; |
|||
namespace DealerSelection.Api.Interface; |
|||
|
|||
public interface IJwtTokenApi |
|||
{ |
|||
Task<string> GenerateToken(AuthValidateModel user); |
|||
Task<bool> Authenticate(AuthValidateModel userLogin); |
|||
Task<TokenValidProperty> IsTokenExpired(string tokenValue); |
|||
} |
@ -0,0 +1,20 @@ |
|||
using DealerSelection.Api.Infrastructure.Mulesoft; |
|||
using DealerSelection.Api.Models; |
|||
|
|||
namespace DealerSelection.Api.Interface; |
|||
|
|||
public interface IMulesoftApi |
|||
{ |
|||
Task<MulesoftResponse> GetDealers(int buId, string buUnit, string strlat, string strLong); |
|||
Task<MulesoftResponse> GetAndInsertDealerDetails(int buId, string dealerCode); |
|||
Task<MulesoftResponse> GetStateWisePrice(int buId, string stateCode, string itemId); |
|||
Task<MulesoftResponse> GetModelOnBrand(int buId, string brand); |
|||
Task<Response> CallLSQBookingApi( MulesoftCustomerInfoDto customerInfo); |
|||
Task<MulesoftCustomerInfoDto> GetCustomerInfo(int buId, string bookingId); |
|||
Task<List<MulesoftCustomerInfoDto>> GetDataForLsqPush (int buId); |
|||
Task<MulesoftResponse> GetActiveState(int buId); |
|||
|
|||
Task<MulesoftResponse> GetActiveCity(int buId, string stateCode); |
|||
|
|||
Task<MulesoftResponse> ModelDetailsByItemCode(int buId, string itemId); |
|||
} |
@ -0,0 +1,7 @@ |
|||
|
|||
namespace DealerSelection.Api.Interface; |
|||
|
|||
public interface IMulesoftTokenApi |
|||
{ |
|||
Task<string> FetchToken(); |
|||
} |
@ -0,0 +1,10 @@ |
|||
|
|||
using DealerSelection.Api.Models; |
|||
|
|||
namespace DealerSelection.Api.Interface; |
|||
|
|||
public interface IYellowAIApi |
|||
{ |
|||
Task UpdateSelectedDealer(CustomerDealerInfoRequest request); |
|||
|
|||
} |
@ -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; } |
|||
} |
@ -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; } |
|||
} |
@ -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; } |
|||
|
|||
} |
@ -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; } |
|||
|
|||
|
|||
} |
@ -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; } |
|||
} |
@ -0,0 +1,20 @@ |
|||
<Project Sdk="Microsoft.NET.Sdk"> |
|||
|
|||
<PropertyGroup> |
|||
<TargetFramework>net6.0</TargetFramework> |
|||
<ImplicitUsings>enable</ImplicitUsings> |
|||
<Nullable>enable</Nullable> |
|||
</PropertyGroup> |
|||
|
|||
<ItemGroup> |
|||
<PackageReference Include="BouncyCastle.NetCore" Version="1.9.0" /> |
|||
<PackageReference Include="iTextSharp" Version="5.5.13.3" /> |
|||
<PackageReference Include="itextsharp.xmlworker" Version="5.5.13.3" /> |
|||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" /> |
|||
<PackageReference Include="SecurityCodeScan.VS2019" Version="5.6.7"> |
|||
<PrivateAssets>all</PrivateAssets> |
|||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> |
|||
</PackageReference> |
|||
</ItemGroup> |
|||
|
|||
</Project> |
@ -0,0 +1,34 @@ |
|||
|
|||
namespace DealerSelection.WebApi.Models; |
|||
|
|||
public class MulesoftResponse |
|||
{ |
|||
public int StatusCode { get; set; } |
|||
public bool IsRequestSuccessfull { get; set; } |
|||
public List<Data> 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; } |
|||
} |
|||
|
@ -0,0 +1,7 @@ |
|||
|
|||
namespace DealerSelection.WebApi.Models; |
|||
|
|||
public class PaymentLinkResponse : Response |
|||
{ |
|||
public string SourceUrl { get; set; } |
|||
} |
@ -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; } |
|||
|
|||
} |
@ -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; } |
|||
} |
@ -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; } |
|||
} |
@ -0,0 +1,8 @@ |
|||
namespace DealerSelection.WebApi.Models; |
|||
|
|||
public class StateResponse |
|||
{ |
|||
public string State { get; set; } |
|||
public string StateCode { get; set; } |
|||
|
|||
} |
@ -0,0 +1,12 @@ |
|||
{ |
|||
"version": 1, |
|||
"isRoot": true, |
|||
"tools": { |
|||
"dotnet-ef": { |
|||
"version": "7.0.9", |
|||
"commands": [ |
|||
"dotnet-ef" |
|||
] |
|||
} |
|||
} |
|||
} |
@ -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<Api.Models.Response, Response>(); |
|||
cfg.CreateMap<Api.Models.MulesoftResponse, MulesoftResponse>(); |
|||
cfg.CreateMap<CustomerDealerInfoRequest, Api.Models.CustomerDealerInfoRequest>(); |
|||
}); |
|||
} |
|||
|
|||
public static Response MapResponse(Api.Models.Response from) |
|||
{ |
|||
return Config.CreateMapper().Map<Response>(from); |
|||
} |
|||
|
|||
public static MulesoftResponse MapMulesoftResponse(Api.Models.MulesoftResponse from) |
|||
{ |
|||
return Config.CreateMapper().Map<Api.Models.MulesoftResponse, MulesoftResponse>(from); |
|||
} |
|||
|
|||
public static Api.Models.CustomerDealerInfoRequest MapCustomerDealerInfoRequest(CustomerDealerInfoRequest from) |
|||
{ |
|||
return Config.CreateMapper().Map<CustomerDealerInfoRequest, Api.Models.CustomerDealerInfoRequest>(from); |
|||
} |
|||
|
|||
} |
Some files were not shown because too many files changed in this diff
Write
Preview
Loading…
Cancel
Save
Reference in new issue