Search functionality for the Fraud Manager
Advanced filters for the Queue creation flow Deployment to 2 tenants Other Changes Simplified Azure Maps user management Added timezone info to local dates on the Item Details page Performance improvements Optimized item enrichment procedure Deployment scripmt improvement Hotfix enrichment for purchases with rich relations Improve enrichment logging
This commit is contained in:
Родитель
eb235c67ba
Коммит
504e85ab62
|
@ -133,14 +133,18 @@ Configuration files are available in the future in AppService.
|
|||
**WARNING!** Redeployment will override any manual changes in configuration files made at AppService.
|
||||
|
||||
# Deploy application
|
||||
## Initial deployment
|
||||
## Single tenant deployment
|
||||
Single tenant deployment creates all objects (Azure AD applications, azure resources) in single tenant.
|
||||
It also use same tenant Active Directory to authenticate users, accessing the application.
|
||||
|
||||
### Initial deployment (single tenant)
|
||||
When deploying the application for the first time, the mail account password should be provided (see step 2 on
|
||||
*Prerequisites*). Use the following command to initiate deployment with prompting for mail account password:
|
||||
```
|
||||
pwsh deploy.ps1 -config main.parameters.<X>.json -setMailPassword
|
||||
```
|
||||
Mail account password is stored in Azure Key Vault.
|
||||
## Redeployments
|
||||
### Redeployments (single tenants)
|
||||
If solution is already deployed, in order to apply changes, use the following command
|
||||
```
|
||||
pwsh deploy.ps1 -config main.parameters.<X>.json
|
||||
|
@ -152,6 +156,68 @@ Note: it is possible to automate deployment and exclude prompting password by in
|
|||
from some powershell wrapper script, and provide mail account password as **secureString** type parameter
|
||||
**-mailSecurePassword** .
|
||||
|
||||
## Two tenants deployment
|
||||
Two tenants deployment separates deployment of objects into two tenants: client and provider.
|
||||
Client tenant in this case used to create Azure AD application with necessary permissions, to install
|
||||
DFP application, and to authenticate users, accessing the application.
|
||||
Provider tenant is used to deploy all Azure resources required to implement the application.
|
||||
|
||||
Two tenants deployment splitted into two phases. Phase one should be performed in client tenant, and phase
|
||||
two in provider tenant
|
||||
|
||||
### Initial deployment (two tenants)
|
||||
|
||||
#### Phase one (client side)
|
||||
During this phase Azure AD application and service principal will be created in the client tenant.
|
||||
Use the following command:
|
||||
```pwsh ./deploy_ad_app.ps1 -prefix <prefix> -envType <Dev|Prod> -tenantId <tenant_id>```
|
||||
At this phase one will be prompted for the azure active directory application secret. This secret should
|
||||
be shared with the provider in a secure manner. Also the output block starting from `Collect shared parameters`
|
||||
should be shared with the provider.
|
||||
|
||||
#### Phase two (provider side)
|
||||
Before starting deployment on provider side, shared parameters from client (see previous step) should be
|
||||
added to environment configuration file main.parameters.<X>.json
|
||||
```json
|
||||
"clientTenantId": {
|
||||
"value": ""
|
||||
},
|
||||
"clientTenantShortName": {
|
||||
"value": ""
|
||||
},
|
||||
"appClientId": {
|
||||
"value": ""
|
||||
},
|
||||
"appSpId": {
|
||||
"value": ""
|
||||
},
|
||||
"dfpSpId": {
|
||||
"value": ""
|
||||
}
|
||||
```
|
||||
When the environment configuration file is ready, run the following command to start the deployment:
|
||||
```
|
||||
pwsh ./deploy.ps1 -config main.parameters.<X>.json -setMailPassword -SetClientSecret -twoTenants
|
||||
```
|
||||
One will be prompted to enter the mail account password and azure application secret, which was shared
|
||||
with the client on phase one.
|
||||
|
||||
### Redeployments (two tenants)
|
||||
|
||||
#### Redeployment (two tenants, client side)
|
||||
Normally there is no reason to re-run deployment on the client side. It can happen when there is a requirement
|
||||
to update client application secret, application reply urls, or client application permissions.
|
||||
The redeployment can be run with the command
|
||||
```pwsh ./deploy_phase1.ps1 -prefix <prefix> -envType <Dev|Prod> -tenantId <tenant_id>```
|
||||
Be aware, that when client application is updated, it is not applied to service principal automatically. It
|
||||
might require to re-create service principal for the application.
|
||||
|
||||
#### Redeployment (two tenants, provider side)
|
||||
If solution is already deployed, in order to apply changes, use the following command
|
||||
```
|
||||
pwsh deploy.ps1 -config main.parameters.<X>.json -twoTenants
|
||||
```
|
||||
|
||||
## Post-deployment actions
|
||||
Once you've installed the new environment from scratch you need to configure application for your needs.
|
||||
Please, find below the tuning description.
|
||||
|
@ -159,7 +225,7 @@ Please, find below the tuning description.
|
|||
### Notification templates
|
||||
Analytics BE module uses notification templates that are stored in the related CosmosDB database called `AnalyticsDB`.
|
||||
The application creates default templates automatically if there are no other templates in the DB.
|
||||
In order to change a desired template, you can find it in the `ConfigurableAppSetting` container and edit it as your wish.
|
||||
In order to change a desired template, you can find it in the `ConfigurableAppSettings` container and edit it as your wish.
|
||||
|
||||
You can use any placeholder that mentioned in
|
||||
[code](../backend/analytics/src/main/java/com/griddynamics/msd365fp/manualreview/analytics/config/Constants.java)
|
||||
|
@ -168,7 +234,7 @@ with the `MAIL_TAG_` prefix
|
|||
### External tool links
|
||||
Queue BE module store templates of External Tool Links in the related Cosmos DB database `QueuesDB`.
|
||||
There are no default templates in the application code, so you need to define them manually.
|
||||
For that, open the `ConfigurableAppSetting` container and put templates in the following format:
|
||||
For that, open the `ConfigurableAppSettings` container and put templates in the following format:
|
||||
```json
|
||||
{
|
||||
"type": "review-console-links",
|
||||
|
|
|
@ -19,7 +19,7 @@ $tenantId = $json.parameters.tenantId.value
|
|||
$deploymentResourceGroup = $prefix + "-rg"
|
||||
$logWorkspace = $prefix + "-log-analytics-ws"
|
||||
$logWorkspaceSecondary = $prefix + "-secondary-log-analytics-ws"
|
||||
$mapsGroupName = $prefix + "-map-access"
|
||||
$mapAppName = $prefix + "-map"
|
||||
|
||||
|
||||
# Login to Azure and set context
|
||||
|
@ -57,28 +57,22 @@ foreach ($la in @($logWorkspace, $logWorkspaceSecondary)) {
|
|||
--force true -y
|
||||
}
|
||||
|
||||
# remove AD service principal
|
||||
if (Get-AzADServicePrincipal -DisplayName $prefix -ErrorAction Ignore) {
|
||||
Write-Host "Removing Azure AD service principal $prefix"
|
||||
Remove-AzADServicePrincipal `
|
||||
-DisplayName $prefix `
|
||||
-Force
|
||||
}
|
||||
foreach ($app in @($prefix, $mapAppName)) {
|
||||
# remove AD service principal
|
||||
if (Get-AzADServicePrincipal -DisplayName $app -ErrorAction Ignore) {
|
||||
Write-Host "Removing Azure AD service principal $app"
|
||||
Remove-AzADServicePrincipal `
|
||||
-DisplayName $app `
|
||||
-Force
|
||||
}
|
||||
|
||||
# remove AD application
|
||||
if (Get-AzADApplication -DisplayName $prefix -ErrorAction Ignore) {
|
||||
Write-Host "Removing Azure AD application $prefix"
|
||||
Remove-AzADApplication `
|
||||
-DisplayName $prefix `
|
||||
-Force
|
||||
}
|
||||
|
||||
# remove AD maps group
|
||||
if (Get-AzADGroup -DisplayName $mapsGroupName -ErrorAction Ignore) {
|
||||
Write-Host "Removing Azure AD group $mapsGroupName"
|
||||
Remove-AzADGroup `
|
||||
-DisplayName $mapsGroupName `
|
||||
-Force
|
||||
# remove AD application
|
||||
if (Get-AzADApplication -DisplayName $app -ErrorAction Ignore) {
|
||||
Write-Host "Removing Azure AD application $app"
|
||||
Remove-AzADApplication `
|
||||
-DisplayName $app `
|
||||
-Force
|
||||
}
|
||||
}
|
||||
|
||||
# remove deployment resource group
|
||||
|
|
294
arm/deploy.ps1
294
arm/deploy.ps1
|
@ -12,33 +12,13 @@ Param(
|
|||
|
||||
[switch] $setMailPassword,
|
||||
|
||||
[switch] $setClientSecret,
|
||||
|
||||
[switch] $twoTenants,
|
||||
|
||||
[string] $location = "westus"
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
$frontendContainer = "web"
|
||||
|
||||
# Dict with java microservice name and path to base directory
|
||||
$applications = @{
|
||||
"queues" = "../backend/queues"
|
||||
"analytics" = "../backend/analytics"
|
||||
}
|
||||
$version = Get-Date -Format FileDateTimeUniversal
|
||||
# Path to fronend build directory
|
||||
$frontendBuildPath = "../frontend/scripts"
|
||||
|
||||
# DFP roles definition
|
||||
$dfpRoles = @{}
|
||||
$dfpRoles["Dev"] = @(
|
||||
"Sandbox_Risk_API",
|
||||
"Sandbox_ManualReview_API"
|
||||
)
|
||||
$dfpRoles["Prod"] = @(
|
||||
"Risk_API",
|
||||
"ManualReview_API"
|
||||
)
|
||||
|
||||
# Read prefix from json
|
||||
$json = Get-Content $config | ConvertFrom-Json
|
||||
|
||||
|
@ -46,7 +26,17 @@ $prefix = $json.parameters.prefix.value
|
|||
$subscriptionId = $json.parameters.subscriptionId.value
|
||||
$tenantId = $json.parameters.tenantId.value
|
||||
$envType = $json.parameters.envType.value
|
||||
$customDomain = $json.parameters.customDomain.value
|
||||
$clientTenantId = $tenantId
|
||||
|
||||
if ($twoTenants) {
|
||||
$clientTenantId = $json.parameters.clientTenantId.value
|
||||
$clientAdApp = @{
|
||||
"appClientId" = $json.parameters.appClientId.value
|
||||
"appSpId" = $json.parameters.appSpId.value
|
||||
"dfpSpId" = $json.parameters.dfpSpId.value
|
||||
"clientTenantShortName" = $json.parameters.clientTenantShortName.value
|
||||
}
|
||||
}
|
||||
|
||||
$deploymentResourceGroup = $prefix + "-rg"
|
||||
$deploymentStorageAccount = $prefix.ToLower().Replace("-","") + "deploysa"
|
||||
|
@ -54,157 +44,11 @@ $deploymentContainer = "deploy"
|
|||
$sasTokenHours = 24 * 365 # one year
|
||||
$deploymentIdentity = $prefix + "-deploy-identity"
|
||||
$keyVaultName = $prefix.ToLower().Replace("-","") + "keyvault"
|
||||
|
||||
$mapsGroupName = $prefix + "-map-access"
|
||||
$mapAppName = $prefix + "-map"
|
||||
|
||||
$baseDir = Get-Location
|
||||
|
||||
function BuildFrontend {
|
||||
Set-Location "${baseDir}/$frontendBuildPath"
|
||||
Copy-Item -Path "config.template.json" -Destination "../public/config.json"
|
||||
yarn install
|
||||
yarn build
|
||||
if ($LastExitCode -ne 0) {
|
||||
throw "Build failed, check logs"
|
||||
}
|
||||
New-Item -Path "${baseDir}/build" -Name "frontend" -ItemType "directory" -ErrorAction Ignore
|
||||
Copy-Item -Path "../build/*" -Destination "${baseDir}/build/frontend" -Recurse
|
||||
Set-Location $baseDir
|
||||
}
|
||||
|
||||
function BuildBackend {
|
||||
foreach ($app in $applications.GetEnumerator()) {
|
||||
Write-Host "=== Building $($app.Name) app..."
|
||||
Set-Location "${baseDir}/$($app.Value)"
|
||||
if (CheckOSWindows) {
|
||||
./gradlew.bat clean packageDist --console=plain
|
||||
} else {
|
||||
./gradlew clean packageDist --console=plain
|
||||
}
|
||||
if ($LastExitCode -ne 0) {
|
||||
throw "Build failed, check logs"
|
||||
}
|
||||
New-Item -Path "${baseDir}/build" -Name "$($app.Name)" -ItemType "directory" -ErrorAction Ignore
|
||||
Copy-Item -Path "build/dist/target.zip" -Destination "${baseDir}/build/$($app.Name)/target.zip" -Recurse
|
||||
}
|
||||
}
|
||||
|
||||
function GetRandomPassword {
|
||||
-join ('abcdefghkmnrstuvwxyzABCDEFGHKLMNPRSTUVWXYZ0123456789'.ToCharArray() | Get-Random -Count 32)
|
||||
}
|
||||
|
||||
function ProvideCleanContainer {
|
||||
param (
|
||||
$storageContainer,
|
||||
$storageContext
|
||||
)
|
||||
|
||||
$sc = Get-AzStorageContainer -Name $storageContainer -Context $storageContext -ErrorAction Ignore
|
||||
if (!$sc) {
|
||||
Write-Host "= Create container $storageContainer"
|
||||
New-AzStorageContainer `
|
||||
-Name $storageContainer `
|
||||
-Context $storageContext
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Host "= Clean container $storageContainer"
|
||||
Get-AzStorageBlob -Container $storageContainer -Context $storageContext `
|
||||
| Where-Object { $_.Name -notMatch '^.*target.*zip' } `
|
||||
| Remove-AzStorageBlob
|
||||
}
|
||||
}
|
||||
|
||||
function GrantDfpPermissionWin {
|
||||
param (
|
||||
[string] $clientAppName,
|
||||
[string] $dfpRoleName
|
||||
)
|
||||
|
||||
Write-Host "= Assign role $dfpRoleName to app" $clientAppName
|
||||
|
||||
$app_name = "Dynamics 365 Fraud Protection"
|
||||
$sp = Get-AzureADServicePrincipal -Filter "displayName eq '$app_name'"
|
||||
|
||||
$c_appRole = $sp.AppRoles | Where-Object { $_.DisplayName -eq $dfpRoleName }
|
||||
$c_sp = Get-AzureADServicePrincipal -Filter "displayName eq '$clientAppName'"
|
||||
|
||||
$roleAssigned = Get-AzureADServiceAppRoleAssignedTo -ObjectId $c_sp.ObjectId `
|
||||
| Where-Object { $_.Id -eq $c_appRole.Id }
|
||||
|
||||
if(!($roleAssigned))
|
||||
{
|
||||
Write-host "Assigning DFP role ..."
|
||||
New-AzureADServiceAppRoleAssignment `
|
||||
-ObjectId $c_sp.ObjectId `
|
||||
-PrincipalId $c_sp.ObjectId `
|
||||
-ResourceId $sp.ObjectId `
|
||||
-Id $c_appRole.Id
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-host "DFP role is already assigned"
|
||||
}
|
||||
}
|
||||
|
||||
function CheckOSWindows
|
||||
{
|
||||
$envOS = Get-ChildItem -Path Env:OS -ErrorAction Ignore
|
||||
return ( $envOS -And $envOS.value.Contains('Windows') )
|
||||
}
|
||||
|
||||
function PutSecret {
|
||||
param (
|
||||
[string] $vaultName,
|
||||
[string] $secretName,
|
||||
[string] $secretValue,
|
||||
[SecureString] $secretSecureValue
|
||||
)
|
||||
|
||||
Write-Host "= Put secret $secretName to Key Vault $vaultName"
|
||||
if ($secretValue) {
|
||||
$secretSecureValue = ConvertTo-SecureString $secretValue -AsPlainText -Force
|
||||
}
|
||||
Set-AzKeyVaultSecret `
|
||||
-VaultName $vaultName `
|
||||
-Name $secretName `
|
||||
-SecretValue $secretSecureValue
|
||||
}
|
||||
|
||||
function GenReplyUrls {
|
||||
# Define Azure app reply urls
|
||||
$replyUrls = @(
|
||||
"https://$prefix.azurefd.net/login",
|
||||
"https://$prefix-queues.azurewebsites.net/oauth2-redirect.html",
|
||||
"https://$prefix-queues-secondary.azurewebsites.net/oauth2-redirect.html",
|
||||
"https://$prefix-analytics.azurewebsites.net/oauth2-redirect.html",
|
||||
"https://$prefix-analytics-secondary.azurewebsites.net/oauth2-redirect.html"
|
||||
)
|
||||
|
||||
$localSwaggerUri = "http://localhost:8080/oauth2-redirect.html"
|
||||
$localFrontUri = "http://localhost:3000/login"
|
||||
|
||||
if ($envType -eq "Dev") {
|
||||
$replyUrls += @($localSwaggerUri, $localFrontUri)
|
||||
}
|
||||
if ($customDomain -And ($customDomain -ne "UNDEFINED")) {
|
||||
$replyUrls += "https://${customDomain}/login"
|
||||
}
|
||||
|
||||
return $replyUrls
|
||||
}
|
||||
|
||||
function GetTenantShortName {
|
||||
param(
|
||||
[string] $TenantId
|
||||
)
|
||||
|
||||
foreach ($domain in (Get-AzTenant -TenantId $tenantId).domains) {
|
||||
if ($domain -match '(.*)\.onmicrosoft\.com') {
|
||||
return $Matches.1
|
||||
}
|
||||
}
|
||||
}
|
||||
. $baseDir/functions.ps1
|
||||
|
||||
################################################################# MAIN PROGRAM
|
||||
|
||||
|
@ -213,6 +57,10 @@ if ($setMailPassword) {
|
|||
$mailSecurePassword = Read-Host "Enter the mail account password" -AsSecureString
|
||||
}
|
||||
|
||||
# Read client secret when azure app deployed to different tenant
|
||||
if ($setClientSecret) {
|
||||
$clientSecureSecret = Read-Host "Enter the Azure application secret" -AsSecureString
|
||||
}
|
||||
|
||||
Write-Host "=== Setting Azure context..."
|
||||
if (!(Set-AzContext -SubscriptionId $subscriptionId -TenantId $tenantId -ErrorAction Ignore)) {
|
||||
|
@ -277,20 +125,40 @@ if (!($vault)) {
|
|||
-Name $keyVaultName `
|
||||
-ResourceGroupName $deploymentResourceGroup `
|
||||
-Location $location `
|
||||
-EnabledForTemplateDeployment `
|
||||
-DisableSoftDelete
|
||||
-EnabledForTemplateDeployment
|
||||
}
|
||||
|
||||
# Store app client secret in Key Vault if it was provided
|
||||
Write-Host "=== Provide Azure AD App client secret"
|
||||
if (!(Get-AzKeyVaultSecret -Name "client-secret" -VaultName $keyVaultName))
|
||||
{
|
||||
$clientSecret = GetRandomPassword
|
||||
PutSecret -vaultName $keyVaultName -secretName "client-secret" -secretValue $clientSecret
|
||||
if (!($clientSecureSecret)) {
|
||||
if ($twoTenants) {
|
||||
Write-Host "When Azure app installed to different tenant, deployment should be done with -SetClientSecret flag"
|
||||
throw "Client secret not provided"
|
||||
}
|
||||
$clientSecret = GetRandomPassword
|
||||
$clientSecureSecret = ConvertTo-SecureString $clientSecret -AsPlainText -Force
|
||||
|
||||
}
|
||||
PutSecret -vaultName $keyVaultName -secretName "client-secret" -secretSecureValue $clientSecureSecret
|
||||
}
|
||||
else
|
||||
{
|
||||
$clientSecret = (Get-AzKeyVaultSecret -VaultName $keyVaultName -Name "client-secret").SecretValueText
|
||||
$clientSecureSecret = ConvertTo-SecureString $clientSecret -AsPlainText -Force
|
||||
}
|
||||
|
||||
# Store Map app client secret in Key Vault if it was provided
|
||||
Write-Host "=== Provide Azure AD Map App client secret"
|
||||
if (!(Get-AzKeyVaultSecret -Name "map-client-secret" -VaultName $keyVaultName))
|
||||
{
|
||||
$mapClientSecret = GetRandomPassword
|
||||
PutSecret -vaultName $keyVaultName -secretName "map-client-secret" -secretValue $mapClientSecret
|
||||
}
|
||||
else
|
||||
{
|
||||
$mapClientSecret = (Get-AzKeyVaultSecret -VaultName $keyVaultName -Name "map-client-secret").SecretValueText
|
||||
}
|
||||
|
||||
# Store mail password in Key Vault if it was provided
|
||||
|
@ -299,36 +167,22 @@ if ($mailSecurePassword)
|
|||
PutSecret -vaultName $keyVaultName -secretName "spring-mail-password" -secretSecureValue $mailSecurePassword
|
||||
}
|
||||
|
||||
# Register application in Azure AD
|
||||
Write-Host "=== Create Azure App registration"
|
||||
$replyUrls = GenReplyUrls
|
||||
./deploy_ad_app.ps1 -AD_APP_NAME "$prefix" -CLIENT_SECRET "$clientSecret" -REPLY_URLS $replyUrls
|
||||
|
||||
# read application id and service principal id
|
||||
$appAd = Get-AzADApplication -DisplayName $prefix
|
||||
$appServicePrincipal = Get-AzADServicePrincipal -ApplicationId $appAd.ApplicationId
|
||||
|
||||
Write-Host "Azure AD application id:"$appAd.ApplicationId
|
||||
Write-Host "Azure AD app service principal:"$appServicePrincipal.Id
|
||||
|
||||
# read DFP application service principal
|
||||
try {
|
||||
$dfpAppServicePrincipal = Get-AzADServicePrincipal -DisplayName "Dynamics 365 Fraud Protection"
|
||||
}
|
||||
catch {
|
||||
"Please check if you installed Dynamics 365 Fraud Protection to your tenant (see Readme.md)"
|
||||
}
|
||||
Write-Host "Dynamics 365 Fraud Protection service principal id:"$dfpAppServicePrincipal.Id
|
||||
|
||||
# Create Azure maps group
|
||||
Write-Host "=== Create Azure Maps Group"
|
||||
if (!($mapsGroup = Get-AzADGroup -DisplayName $mapsGroupName))
|
||||
{
|
||||
$mapsGroup = New-AzADGroup `
|
||||
-DisplayName $mapsGroupName `
|
||||
-MailNickname $mapsGroupName
|
||||
# Register azure app if single tenant deployment
|
||||
if (!($twoTenants)) {
|
||||
Write-Host "=== Register azure application"
|
||||
$clientAdApp = ./deploy_ad_app.ps1 `
|
||||
-prefix $prefix `
|
||||
-envType $envType `
|
||||
-tenantId $tenantId `
|
||||
-clientSecureSecret $clientSecureSecret `
|
||||
}
|
||||
|
||||
# Register map application in Azure AD
|
||||
Write-Host "== Create Azure application for maps"
|
||||
$mapClientSecureSecret = ConvertTo-SecureString $mapClientSecret -AsPlainText -Force
|
||||
$mapApp = CreateMapApp -mapAppName $mapAppName -MapAppSecurePassword $mapClientSecureSecret
|
||||
Write-Host "Map application id:"$mapApp.mapAppId
|
||||
Write-Host "Map service principal id:"$mapApp.mapSpId
|
||||
|
||||
# Prepare Storage Account
|
||||
Write-Host "=== Provide storage account for deployment artifacts"
|
||||
|
@ -415,40 +269,24 @@ if (!(Get-AzRoleAssignment -ObjectId $spId.PrincipalId -ResourceGroupName $deplo
|
|||
}
|
||||
|
||||
|
||||
# Read tenant short name
|
||||
$tenantShortName = GetTenantShortName -TenantId $tenantId
|
||||
|
||||
|
||||
Write-Host "=== Start deployment"
|
||||
$deployment = New-AzResourceGroupDeployment `
|
||||
-ResourceGroupName $deploymentResourceGroup `
|
||||
-TemplateUri ("https://${deploymentStorageAccount}.blob.core.windows.net/deploy/main.json" + $token) `
|
||||
-TemplateParameterFile $config `
|
||||
-appClientId $appAd.ApplicationId `
|
||||
-appSpId $appServicePrincipal.Id `
|
||||
-dfpSpId $dfpAppServicePrincipal.Id `
|
||||
-mapsGroupId $mapsGroup.Id `
|
||||
-clientTenantId $clientTenantId `
|
||||
-appClientId $clientAdApp.appClientId `
|
||||
-appSpId $clientAdApp.appSpId `
|
||||
-dfpSpId $clientAdApp.dfpSpId `
|
||||
-mapAppId $mapApp.mapAppId `
|
||||
-mapSpId $mapApp.mapSpId `
|
||||
-deploymentIdentity $spId.Id `
|
||||
-deploymentStorageAccount $deploymentStorageAccount `
|
||||
-tenantShortName $tenantShortName `
|
||||
-clientTenantShortName $clientAdApp.clientTenantShortName `
|
||||
-appQueuesPackageUrl ("https://${deploymentStorageAccount}.blob.core.windows.net/deploy/queues/target-${version}.zip" + $token) `
|
||||
-appAnalyticsPackageUrl ("https://${deploymentStorageAccount}.blob.core.windows.net/deploy/analytics/target-${version}.zip" + $token) `
|
||||
-keyVaultName $keyVaultName
|
||||
|
||||
Write-Host "=== Set admin consent for Azure AD applicaton"
|
||||
./deploy_ad_app_admin_consent.ps1 -AD_APP_NAME "$prefix"
|
||||
|
||||
# Assign Azure App permissions for DFP
|
||||
# Works only on Windows due to AzureAD module
|
||||
# on Mac grant_dfp_permissions.ps1 should be executed manually (see Readme for more details)
|
||||
if (CheckOSWindows)
|
||||
{
|
||||
Write-Host "=== Assing DFP roles to application"
|
||||
foreach ($dfpRoleName in $dfpRoles[$envType]) {
|
||||
GrantDfpPermissionWin -clientAppName $prefix -dfpRoleName $dfpRoleName
|
||||
}
|
||||
}
|
||||
|
||||
Write-Host "Deployment Output"
|
||||
Write-Host $deployment.OutputsString
|
||||
|
||||
|
|
|
@ -2,77 +2,198 @@
|
|||
# Licensed under the MIT license.
|
||||
|
||||
Param(
|
||||
[string] $AD_APP_NAME,
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string] $prefix,
|
||||
|
||||
[string] $CLIENT_SECRET,
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string] $envType,
|
||||
|
||||
[string[]] $REPLY_URLS
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string] $tenantId,
|
||||
|
||||
[SecureString] $clientSecureSecret
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
. ./functions.ps1
|
||||
|
||||
# Register Azure AD Application
|
||||
Write-Host "= Register App"$AD_APP_NAME
|
||||
$CLIENT_ID = (az ad app list --display-name "${AD_APP_NAME}" --query "[0].appId")
|
||||
if (!($CLIENT_ID))
|
||||
function ConvertSecureToPlaintext
|
||||
{
|
||||
$output = ( az ad app create --display-name "${AD_APP_NAME}" `
|
||||
--oauth2-allow-implicit-flow `
|
||||
--available-to-other-tenants `
|
||||
param (
|
||||
[secureString] $secureStr
|
||||
)
|
||||
# Use different functions in powershell 5.1 and 7.x+
|
||||
if (((Get-Host).Version.Major -eq "5") -And ((Get-Host).Version.Minor -eq "1")) {
|
||||
$bstr = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($secureStr)
|
||||
$plaintextStr = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($bstr)
|
||||
} else {
|
||||
$plaintextStr = ConvertFrom-SecureString -SecureString $secureStr -AsPlainText
|
||||
}
|
||||
return $plaintextStr
|
||||
}
|
||||
|
||||
|
||||
function deployAdApp {
|
||||
Param(
|
||||
[string] $AD_APP_NAME,
|
||||
|
||||
[string] $CLIENT_SECRET,
|
||||
|
||||
[string[]] $REPLY_URLS
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
# Register Azure AD application
|
||||
Write-Host "= Register App"$AD_APP_NAME
|
||||
$CLIENT_ID = (az ad app list --display-name "${AD_APP_NAME}" --query "[0].appId")
|
||||
if (!($CLIENT_ID))
|
||||
{
|
||||
$output = ( az ad app create --display-name "${AD_APP_NAME}" `
|
||||
--oauth2-allow-implicit-flow `
|
||||
--available-to-other-tenants `
|
||||
--password "${CLIENT_SECRET}" `
|
||||
--reply-urls $REPLY_URLS `
|
||||
--app-roles @manifests/ad_app_roles_manifest.json `
|
||||
--optional-claims @manifests/ad_app_claims_manifest.json `
|
||||
--required-resource-accesses @manifests/ad_app_permissions_manifest.json )
|
||||
|
||||
if ($LastExitCode -ne 0) {
|
||||
throw "Last command failed, check logs"
|
||||
}
|
||||
|
||||
$CLIENT_ID = (az ad app list --display-name ${AD_APP_NAME} --query "[0].appId")
|
||||
$CLIENT_ID = $CLIENT_ID.Trim('"')
|
||||
|
||||
Write-Host "= Update app identifier uris"
|
||||
az ad app update --id "${CLIENT_ID}" `
|
||||
--identifier-uris "api://${CLIENT_ID}"
|
||||
|
||||
if ($LastExitCode -ne 0) {
|
||||
throw "Last command failed, check logs"
|
||||
}
|
||||
}
|
||||
else {
|
||||
Write-Host "= Azure AD App is already exist"
|
||||
$CLIENT_ID = $CLIENT_ID.Trim('"')
|
||||
}
|
||||
|
||||
Write-Host "= Update app properties"
|
||||
az ad app update --id "${CLIENT_ID}" `
|
||||
--password "${CLIENT_SECRET}" `
|
||||
--reply-urls $REPLY_URLS `
|
||||
--app-roles @manifests/ad_app_roles_manifest.json `
|
||||
--optional-claims @manifests/ad_app_claims_manifest.json `
|
||||
--required-resource-accesses @manifests/ad_app_permissions_manifest.json )
|
||||
--required-resource-accesses @manifests/ad_app_permissions_manifest.json
|
||||
|
||||
if ($LastExitCode -ne 0) {
|
||||
throw "Last command failed, check logs"
|
||||
}
|
||||
|
||||
$CLIENT_ID = (az ad app list --display-name ${AD_APP_NAME} --query "[0].appId")
|
||||
$CLIENT_ID = $CLIENT_ID.Trim('"')
|
||||
Write-Host "= Check if SP already exist"
|
||||
$APP_SP_ID = (az ad sp list --filter "displayname eq '${AD_APP_NAME}'" --query "[0].objectId" )
|
||||
if (!($APP_SP_ID))
|
||||
{
|
||||
Write-Host "= Create SP"
|
||||
$output = ( az ad sp create --id "${CLIENT_ID}" )
|
||||
|
||||
if ($LastExitCode -ne 0) {
|
||||
throw "Last command failed, check logs"
|
||||
}
|
||||
|
||||
az ad sp update --id "${CLIENT_ID}" --add tags "WindowsAzureActiveDirectoryIntegratedApp"
|
||||
|
||||
if ($LastExitCode -ne 0) {
|
||||
throw "Last command failed, check logs"
|
||||
}
|
||||
|
||||
Write-Host "= Update app identifier uris"
|
||||
az ad app update --id "${CLIENT_ID}" `
|
||||
--identifier-uris "api://${CLIENT_ID}"
|
||||
# Set admin consent
|
||||
Write-Host "= Set admin consent"
|
||||
for ($i = 0; $i -lt 5; $i++) {
|
||||
Write-Host "Retry"$i
|
||||
Start-Sleep -s 10
|
||||
az ad app permission admin-consent --id "${CLIENT_ID}"
|
||||
if ($LastExitCode -eq 0) { break }
|
||||
}
|
||||
|
||||
if ($LastExitCode -ne 0) {
|
||||
throw "Last command failed, check logs"
|
||||
if ($LastExitCode -ne 0) {
|
||||
throw "Last command failed, check logs"
|
||||
}
|
||||
}
|
||||
else {
|
||||
Write-Host "= SP is already exist"
|
||||
}
|
||||
}
|
||||
else {
|
||||
Write-Host "= Azure AD App is already exist"
|
||||
$CLIENT_ID = $CLIENT_ID.Trim('"')
|
||||
|
||||
################################################################# MAIN PROGRAM
|
||||
|
||||
Write-Host "== Verify Azure context..."
|
||||
$currentAzureContext = Get-AzContext
|
||||
if (!($currentAzureContext.Tenant.Id -eq $tenantId)) {
|
||||
Write-Host "= Login to Azure"
|
||||
Write-Host "Provide credentials for PS in tenant ${tenantId}"
|
||||
Login-AzAccount
|
||||
}
|
||||
|
||||
Write-Host "= Update app properties"
|
||||
az ad app update --id "${CLIENT_ID}" `
|
||||
--password "${CLIENT_SECRET}" `
|
||||
--reply-urls $REPLY_URLS `
|
||||
--required-resource-accesses @manifests/ad_app_permissions_manifest.json
|
||||
|
||||
if ($LastExitCode -ne 0) {
|
||||
throw "Last command failed, check logs"
|
||||
$az_tenant = (az account show --query "tenantId").Trim('"')
|
||||
if (!($az_tenant -eq $tenantId)) {
|
||||
Write-Host "= Provide credentials for Az Cli in tenant ${tenantId} and subscription ${subscriptionId}"
|
||||
az login
|
||||
}
|
||||
|
||||
Write-Host "= Check if SP already exist"
|
||||
$APP_SP_ID = (az ad sp list --filter "displayname eq '${AD_APP_NAME}'" --query "[0].objectId" )
|
||||
if (!($APP_SP_ID))
|
||||
# Init AzureAD in windows environment
|
||||
if (CheckOSWindows)
|
||||
{
|
||||
Write-Host "= Create SP"
|
||||
$output = ( az ad sp create --id "${CLIENT_ID}" )
|
||||
|
||||
if ($LastExitCode -ne 0) {
|
||||
throw "Last command failed, check logs"
|
||||
}
|
||||
|
||||
az ad sp update --id "${CLIENT_ID}" --add tags "WindowsAzureActiveDirectoryIntegratedApp"
|
||||
|
||||
if ($LastExitCode -ne 0) {
|
||||
throw "Last command failed, check logs"
|
||||
}
|
||||
}
|
||||
else {
|
||||
Write-Host "= SP is already exist"
|
||||
# Will skip re-prompting credentials for AzureAD module
|
||||
Connect-AzureAD -TenantId $currentAzureContext.Tenant.Id -AccountId $currentAzureContext.Account.Id
|
||||
}
|
||||
|
||||
# Read Azure app client secret
|
||||
if (!($clientSecureSecret)) {
|
||||
$clientSecureSecret = Read-Host "Enter the Azure application secret" -AsSecureString
|
||||
}
|
||||
|
||||
# Register application in Azure AD
|
||||
Write-Host "== Create Azure App registration"
|
||||
$replyUrls = GenReplyUrls
|
||||
$clientSecret = ConvertSecureToPlaintext -SecureStr $clientSecureSecret
|
||||
deployAdApp -AD_APP_NAME "$prefix" -CLIENT_SECRET "$clientSecret" -REPLY_URLS $replyUrls
|
||||
|
||||
# read application id and service principal id
|
||||
$appAd = Get-AzADApplication -DisplayName $prefix
|
||||
$appServicePrincipal = Get-AzADServicePrincipal -ApplicationId $appAd.ApplicationId
|
||||
|
||||
# read DFP application service principal
|
||||
try {
|
||||
$dfpAppServicePrincipal = Get-AzADServicePrincipal -DisplayName "Dynamics 365 Fraud Protection"
|
||||
}
|
||||
catch {
|
||||
"Please check if you installed Dynamics 365 Fraud Protection to your tenant (see Readme.md)"
|
||||
}
|
||||
|
||||
# Assign Azure App permissions for DFP
|
||||
# Works only on Windows due to AzureAD module
|
||||
# on Mac grant_dfp_permissions.ps1 shuld be execured (see Readme for more details)
|
||||
if (CheckOSWindows)
|
||||
{
|
||||
Write-Host "== Assing DFP roles to application"
|
||||
foreach ($dfpRoleName in $dfpRoles[$envType]) {
|
||||
GrantDfpPermissionWin -clientAppName $prefix -dfpRoleName $dfpRoleName
|
||||
}
|
||||
}
|
||||
|
||||
# Read tenant short name
|
||||
$tenantShortName = GetTenantShortName -TenantId $tenantId
|
||||
|
||||
# Outputs
|
||||
Write-Host "== Collect shared parameters"
|
||||
Write-Host "Azure AD application name:"$prefix
|
||||
Write-Host "Azure AD application client id:"$appAd.ApplicationId
|
||||
Write-Host "Azure AD app service principal:"$appServicePrincipal.Id
|
||||
Write-Host "Dynamics 365 Fraud Protection service principal id:"$dfpAppServicePrincipal.Id
|
||||
Write-Host "Tenant id:"$tenantId
|
||||
Write-Host "Tenant short name:"$tenantShortName
|
||||
|
||||
return @{
|
||||
"appClientId" = $appAd.ApplicationId
|
||||
"appSpId" = $appServicePrincipal.Id
|
||||
"dfpSpId" = $dfpAppServicePrincipal.Id
|
||||
"clientTenantShortName" = $tenantShortName
|
||||
}
|
||||
|
|
|
@ -0,0 +1,217 @@
|
|||
# Copyright (c) Microsoft Corporation.
|
||||
# Licensed under the MIT license.
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
$frontendContainer = "web"
|
||||
|
||||
# Dict with java microservice name and path to base directory
|
||||
$applications = @{
|
||||
"queues" = "../backend/queues"
|
||||
"analytics" = "../backend/analytics"
|
||||
}
|
||||
$version = Get-Date -Format FileDateTimeUniversal
|
||||
# Path to fronend build directory
|
||||
$frontendBuildPath = "../frontend/scripts"
|
||||
|
||||
# DFP roles definition
|
||||
$dfpRoles = @{}
|
||||
$dfpRoles["Dev"] = @(
|
||||
"Sandbox_Risk_API",
|
||||
"Sandbox_ManualReview_API"
|
||||
)
|
||||
$dfpRoles["Prod"] = @(
|
||||
"Risk_API",
|
||||
"ManualReview_API"
|
||||
)
|
||||
|
||||
function BuildFrontend {
|
||||
Set-Location "${baseDir}/$frontendBuildPath"
|
||||
Copy-Item -Path "config.template.json" -Destination "../public/config.json"
|
||||
yarn install
|
||||
yarn build
|
||||
if ($LastExitCode -ne 0) {
|
||||
throw "Build failed, check logs"
|
||||
}
|
||||
New-Item -Path "${baseDir}/build" -Name "frontend" -ItemType "directory" -ErrorAction Ignore
|
||||
Copy-Item -Path "../build/*" -Destination "${baseDir}/build/frontend" -Recurse
|
||||
Set-Location $baseDir
|
||||
}
|
||||
|
||||
function BuildBackend {
|
||||
foreach ($app in $applications.GetEnumerator()) {
|
||||
Write-Host "=== Building $($app.Name) app..."
|
||||
Set-Location "${baseDir}/$($app.Value)"
|
||||
if (CheckOSWindows) {
|
||||
./gradlew.bat clean packageDist --console=plain
|
||||
} else {
|
||||
./gradlew clean packageDist --console=plain
|
||||
}
|
||||
if ($LastExitCode -ne 0) {
|
||||
throw "Build failed, check logs"
|
||||
}
|
||||
New-Item -Path "${baseDir}/build" -Name "$($app.Name)" -ItemType "directory" -ErrorAction Ignore
|
||||
Copy-Item -Path "build/dist/target.zip" -Destination "${baseDir}/build/$($app.Name)/target.zip" -Recurse
|
||||
}
|
||||
}
|
||||
|
||||
function GetRandomPassword {
|
||||
$password = -join ('abcdefghkmnrstuvwxyzABCDEFGHKLMNPRSTUVWXYZ0123456789'.ToCharArray() | Get-Random -Count 30)
|
||||
$password += -join ('!~.'.ToCharArray() | Get-Random -Count 2)
|
||||
return $password
|
||||
}
|
||||
|
||||
function ProvideCleanContainer {
|
||||
param (
|
||||
$storageContainer,
|
||||
$storageContext
|
||||
)
|
||||
|
||||
$sc = Get-AzStorageContainer -Name $storageContainer -Context $storageContext -ErrorAction Ignore
|
||||
if (!$sc) {
|
||||
Write-Host "= Create container $storageContainer"
|
||||
New-AzStorageContainer `
|
||||
-Name $storageContainer `
|
||||
-Context $storageContext
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Host "= Clean container $storageContainer"
|
||||
Get-AzStorageBlob -Container $storageContainer -Context $storageContext `
|
||||
| Where-Object { $_.Name -notMatch '^.*target.*zip' } `
|
||||
| Remove-AzStorageBlob
|
||||
}
|
||||
}
|
||||
|
||||
function GrantDfpPermissionWin {
|
||||
param (
|
||||
[string] $clientAppName,
|
||||
[string] $dfpRoleName
|
||||
)
|
||||
|
||||
Write-Host "= Assign role $dfpRoleName to app" $clientAppName
|
||||
|
||||
$app_name = "Dynamics 365 Fraud Protection"
|
||||
$sp = Get-AzureADServicePrincipal -Filter "displayName eq '$app_name'"
|
||||
|
||||
$c_appRole = $sp.AppRoles | Where-Object { $_.DisplayName -eq $dfpRoleName }
|
||||
|
||||
for ($i = 0; $i -lt 5; $i++) {
|
||||
Start-Sleep -s 5
|
||||
$c_sp = Get-AzureADServicePrincipal -Filter "displayName eq '$clientAppName'"
|
||||
if ($c_sp) { break }
|
||||
}
|
||||
|
||||
$roleAssigned = Get-AzureADServiceAppRoleAssignedTo -ObjectId $c_sp.ObjectId `
|
||||
| Where-Object { $_.Id -eq $c_appRole.Id }
|
||||
|
||||
if(!($roleAssigned))
|
||||
{
|
||||
Write-host "Assigning DFP role ..."
|
||||
New-AzureADServiceAppRoleAssignment `
|
||||
-ObjectId $c_sp.ObjectId `
|
||||
-PrincipalId $c_sp.ObjectId `
|
||||
-ResourceId $sp.ObjectId `
|
||||
-Id $c_appRole.Id
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-host "DFP role is already assigned"
|
||||
}
|
||||
}
|
||||
|
||||
function CheckOSWindows
|
||||
{
|
||||
$envOS = Get-ChildItem -Path Env:OS -ErrorAction Ignore
|
||||
return ( $envOS -And $envOS.value.Contains('Windows') )
|
||||
}
|
||||
|
||||
function PutSecret {
|
||||
param (
|
||||
[string] $vaultName,
|
||||
[string] $secretName,
|
||||
[string] $secretValue,
|
||||
[SecureString] $secretSecureValue
|
||||
)
|
||||
|
||||
Write-Host "= Put secret $secretName to Key Vault $vaultName"
|
||||
if ($secretValue) {
|
||||
$secretSecureValue = ConvertTo-SecureString $secretValue -AsPlainText -Force
|
||||
}
|
||||
Set-AzKeyVaultSecret `
|
||||
-VaultName $vaultName `
|
||||
-Name $secretName `
|
||||
-SecretValue $secretSecureValue
|
||||
}
|
||||
|
||||
function GenReplyUrls {
|
||||
# Define Azure app reply urls
|
||||
$replyUrls = @(
|
||||
"https://$prefix.azurefd.net/login",
|
||||
"https://$prefix-queues.azurewebsites.net/oauth2-redirect.html",
|
||||
"https://$prefix-queues-secondary.azurewebsites.net/oauth2-redirect.html",
|
||||
"https://$prefix-analytics.azurewebsites.net/oauth2-redirect.html",
|
||||
"https://$prefix-analytics-secondary.azurewebsites.net/oauth2-redirect.html"
|
||||
)
|
||||
|
||||
$localSwaggerUri = "http://localhost:8080/oauth2-redirect.html"
|
||||
$localFrontUri = "http://localhost:3000/login"
|
||||
|
||||
if ($envType -eq "Dev") {
|
||||
$replyUrls += @($localSwaggerUri, $localFrontUri)
|
||||
}
|
||||
if ($customDomain -And ($customDomain -ne "UNDEFINED")) {
|
||||
$replyUrls += "https://${customDomain}/login"
|
||||
}
|
||||
|
||||
return $replyUrls
|
||||
}
|
||||
|
||||
function GetTenantShortName {
|
||||
param(
|
||||
[string] $TenantId
|
||||
)
|
||||
|
||||
foreach ($domain in (Get-AzTenant -TenantId $tenantId).domains) {
|
||||
if ($domain -match '(.*)\.onmicrosoft\.com') {
|
||||
return $Matches.1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function CreateMapApp {
|
||||
param (
|
||||
[string] $mapAppName,
|
||||
[secureString] $MapAppSecurePassword
|
||||
)
|
||||
|
||||
Write-Host "= Create application"
|
||||
if (!($mapApp = Get-AzADApplication -DisplayName $mapAppName)) {
|
||||
$mapApp = New-AzADApplication `
|
||||
-DisplayName $mapAppName `
|
||||
-Password $mapAppSecurePassword `
|
||||
-IdentifierUris "http://${mapAppName}"
|
||||
|
||||
Write-Host "= Update application identifier uri"
|
||||
Update-AzADApplication `
|
||||
-ApplicationId $mapApp.ApplicationId `
|
||||
-IdentifierUri "api://$($mapApp.ApplicationId)"
|
||||
} else {
|
||||
Write-Host "Application is already exist"
|
||||
}
|
||||
|
||||
Write-Host "= Create service principal"
|
||||
if (!($mapSp = Get-AzADServicePrincipal -DisplayName $mapAppName)) {
|
||||
$mapSp = New-AzADServicePrincipal `
|
||||
-DisplayName $mapAppName `
|
||||
-ApplicationId $mapApp.ApplicationId `
|
||||
-SkipAssignment
|
||||
} else {
|
||||
Write-Host "Service principal is already exist"
|
||||
}
|
||||
|
||||
return @{
|
||||
"mapAppId" = $mapApp.ApplicationId
|
||||
"mapSpId" = $mapSp.Id
|
||||
}
|
||||
}
|
|
@ -31,6 +31,9 @@
|
|||
"tenantId": {
|
||||
"type": "string"
|
||||
},
|
||||
"clientTenantId": {
|
||||
"type": "string"
|
||||
},
|
||||
"keyVaultName": {
|
||||
"type": "string"
|
||||
},
|
||||
|
@ -106,7 +109,11 @@
|
|||
"type": "string",
|
||||
"defaultValue": ""
|
||||
},
|
||||
"mapsGroupId": {
|
||||
"mapAppId": {
|
||||
"type": "string",
|
||||
"defaultValue": ""
|
||||
},
|
||||
"mapSpId": {
|
||||
"type": "string",
|
||||
"defaultValue": ""
|
||||
},
|
||||
|
@ -126,7 +133,7 @@
|
|||
"dfpSpId": {
|
||||
"type": "string"
|
||||
},
|
||||
"tenantShortName": {
|
||||
"clientTenantShortName": {
|
||||
"type": "string"
|
||||
},
|
||||
"alertReceivers": {
|
||||
|
@ -343,7 +350,7 @@
|
|||
"value": "[parameters('mapAccountSku')]"
|
||||
},
|
||||
"principalId": {
|
||||
"value": "[parameters('mapsGroupId')]"
|
||||
"value": "[parameters('mapSpId')]"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -607,6 +614,9 @@
|
|||
"tenantId": {
|
||||
"value": "[parameters('tenantId')]"
|
||||
},
|
||||
"clientTenantId": {
|
||||
"value": "[parameters('clientTenantId')]"
|
||||
},
|
||||
"appJavaOpts": {
|
||||
"value": "[variables('appJavaOpts')]"
|
||||
},
|
||||
|
@ -622,8 +632,8 @@
|
|||
"dfpSpId": {
|
||||
"value": "[parameters('dfpSpId')]"
|
||||
},
|
||||
"tenantShortName": {
|
||||
"value": "[parameters('tenantShortName')]"
|
||||
"clientTenantShortName": {
|
||||
"value": "[parameters('clientTenantShortName')]"
|
||||
},
|
||||
"keyVaultEndpoint": {
|
||||
"value": "[variables('keyVaultEndpoint')]"
|
||||
|
@ -636,6 +646,9 @@
|
|||
},
|
||||
"logWorkspaceName": {
|
||||
"value": "[variables('LogWorkspaceName')]"
|
||||
},
|
||||
"mapAppId": {
|
||||
"value": "[parameters('mapAppId')]"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -703,6 +716,9 @@
|
|||
"tenantId": {
|
||||
"value": "[parameters('tenantId')]"
|
||||
},
|
||||
"clientTenantId": {
|
||||
"value": "[parameters('clientTenantId')]"
|
||||
},
|
||||
"appJavaOpts": {
|
||||
"value": "[variables('appJavaOptsSecondary')]"
|
||||
},
|
||||
|
@ -718,8 +734,8 @@
|
|||
"dfpSpId": {
|
||||
"value": "[parameters('dfpSpId')]"
|
||||
},
|
||||
"tenantShortName": {
|
||||
"value": "[parameters('tenantShortName')]"
|
||||
"clientTenantShortName": {
|
||||
"value": "[parameters('clientTenantShortName')]"
|
||||
},
|
||||
"keyVaultEndpoint": {
|
||||
"value": "[variables('keyVaultEndpoint')]"
|
||||
|
@ -732,6 +748,9 @@
|
|||
},
|
||||
"logWorkspaceName": {
|
||||
"value": "[variables('LogWorkspaceSecondaryName')]"
|
||||
},
|
||||
"mapAppId": {
|
||||
"value": "[parameters('mapAppId')]"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -799,6 +818,9 @@
|
|||
"tenantId": {
|
||||
"value": "[parameters('tenantId')]"
|
||||
},
|
||||
"clientTenantId": {
|
||||
"value": "[parameters('clientTenantId')]"
|
||||
},
|
||||
"appJavaOpts": {
|
||||
"value": "[variables('appJavaOpts')]"
|
||||
},
|
||||
|
@ -814,8 +836,8 @@
|
|||
"dfpSpId": {
|
||||
"value": "[parameters('dfpSpId')]"
|
||||
},
|
||||
"tenantShortName": {
|
||||
"value": "[parameters('tenantShortName')]"
|
||||
"clientTenantShortName": {
|
||||
"value": "[parameters('clientTenantShortName')]"
|
||||
},
|
||||
"keyVaultEndpoint": {
|
||||
"value": "[variables('keyVaultEndpoint')]"
|
||||
|
@ -828,6 +850,9 @@
|
|||
},
|
||||
"logWorkspaceName": {
|
||||
"value": "[variables('LogWorkspaceName')]"
|
||||
},
|
||||
"mapAppId": {
|
||||
"value": "[parameters('mapAppId')]"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -895,6 +920,9 @@
|
|||
"tenantId": {
|
||||
"value": "[parameters('tenantId')]"
|
||||
},
|
||||
"clientTenantId": {
|
||||
"value": "[parameters('clientTenantId')]"
|
||||
},
|
||||
"appJavaOpts": {
|
||||
"value": "[variables('appJavaOptsSecondary')]"
|
||||
},
|
||||
|
@ -910,8 +938,8 @@
|
|||
"dfpSpId": {
|
||||
"value": "[parameters('dfpSpId')]"
|
||||
},
|
||||
"tenantShortName": {
|
||||
"value": "[parameters('tenantShortName')]"
|
||||
"clientTenantShortName": {
|
||||
"value": "[parameters('clientTenantShortName')]"
|
||||
},
|
||||
"keyVaultEndpoint": {
|
||||
"value": "[variables('keyVaultEndpoint')]"
|
||||
|
@ -924,6 +952,9 @@
|
|||
},
|
||||
"logWorkspaceName": {
|
||||
"value": "[variables('LogWorkspaceSecondaryName')]"
|
||||
},
|
||||
"mapAppId": {
|
||||
"value": "[parameters('mapAppId')]"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1201,7 +1232,7 @@
|
|||
"value": "[parameters('appClientId')]"
|
||||
},
|
||||
"tenantId":{
|
||||
"value": "[parameters('tenantId')]"
|
||||
"value": "[parameters('clientTenantId')]"
|
||||
},
|
||||
"mapClientId":{
|
||||
"value": "[reference('mapAccountTemplate').outputs.mapsAccountClientId.value]"
|
||||
|
|
|
@ -8,9 +8,24 @@
|
|||
"subscriptionId": {
|
||||
"value": "00000000-0000-0000-0000-000000000000"
|
||||
},
|
||||
"clientTenantId": {
|
||||
"value": "00000000-0000-0000-0000-000000000000"
|
||||
},
|
||||
"tenantId": {
|
||||
"value": "00000000-0000-0000-0000-000000000000"
|
||||
},
|
||||
"clientTenantShortName": {
|
||||
"value": "gddfp"
|
||||
},
|
||||
"appClientId": {
|
||||
"value": "00000000-0000-0000-0000-000000000000"
|
||||
},
|
||||
"appSpId": {
|
||||
"value": "00000000-0000-0000-0000-000000000000"
|
||||
},
|
||||
"dfpSpId": {
|
||||
"value": "00000000-0000-0000-0000-000000000000"
|
||||
},
|
||||
"envType": {
|
||||
"value": "Dev"
|
||||
},
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
},
|
||||
"guid": {
|
||||
"type": "string",
|
||||
"defaultValue": "[guid(resourceGroup().id)]",
|
||||
"defaultValue": "[guid(parameters('principalId'))]",
|
||||
"metadata": {
|
||||
"description": "Input string for new GUID associated with assigning built in role types"
|
||||
}
|
||||
|
@ -49,7 +49,7 @@
|
|||
"properties": {
|
||||
"roleDefinitionId": "[variables('Azure Maps Data Reader')]",
|
||||
"principalId": "[parameters('principalId')]",
|
||||
"principalType": "Group"
|
||||
"principalType": "ServicePrincipal"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
|
|
@ -548,6 +548,28 @@
|
|||
"options": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers",
|
||||
"apiVersion": "2020-04-01",
|
||||
"name": "[concat(parameters('cosmosDbAccountName'), '/QueuesDB/EmailDomains')]",
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases', parameters('cosmosDbAccountName'), 'QueuesDB')]",
|
||||
"[resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('cosmosDbAccountName'))]"
|
||||
],
|
||||
"properties": {
|
||||
"resource": {
|
||||
"id": "EmailDomains",
|
||||
"partitionKey": {
|
||||
"paths": [
|
||||
"/id"
|
||||
],
|
||||
"kind": "Hash"
|
||||
},
|
||||
"defaultTtl": -1
|
||||
},
|
||||
"options": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers",
|
||||
"apiVersion": "2020-04-01",
|
||||
|
|
|
@ -46,39 +46,54 @@
|
|||
"dfphubPolicyName": "dfpSend"
|
||||
},
|
||||
"resources": [
|
||||
{
|
||||
"type": "Microsoft.EventHub/namespaces",
|
||||
"apiVersion": "2018-01-01-preview",
|
||||
"name": "[parameters('ehubName')]",
|
||||
"location": "[parameters('location')]",
|
||||
"sku": {
|
||||
"name": "[parameters('eventHubSku')]",
|
||||
"tier": "[parameters('eventHubSku')]",
|
||||
"capacity": "[parameters('ehubCapacity')]"
|
||||
},
|
||||
"properties": {
|
||||
"zoneRedundant": false,
|
||||
"isAutoInflateEnabled": true,
|
||||
"maximumThroughputUnits": "[parameters('ehubMaximumThroughputUnits')]",
|
||||
"kafkaEnabled": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Microsoft.EventHub/namespaces/AuthorizationRules",
|
||||
"apiVersion": "2017-04-01",
|
||||
"name": "[concat(parameters('ehubName'), '/RootManageSharedAccessKey')]",
|
||||
"location": "[parameters('location')]",
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.EventHub/namespaces', parameters('ehubName'))]"
|
||||
],
|
||||
"properties": {
|
||||
"rights": [
|
||||
"Listen",
|
||||
"Manage",
|
||||
"Send"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Microsoft.EventHub/namespaces",
|
||||
"apiVersion": "2018-01-01-preview",
|
||||
"name": "[parameters('ehubName')]",
|
||||
"location": "[parameters('location')]",
|
||||
"sku": {
|
||||
"name": "[parameters('eventHubSku')]",
|
||||
"tier": "[parameters('eventHubSku')]",
|
||||
"capacity": "[parameters('ehubCapacity')]"
|
||||
},
|
||||
"properties": {
|
||||
"zoneRedundant": false,
|
||||
"isAutoInflateEnabled": true,
|
||||
"maximumThroughputUnits": "[parameters('ehubMaximumThroughputUnits')]",
|
||||
"kafkaEnabled": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Microsoft.EventHub/namespaces/AuthorizationRules",
|
||||
"apiVersion": "2017-04-01",
|
||||
"name": "[concat(parameters('ehubName'), '/RootManageSharedAccessKey')]",
|
||||
"location": "[parameters('location')]",
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.EventHub/namespaces', parameters('ehubName'))]"
|
||||
],
|
||||
"properties": {
|
||||
"rights": [
|
||||
"Listen",
|
||||
"Manage",
|
||||
"Send"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Microsoft.EventHub/namespaces/networkRuleSets",
|
||||
"apiVersion": "2018-01-01-preview",
|
||||
"name": "[concat(parameters('ehubName'), '/default')]",
|
||||
"location": "[parameters('location')]",
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.EventHub/namespaces', parameters('ehubName'))]",
|
||||
"[resourceId('Microsoft.EventHub/namespaces/AuthorizationRules',parameters('ehubName'),'RootManageSharedAccessKey')]"
|
||||
],
|
||||
"properties": {
|
||||
"defaultAction": "Allow",
|
||||
"virtualNetworkRules": [],
|
||||
"ipRules": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Microsoft.EventHub/namespaces/eventhubs",
|
||||
"apiVersion": "2017-04-01",
|
||||
|
@ -190,20 +205,6 @@
|
|||
"partitionCount": "[parameters('ehubNumPartitions')]",
|
||||
"status": "Active"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Microsoft.EventHub/namespaces/networkRuleSets",
|
||||
"apiVersion": "2018-01-01-preview",
|
||||
"name": "[concat(parameters('ehubName'), '/default')]",
|
||||
"location": "[parameters('location')]",
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.EventHub/namespaces', parameters('ehubName'))]"
|
||||
],
|
||||
"properties": {
|
||||
"defaultAction": "Allow",
|
||||
"virtualNetworkRules": [],
|
||||
"ipRules": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Microsoft.EventHub/namespaces/eventhubs/authorizationRules",
|
||||
|
|
|
@ -75,6 +75,9 @@
|
|||
"tenantId": {
|
||||
"type": "string"
|
||||
},
|
||||
"clientTenantId": {
|
||||
"type": "string"
|
||||
},
|
||||
"appJavaOpts": {
|
||||
"type": "string"
|
||||
},
|
||||
|
@ -99,11 +102,14 @@
|
|||
"appInsightName": {
|
||||
"type": "String"
|
||||
},
|
||||
"tenantShortName": {
|
||||
"clientTenantShortName": {
|
||||
"type": "String"
|
||||
},
|
||||
"logWorkspaceName": {
|
||||
"type": "string"
|
||||
},
|
||||
"mapAppId": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"variables": {
|
||||
|
@ -174,10 +180,18 @@
|
|||
"name": "APP_SP_ID",
|
||||
"value": "[parameters('appSpId')]"
|
||||
},
|
||||
{
|
||||
"name": "MAP_CLIENT_ID",
|
||||
"value": "[parameters('mapAppId')]"
|
||||
},
|
||||
{
|
||||
"name": "TENANT_ID",
|
||||
"value": "[parameters('tenantId')]"
|
||||
},
|
||||
{
|
||||
"name": "CLIENT_TENANT_ID",
|
||||
"value": "[parameters('clientTenantId')]"
|
||||
},
|
||||
{
|
||||
"name": "MAIL_USERNAME",
|
||||
"value": "[parameters('mailUsername')]"
|
||||
|
@ -195,8 +209,8 @@
|
|||
"value": "[parameters('dfpSpId')]"
|
||||
},
|
||||
{
|
||||
"name": "TENANT_SHORT_NAME",
|
||||
"value": "[parameters('tenantShortName')]"
|
||||
"name": "CLIENT_TENANT_SHORT_NAME",
|
||||
"value": "[parameters('clientTenantShortName')]"
|
||||
},
|
||||
{
|
||||
"name": "KEYVAULT_ENDPOINT",
|
||||
|
|
|
@ -55,17 +55,25 @@ unoptimized code to avoid unexpected costs in Azure resources.
|
|||
### Configure integration
|
||||
|
||||
To get the whole environment installed, please, refer to [deployment](../arm/README.md).
|
||||
To get environment variables that are used by application to connect to cloud environment, run [script](./getEnv.sh)
|
||||
To get environment variables that are used by application to connect to cloud environment, run [script](./getEnv.sh)
|
||||
(works only for single-tenant deployments)
|
||||
with specified environment name:
|
||||
```shell script
|
||||
/getEnv.sh "<name_that_is_prefix_of_deployment>"
|
||||
```
|
||||
__Warning!__ You need to be unlogined in "Az Cli" or be logined with appropriate account. In first case the script will
|
||||
route you to login page.
|
||||
__Warning!__ In order to get all variables you should have enough [permissions](#prerequisites).
|
||||
>__Warning!__ You need to be unlogined in "Az Cli" or be logined with appropriate account. In first case the script will
|
||||
route you to login page.
|
||||
|
||||
>__Warning!__ In order to get all variables you should have enough [permissions](#prerequisites) and you should
|
||||
be authorized to get/list secrets in the KeyVault of the current installation.
|
||||
|
||||
>__Warning!__ For some tenants definition of SHORT_TENANT_NAME doesn't work properly. Please, define it manually as substring
|
||||
of your Tenant's Primary domain before `.onmicrosoft.com`.
|
||||
|
||||
The script output under the `-----[ Result ]-----` row will contain the set of variables that you need to have
|
||||
established in your environment before local launch or comprehensive build.
|
||||
established in your environment before local launch or comprehensive build. Also, please, be aware that application
|
||||
which mentioned in the `CLIENT_ID` variable should have permissions to get/list secrets in the KeyVault of
|
||||
the current installation.
|
||||
|
||||
__Warning!__ Values in the script output are unescaped. Be careful if there are special symbols.
|
||||
|
||||
|
|
|
@ -114,8 +114,8 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"500" : {
|
||||
"description" : "Internal Server Error",
|
||||
"400" : {
|
||||
"description" : "Bad Request",
|
||||
"content" : {
|
||||
"application/json" : {
|
||||
"schema" : {
|
||||
|
@ -128,8 +128,8 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"400" : {
|
||||
"description" : "Bad Request",
|
||||
"500" : {
|
||||
"description" : "Internal Server Error",
|
||||
"content" : {
|
||||
"application/json" : {
|
||||
"schema" : {
|
||||
|
@ -251,8 +251,8 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"500" : {
|
||||
"description" : "Internal Server Error",
|
||||
"400" : {
|
||||
"description" : "Bad Request",
|
||||
"content" : {
|
||||
"application/json" : {
|
||||
"schema" : {
|
||||
|
@ -265,8 +265,8 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"400" : {
|
||||
"description" : "Bad Request",
|
||||
"500" : {
|
||||
"description" : "Internal Server Error",
|
||||
"content" : {
|
||||
"application/json" : {
|
||||
"schema" : {
|
||||
|
@ -378,8 +378,8 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"500" : {
|
||||
"description" : "Internal Server Error",
|
||||
"400" : {
|
||||
"description" : "Bad Request",
|
||||
"content" : {
|
||||
"application/json" : {
|
||||
"schema" : {
|
||||
|
@ -392,8 +392,8 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"400" : {
|
||||
"description" : "Bad Request",
|
||||
"500" : {
|
||||
"description" : "Internal Server Error",
|
||||
"content" : {
|
||||
"application/json" : {
|
||||
"schema" : {
|
||||
|
@ -509,8 +509,8 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"500" : {
|
||||
"description" : "Internal Server Error",
|
||||
"400" : {
|
||||
"description" : "Bad Request",
|
||||
"content" : {
|
||||
"application/json" : {
|
||||
"schema" : {
|
||||
|
@ -523,8 +523,8 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"400" : {
|
||||
"description" : "Bad Request",
|
||||
"500" : {
|
||||
"description" : "Internal Server Error",
|
||||
"content" : {
|
||||
"application/json" : {
|
||||
"schema" : {
|
||||
|
@ -630,8 +630,8 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"500" : {
|
||||
"description" : "Internal Server Error",
|
||||
"400" : {
|
||||
"description" : "Bad Request",
|
||||
"content" : {
|
||||
"application/json" : {
|
||||
"schema" : {
|
||||
|
@ -644,8 +644,8 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"400" : {
|
||||
"description" : "Bad Request",
|
||||
"500" : {
|
||||
"description" : "Internal Server Error",
|
||||
"content" : {
|
||||
"application/json" : {
|
||||
"schema" : {
|
||||
|
@ -755,8 +755,8 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"500" : {
|
||||
"description" : "Internal Server Error",
|
||||
"400" : {
|
||||
"description" : "Bad Request",
|
||||
"content" : {
|
||||
"application/json" : {
|
||||
"schema" : {
|
||||
|
@ -769,8 +769,8 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"400" : {
|
||||
"description" : "Bad Request",
|
||||
"500" : {
|
||||
"description" : "Internal Server Error",
|
||||
"content" : {
|
||||
"application/json" : {
|
||||
"schema" : {
|
||||
|
@ -892,8 +892,8 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"500" : {
|
||||
"description" : "Internal Server Error",
|
||||
"400" : {
|
||||
"description" : "Bad Request",
|
||||
"content" : {
|
||||
"application/json" : {
|
||||
"schema" : {
|
||||
|
@ -906,8 +906,8 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"400" : {
|
||||
"description" : "Bad Request",
|
||||
"500" : {
|
||||
"description" : "Internal Server Error",
|
||||
"content" : {
|
||||
"application/json" : {
|
||||
"schema" : {
|
||||
|
@ -1024,8 +1024,8 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"500" : {
|
||||
"description" : "Internal Server Error",
|
||||
"400" : {
|
||||
"description" : "Bad Request",
|
||||
"content" : {
|
||||
"application/json" : {
|
||||
"schema" : {
|
||||
|
@ -1038,8 +1038,8 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"400" : {
|
||||
"description" : "Bad Request",
|
||||
"500" : {
|
||||
"description" : "Internal Server Error",
|
||||
"content" : {
|
||||
"application/json" : {
|
||||
"schema" : {
|
||||
|
@ -1158,8 +1158,8 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"500" : {
|
||||
"description" : "Internal Server Error",
|
||||
"400" : {
|
||||
"description" : "Bad Request",
|
||||
"content" : {
|
||||
"application/json" : {
|
||||
"schema" : {
|
||||
|
@ -1172,8 +1172,8 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"400" : {
|
||||
"description" : "Bad Request",
|
||||
"500" : {
|
||||
"description" : "Internal Server Error",
|
||||
"content" : {
|
||||
"application/json" : {
|
||||
"schema" : {
|
||||
|
@ -1290,8 +1290,8 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"500" : {
|
||||
"description" : "Internal Server Error",
|
||||
"400" : {
|
||||
"description" : "Bad Request",
|
||||
"content" : {
|
||||
"application/json" : {
|
||||
"schema" : {
|
||||
|
@ -1304,8 +1304,8 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"400" : {
|
||||
"description" : "Bad Request",
|
||||
"500" : {
|
||||
"description" : "Internal Server Error",
|
||||
"content" : {
|
||||
"application/json" : {
|
||||
"schema" : {
|
||||
|
@ -1456,8 +1456,8 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"500" : {
|
||||
"description" : "Internal Server Error",
|
||||
"400" : {
|
||||
"description" : "Bad Request",
|
||||
"content" : {
|
||||
"application/json" : {
|
||||
"schema" : {
|
||||
|
@ -1470,8 +1470,8 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"400" : {
|
||||
"description" : "Bad Request",
|
||||
"500" : {
|
||||
"description" : "Internal Server Error",
|
||||
"content" : {
|
||||
"application/json" : {
|
||||
"schema" : {
|
||||
|
@ -1632,8 +1632,8 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"500" : {
|
||||
"description" : "Internal Server Error",
|
||||
"400" : {
|
||||
"description" : "Bad Request",
|
||||
"content" : {
|
||||
"application/json" : {
|
||||
"schema" : {
|
||||
|
@ -1646,8 +1646,8 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"400" : {
|
||||
"description" : "Bad Request",
|
||||
"500" : {
|
||||
"description" : "Internal Server Error",
|
||||
"content" : {
|
||||
"application/json" : {
|
||||
"schema" : {
|
||||
|
@ -1812,8 +1812,8 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"500" : {
|
||||
"description" : "Internal Server Error",
|
||||
"400" : {
|
||||
"description" : "Bad Request",
|
||||
"content" : {
|
||||
"application/json" : {
|
||||
"schema" : {
|
||||
|
@ -1826,8 +1826,8 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"400" : {
|
||||
"description" : "Bad Request",
|
||||
"500" : {
|
||||
"description" : "Internal Server Error",
|
||||
"content" : {
|
||||
"application/json" : {
|
||||
"schema" : {
|
||||
|
@ -1982,8 +1982,8 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"500" : {
|
||||
"description" : "Internal Server Error",
|
||||
"400" : {
|
||||
"description" : "Bad Request",
|
||||
"content" : {
|
||||
"application/json" : {
|
||||
"schema" : {
|
||||
|
@ -1996,8 +1996,8 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"400" : {
|
||||
"description" : "Bad Request",
|
||||
"500" : {
|
||||
"description" : "Internal Server Error",
|
||||
"content" : {
|
||||
"application/json" : {
|
||||
"schema" : {
|
||||
|
@ -2148,8 +2148,8 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"500" : {
|
||||
"description" : "Internal Server Error",
|
||||
"400" : {
|
||||
"description" : "Bad Request",
|
||||
"content" : {
|
||||
"application/json" : {
|
||||
"schema" : {
|
||||
|
@ -2162,8 +2162,8 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"400" : {
|
||||
"description" : "Bad Request",
|
||||
"500" : {
|
||||
"description" : "Internal Server Error",
|
||||
"content" : {
|
||||
"application/json" : {
|
||||
"schema" : {
|
||||
|
@ -2314,8 +2314,8 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"500" : {
|
||||
"description" : "Internal Server Error",
|
||||
"400" : {
|
||||
"description" : "Bad Request",
|
||||
"content" : {
|
||||
"application/json" : {
|
||||
"schema" : {
|
||||
|
@ -2328,8 +2328,8 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"400" : {
|
||||
"description" : "Bad Request",
|
||||
"500" : {
|
||||
"description" : "Internal Server Error",
|
||||
"content" : {
|
||||
"application/json" : {
|
||||
"schema" : {
|
||||
|
@ -2478,8 +2478,8 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"500" : {
|
||||
"description" : "Internal Server Error",
|
||||
"400" : {
|
||||
"description" : "Bad Request",
|
||||
"content" : {
|
||||
"application/json" : {
|
||||
"schema" : {
|
||||
|
@ -2492,8 +2492,8 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"400" : {
|
||||
"description" : "Bad Request",
|
||||
"500" : {
|
||||
"description" : "Internal Server Error",
|
||||
"content" : {
|
||||
"application/json" : {
|
||||
"schema" : {
|
||||
|
@ -2633,8 +2633,8 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"500" : {
|
||||
"description" : "Internal Server Error",
|
||||
"400" : {
|
||||
"description" : "Bad Request",
|
||||
"content" : {
|
||||
"application/json" : {
|
||||
"schema" : {
|
||||
|
@ -2647,8 +2647,8 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"400" : {
|
||||
"description" : "Bad Request",
|
||||
"500" : {
|
||||
"description" : "Internal Server Error",
|
||||
"content" : {
|
||||
"application/json" : {
|
||||
"schema" : {
|
||||
|
@ -2797,8 +2797,8 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"500" : {
|
||||
"description" : "Internal Server Error",
|
||||
"400" : {
|
||||
"description" : "Bad Request",
|
||||
"content" : {
|
||||
"application/json" : {
|
||||
"schema" : {
|
||||
|
@ -2811,8 +2811,8 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"400" : {
|
||||
"description" : "Bad Request",
|
||||
"500" : {
|
||||
"description" : "Internal Server Error",
|
||||
"content" : {
|
||||
"application/json" : {
|
||||
"schema" : {
|
||||
|
@ -2952,8 +2952,8 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"500" : {
|
||||
"description" : "Internal Server Error",
|
||||
"400" : {
|
||||
"description" : "Bad Request",
|
||||
"content" : {
|
||||
"application/json" : {
|
||||
"schema" : {
|
||||
|
@ -2966,8 +2966,8 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"400" : {
|
||||
"description" : "Bad Request",
|
||||
"500" : {
|
||||
"description" : "Internal Server Error",
|
||||
"content" : {
|
||||
"application/json" : {
|
||||
"schema" : {
|
||||
|
@ -3127,8 +3127,8 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"500" : {
|
||||
"description" : "Internal Server Error",
|
||||
"400" : {
|
||||
"description" : "Bad Request",
|
||||
"content" : {
|
||||
"application/json" : {
|
||||
"schema" : {
|
||||
|
@ -3141,8 +3141,8 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"400" : {
|
||||
"description" : "Bad Request",
|
||||
"500" : {
|
||||
"description" : "Internal Server Error",
|
||||
"content" : {
|
||||
"application/json" : {
|
||||
"schema" : {
|
||||
|
@ -3247,8 +3247,8 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"500" : {
|
||||
"description" : "Internal Server Error",
|
||||
"400" : {
|
||||
"description" : "Bad Request",
|
||||
"content" : {
|
||||
"application/json" : {
|
||||
"schema" : {
|
||||
|
@ -3261,8 +3261,8 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"400" : {
|
||||
"description" : "Bad Request",
|
||||
"500" : {
|
||||
"description" : "Internal Server Error",
|
||||
"content" : {
|
||||
"application/json" : {
|
||||
"schema" : {
|
||||
|
@ -3362,8 +3362,8 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"500" : {
|
||||
"description" : "Internal Server Error",
|
||||
"400" : {
|
||||
"description" : "Bad Request",
|
||||
"content" : {
|
||||
"application/json" : {
|
||||
"schema" : {
|
||||
|
@ -3376,8 +3376,8 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"400" : {
|
||||
"description" : "Bad Request",
|
||||
"500" : {
|
||||
"description" : "Internal Server Error",
|
||||
"content" : {
|
||||
"application/json" : {
|
||||
"schema" : {
|
||||
|
@ -3488,8 +3488,8 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"500" : {
|
||||
"description" : "Internal Server Error",
|
||||
"400" : {
|
||||
"description" : "Bad Request",
|
||||
"content" : {
|
||||
"application/json" : {
|
||||
"schema" : {
|
||||
|
@ -3502,8 +3502,8 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"400" : {
|
||||
"description" : "Bad Request",
|
||||
"500" : {
|
||||
"description" : "Internal Server Error",
|
||||
"content" : {
|
||||
"application/json" : {
|
||||
"schema" : {
|
||||
|
@ -3650,8 +3650,8 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"500" : {
|
||||
"description" : "Internal Server Error",
|
||||
"400" : {
|
||||
"description" : "Bad Request",
|
||||
"content" : {
|
||||
"application/json" : {
|
||||
"schema" : {
|
||||
|
@ -3664,8 +3664,8 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"400" : {
|
||||
"description" : "Bad Request",
|
||||
"500" : {
|
||||
"description" : "Internal Server Error",
|
||||
"content" : {
|
||||
"application/json" : {
|
||||
"schema" : {
|
||||
|
@ -3803,8 +3803,8 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"500" : {
|
||||
"description" : "Internal Server Error",
|
||||
"400" : {
|
||||
"description" : "Bad Request",
|
||||
"content" : {
|
||||
"application/json" : {
|
||||
"schema" : {
|
||||
|
@ -3817,8 +3817,8 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"400" : {
|
||||
"description" : "Bad Request",
|
||||
"500" : {
|
||||
"description" : "Internal Server Error",
|
||||
"content" : {
|
||||
"application/json" : {
|
||||
"schema" : {
|
||||
|
@ -3924,8 +3924,8 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"500" : {
|
||||
"description" : "Internal Server Error",
|
||||
"400" : {
|
||||
"description" : "Bad Request",
|
||||
"content" : {
|
||||
"application/json" : {
|
||||
"schema" : {
|
||||
|
@ -3938,8 +3938,8 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"400" : {
|
||||
"description" : "Bad Request",
|
||||
"500" : {
|
||||
"description" : "Internal Server Error",
|
||||
"content" : {
|
||||
"application/json" : {
|
||||
"schema" : {
|
||||
|
@ -4048,8 +4048,8 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"500" : {
|
||||
"description" : "Internal Server Error",
|
||||
"400" : {
|
||||
"description" : "Bad Request",
|
||||
"content" : {
|
||||
"application/json" : {
|
||||
"schema" : {
|
||||
|
@ -4062,8 +4062,8 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"400" : {
|
||||
"description" : "Bad Request",
|
||||
"500" : {
|
||||
"description" : "Internal Server Error",
|
||||
"content" : {
|
||||
"application/json" : {
|
||||
"schema" : {
|
||||
|
@ -4171,8 +4171,8 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"500" : {
|
||||
"description" : "Internal Server Error",
|
||||
"400" : {
|
||||
"description" : "Bad Request",
|
||||
"content" : {
|
||||
"application/json" : {
|
||||
"schema" : {
|
||||
|
@ -4185,8 +4185,8 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"400" : {
|
||||
"description" : "Bad Request",
|
||||
"500" : {
|
||||
"description" : "Internal Server Error",
|
||||
"content" : {
|
||||
"application/json" : {
|
||||
"schema" : {
|
||||
|
@ -4309,8 +4309,8 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"500" : {
|
||||
"description" : "Internal Server Error",
|
||||
"400" : {
|
||||
"description" : "Bad Request",
|
||||
"content" : {
|
||||
"application/json" : {
|
||||
"schema" : {
|
||||
|
@ -4323,8 +4323,8 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"400" : {
|
||||
"description" : "Bad Request",
|
||||
"500" : {
|
||||
"description" : "Internal Server Error",
|
||||
"content" : {
|
||||
"application/json" : {
|
||||
"schema" : {
|
||||
|
@ -4447,8 +4447,8 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"500" : {
|
||||
"description" : "Internal Server Error",
|
||||
"400" : {
|
||||
"description" : "Bad Request",
|
||||
"content" : {
|
||||
"application/json" : {
|
||||
"schema" : {
|
||||
|
@ -4461,8 +4461,8 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"400" : {
|
||||
"description" : "Bad Request",
|
||||
"500" : {
|
||||
"description" : "Internal Server Error",
|
||||
"content" : {
|
||||
"application/json" : {
|
||||
"schema" : {
|
||||
|
@ -4578,8 +4578,8 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"500" : {
|
||||
"description" : "Internal Server Error",
|
||||
"400" : {
|
||||
"description" : "Bad Request",
|
||||
"content" : {
|
||||
"application/json" : {
|
||||
"schema" : {
|
||||
|
@ -4592,8 +4592,8 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"400" : {
|
||||
"description" : "Bad Request",
|
||||
"500" : {
|
||||
"description" : "Internal Server Error",
|
||||
"content" : {
|
||||
"application/json" : {
|
||||
"schema" : {
|
||||
|
@ -4716,8 +4716,8 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"500" : {
|
||||
"description" : "Internal Server Error",
|
||||
"400" : {
|
||||
"description" : "Bad Request",
|
||||
"content" : {
|
||||
"application/json" : {
|
||||
"schema" : {
|
||||
|
@ -4730,8 +4730,8 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"400" : {
|
||||
"description" : "Bad Request",
|
||||
"500" : {
|
||||
"description" : "Internal Server Error",
|
||||
"content" : {
|
||||
"application/json" : {
|
||||
"schema" : {
|
||||
|
@ -4839,8 +4839,8 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"500" : {
|
||||
"description" : "Internal Server Error",
|
||||
"400" : {
|
||||
"description" : "Bad Request",
|
||||
"content" : {
|
||||
"application/json" : {
|
||||
"schema" : {
|
||||
|
@ -4853,8 +4853,8 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"400" : {
|
||||
"description" : "Bad Request",
|
||||
"500" : {
|
||||
"description" : "Internal Server Error",
|
||||
"content" : {
|
||||
"application/json" : {
|
||||
"schema" : {
|
||||
|
@ -4977,8 +4977,8 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"500" : {
|
||||
"description" : "Internal Server Error",
|
||||
"400" : {
|
||||
"description" : "Bad Request",
|
||||
"content" : {
|
||||
"application/json" : {
|
||||
"schema" : {
|
||||
|
@ -4991,8 +4991,8 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"400" : {
|
||||
"description" : "Bad Request",
|
||||
"500" : {
|
||||
"description" : "Internal Server Error",
|
||||
"content" : {
|
||||
"application/json" : {
|
||||
"schema" : {
|
||||
|
@ -5107,8 +5107,8 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"500" : {
|
||||
"description" : "Internal Server Error",
|
||||
"400" : {
|
||||
"description" : "Bad Request",
|
||||
"content" : {
|
||||
"application/json" : {
|
||||
"schema" : {
|
||||
|
@ -5121,8 +5121,8 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"400" : {
|
||||
"description" : "Bad Request",
|
||||
"500" : {
|
||||
"description" : "Internal Server Error",
|
||||
"content" : {
|
||||
"application/json" : {
|
||||
"schema" : {
|
||||
|
@ -5793,7 +5793,13 @@
|
|||
"type" : "string",
|
||||
"format" : "date-time"
|
||||
},
|
||||
"failedStatusMessage" : {
|
||||
"previousRunSuccessfull" : {
|
||||
"type" : "boolean"
|
||||
},
|
||||
"lastFailedRunMessage" : {
|
||||
"type" : "string"
|
||||
},
|
||||
"instanceId" : {
|
||||
"type" : "string"
|
||||
},
|
||||
"get_etag" : {
|
||||
|
@ -5834,13 +5840,13 @@
|
|||
"type" : "integer",
|
||||
"format" : "int64"
|
||||
},
|
||||
"zero" : {
|
||||
"type" : "boolean"
|
||||
},
|
||||
"nano" : {
|
||||
"type" : "integer",
|
||||
"format" : "int32"
|
||||
},
|
||||
"zero" : {
|
||||
"type" : "boolean"
|
||||
},
|
||||
"negative" : {
|
||||
"type" : "boolean"
|
||||
},
|
||||
|
|
|
@ -26,7 +26,9 @@ public class Task {
|
|||
private String id;
|
||||
private TaskStatus status;
|
||||
private OffsetDateTime previousRun;
|
||||
private String failedStatusMessage;
|
||||
private Boolean previousRunSuccessfull;
|
||||
private String lastFailedRunMessage;
|
||||
private String instanceId;
|
||||
|
||||
@Version
|
||||
@SuppressWarnings("java:S116")
|
||||
|
|
|
@ -96,7 +96,7 @@ public class TaskService {
|
|||
allTasks.forEach(task -> {
|
||||
if (!READY.equals(task.getStatus())) {
|
||||
task.setStatus(READY);
|
||||
task.setFailedStatusMessage("Restored manually");
|
||||
task.setLastFailedRunMessage("Restored manually");
|
||||
taskRepository.save(task);
|
||||
}
|
||||
});
|
||||
|
@ -174,13 +174,13 @@ public class TaskService {
|
|||
(long) (timeout.toSeconds() * applicationProperties.getTaskResetTimeoutMultiplier()));
|
||||
if (timeAfterPreviousRun.compareTo(acceptableDelayBeforeWarning) > 0) {
|
||||
log.warn("Task [{}] is idle for too long. Last execution was [{}] minutes ago with status message: [{}]",
|
||||
task.getId(), timeAfterPreviousRun.toMinutes(), task.getFailedStatusMessage());
|
||||
task.getId(), timeAfterPreviousRun.toMinutes(), task.getLastFailedRunMessage());
|
||||
}
|
||||
if (!READY.equals(task.getStatus()) && timeAfterPreviousRun.compareTo(acceptableDelayBeforeReset) > 0) {
|
||||
try {
|
||||
log.info("Start [{}] task restore", task.getId());
|
||||
task.setStatus(READY);
|
||||
task.setFailedStatusMessage("Restored after long downtime");
|
||||
task.setLastFailedRunMessage("Restored after long downtime");
|
||||
taskRepository.save(task);
|
||||
log.info("Task [{}] has been restored", task.getId());
|
||||
} catch (CosmosDBAccessException e) {
|
||||
|
@ -225,7 +225,7 @@ public class TaskService {
|
|||
* have to be saved to the database with updated {@link Task#getStatus()}.
|
||||
* </p>
|
||||
* In case task execution failed with an exception,
|
||||
* {@link Task#getFailedStatusMessage()} is set to
|
||||
* {@link Task#getLastFailedRunMessage()} is set to
|
||||
* {@link Exception#getMessage()} and new state saved into the database.
|
||||
*
|
||||
* @param task which should represent a lock object
|
||||
|
@ -246,6 +246,7 @@ public class TaskService {
|
|||
// acquire a lock
|
||||
OffsetDateTime startTime = OffsetDateTime.now();
|
||||
task.setStatus(RUNNING);
|
||||
task.setInstanceId(applicationProperties.getInstanceId());
|
||||
if (task.getPreviousRun() == null){
|
||||
task.setPreviousRun(startTime);
|
||||
}
|
||||
|
@ -279,10 +280,12 @@ public class TaskService {
|
|||
.whenComplete((result, exception) -> {
|
||||
runningTask.setStatus(READY);
|
||||
runningTask.setPreviousRun(startTime);
|
||||
runningTask.setPreviousRunSuccessfull(true);
|
||||
if (exception != null) {
|
||||
log.warn("Task [{}] finished its execution with an exception.",
|
||||
runningTask.getId(), exception);
|
||||
runningTask.setFailedStatusMessage(exception.getMessage());
|
||||
runningTask.setLastFailedRunMessage(exception.getMessage());
|
||||
runningTask.setPreviousRunSuccessfull(false);
|
||||
taskRepository.save(runningTask);
|
||||
} else if (result.isEmpty()) {
|
||||
log.info("Task [{}] finished its execution with empty result.", runningTask.getId());
|
||||
|
|
|
@ -33,7 +33,7 @@ azure:
|
|||
cosmosdb:
|
||||
default-ttl: P1827D
|
||||
dfp:
|
||||
purchase-status-event-url: https://${TENANT_SHORT_NAME}-${TENANT_ID}.api.dfp.dynamics-int.com/v1.0/merchantservices/events/PurchaseStatus
|
||||
purchase-status-event-url: https://${CLIENT_TENANT_SHORT_NAME}-${CLIENT_TENANT_ID}.api.dfp.dynamics-int.com/v1.0/merchantservices/events/PurchaseStatus
|
||||
graph-api:
|
||||
role-assignments-url: https://graph.microsoft.com/v1.0/servicePrincipals/${DFP_SP_ID}/appRoleAssignedTo
|
||||
user-role-assignments-url-template: https://graph.microsoft.com/v1.0/users/#user_id#/appRoleAssignments?$filter=resourceId eq ${DFP_SP_ID}
|
||||
|
@ -41,6 +41,8 @@ azure:
|
|||
user-url-template: https://graph.microsoft.com/v1.0/users/#user_id#
|
||||
app-service-principal-url: https://graph.microsoft.com/v1.0/servicePrincipals/${DFP_SP_ID}
|
||||
user-photo-url-template: https://graph.microsoft.com/beta/users/#user_id#/photo/$value
|
||||
timeout: PT5S
|
||||
retries: 2
|
||||
role-mapping:
|
||||
ManualReviewFraudManager: ADMIN_MANAGER
|
||||
ManualReviewSeniorAnalyst: SENIOR_ANALYST
|
||||
|
@ -61,7 +63,7 @@ azure:
|
|||
|
||||
swagger:
|
||||
# the https://cors-anywhere.herokuapp.com/ prefix is only for dev environments
|
||||
token-url: https://cors-anywhere.herokuapp.com/https://login.microsoftonline.com/${TENANT_ID}/oauth2/v2.0/token
|
||||
token-url: https://cors-anywhere.herokuapp.com/https://login.microsoftonline.com/${CLIENT_TENANT_ID}/oauth2/v2.0/token
|
||||
|
||||
spring:
|
||||
security:
|
||||
|
@ -74,9 +76,9 @@ spring:
|
|||
scope: https://api.dfp.microsoft-int.com/.default
|
||||
provider:
|
||||
azure-graph-api:
|
||||
token-uri: https://login.microsoftonline.com/${TENANT_ID}/oauth2/v2.0/token
|
||||
token-uri: https://login.microsoftonline.com/${CLIENT_TENANT_ID}/oauth2/v2.0/token
|
||||
azure-dfp-api:
|
||||
token-uri: https://login.microsoftonline.com/${TENANT_ID}/oauth2/v2.0/token
|
||||
token-uri: https://login.microsoftonline.com/${CLIENT_TENANT_ID}/oauth2/v2.0/token
|
||||
|
||||
resilience4j.retry:
|
||||
instances:
|
||||
|
|
|
@ -27,4 +27,4 @@ azure:
|
|||
# Use service principle to authenticate locally
|
||||
client-key: ${CLIENT_SECRET}
|
||||
client-id: ${CLIENT_ID}
|
||||
tenant-id: ${TENANT_ID}
|
||||
tenant-id: ${CLIENT_TENANT_ID}
|
||||
|
|
|
@ -32,7 +32,7 @@ azure:
|
|||
cosmosdb:
|
||||
default-ttl: P1827D
|
||||
dfp:
|
||||
purchase-status-event-url: https://${TENANT_SHORT_NAME}-${TENANT_ID}.api.dfp.dynamics.com/v1.0/merchantservices/events/PurchaseStatus
|
||||
purchase-status-event-url: https://${CLIENT_TENANT_SHORT_NAME}-${CLIENT_TENANT_ID}.api.dfp.dynamics.com/v1.0/merchantservices/events/PurchaseStatus
|
||||
graph-api:
|
||||
role-assignments-url: https://graph.microsoft.com/v1.0/servicePrincipals/${DFP_SP_ID}/appRoleAssignedTo
|
||||
user-role-assignments-url-template: https://graph.microsoft.com/v1.0/users/#user_id#/appRoleAssignments?$filter=resourceId eq ${DFP_SP_ID}
|
||||
|
@ -40,6 +40,8 @@ azure:
|
|||
user-url-template: https://graph.microsoft.com/v1.0/users/#user_id#
|
||||
app-service-principal-url: https://graph.microsoft.com/v1.0/servicePrincipals/${DFP_SP_ID}
|
||||
user-photo-url-template: https://graph.microsoft.com/beta/users/#user_id#/photo/$value
|
||||
timeout: PT5S
|
||||
retries: 2
|
||||
role-mapping:
|
||||
ManualReviewFraudManager: ADMIN_MANAGER
|
||||
ManualReviewSeniorAnalyst: SENIOR_ANALYST
|
||||
|
@ -56,7 +58,7 @@ azure:
|
|||
health-check-allowed-delay: PT60M
|
||||
|
||||
swagger:
|
||||
token-url: https://login.microsoftonline.com/${TENANT_ID}/oauth2/v2.0/token
|
||||
token-url: https://login.microsoftonline.com/${CLIENT_TENANT_ID}/oauth2/v2.0/token
|
||||
|
||||
spring:
|
||||
security:
|
||||
|
@ -69,9 +71,9 @@ spring:
|
|||
scope: https://api.dfp.microsoft.com/.default
|
||||
provider:
|
||||
azure-graph-api:
|
||||
token-uri: https://login.microsoftonline.com/${TENANT_ID}/oauth2/v2.0/token
|
||||
token-uri: https://login.microsoftonline.com/${CLIENT_TENANT_ID}/oauth2/v2.0/token
|
||||
azure-dfp-api:
|
||||
token-uri: https://login.microsoftonline.com/${TENANT_ID}/oauth2/v2.0/token
|
||||
token-uri: https://login.microsoftonline.com/${CLIENT_TENANT_ID}/oauth2/v2.0/token
|
||||
|
||||
resilience4j.retry:
|
||||
instances:
|
||||
|
|
|
@ -54,7 +54,7 @@ azure:
|
|||
session-stateless: true
|
||||
app-id-uri: api://${CLIENT_ID}
|
||||
dfp:
|
||||
purchase-status-event-url: https://${TENANT_SHORT_NAME}-${TENANT_ID}.api.dfp.dynamics-int.com/v1.0/merchantservices/events/PurchaseStatus
|
||||
purchase-status-event-url: https://${CLIENT_TENANT_SHORT_NAME}-${CLIENT_TENANT_ID}.api.dfp.dynamics-int.com/v1.0/merchantservices/events/PurchaseStatus
|
||||
graph-api:
|
||||
role-assignments-url: https://graph.microsoft.com/v1.0/servicePrincipals/${DFP_SP_ID}/appRoleAssignedTo
|
||||
user-role-assignments-url-template: https://graph.microsoft.com/v1.0/users/#user_id#/appRoleAssignments?$filter=resourceId eq ${DFP_SP_ID}
|
||||
|
@ -62,6 +62,8 @@ azure:
|
|||
user-url-template: https://graph.microsoft.com/v1.0/users/#user_id#
|
||||
app-service-principal-url: https://graph.microsoft.com/v1.0/servicePrincipals/${DFP_SP_ID}
|
||||
user-photo-url-template: https://graph.microsoft.com/beta/users/#user_id#/photo/$value
|
||||
timeout: PT5S
|
||||
retries: 2
|
||||
role-mapping:
|
||||
ManualReviewFraudManager: ADMIN_MANAGER
|
||||
ManualReviewSeniorAnalyst: SENIOR_ANALYST
|
||||
|
@ -110,9 +112,9 @@ azure:
|
|||
group: ${spring.application.name}
|
||||
|
||||
swagger:
|
||||
auth-url: https://login.microsoftonline.com/${TENANT_ID}/oauth2/authorize?resource=${CLIENT_ID}
|
||||
auth-url: https://login.microsoftonline.com/${CLIENT_TENANT_ID}/oauth2/authorize?resource=${CLIENT_ID}
|
||||
# the https://cors-anywhere.herokuapp.com/ prefix is only for dev environments
|
||||
token-url: https://cors-anywhere.herokuapp.com/https://login.microsoftonline.com/${TENANT_ID}/oauth2/v2.0/token
|
||||
token-url: https://cors-anywhere.herokuapp.com/https://login.microsoftonline.com/${CLIENT_TENANT_ID}/oauth2/v2.0/token
|
||||
token-scope: ${azure.activedirectory.app-id-uri}/.default
|
||||
|
||||
spring:
|
||||
|
@ -134,9 +136,9 @@ spring:
|
|||
scope: https://api.dfp.microsoft-int.com/.default
|
||||
provider:
|
||||
azure-graph-api:
|
||||
token-uri: https://login.microsoftonline.com/${TENANT_ID}/oauth2/v2.0/token
|
||||
token-uri: https://login.microsoftonline.com/${CLIENT_TENANT_ID}/oauth2/v2.0/token
|
||||
azure-dfp-api:
|
||||
token-uri: https://login.microsoftonline.com/${TENANT_ID}/oauth2/v2.0/token
|
||||
token-uri: https://login.microsoftonline.com/${CLIENT_TENANT_ID}/oauth2/v2.0/token
|
||||
aop:
|
||||
proxyTargetClass: true
|
||||
mail:
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
package com.griddynamics.msd365fp.manualreview.analytics.service;
|
||||
|
||||
import com.griddynamics.msd365fp.manualreview.analytics.config.ModelMapperConfig;
|
||||
import com.griddynamics.msd365fp.manualreview.analytics.config.properties.ApplicationProperties;
|
||||
import com.griddynamics.msd365fp.manualreview.analytics.model.persistence.*;
|
||||
import com.griddynamics.msd365fp.manualreview.analytics.repository.*;
|
||||
import com.griddynamics.msd365fp.manualreview.model.Label;
|
||||
|
@ -52,6 +53,10 @@ class StreamServiceTest {
|
|||
ItemPlacementActivityRepository itemPlacementActivityRepository;
|
||||
@Mock
|
||||
QueueSizeCalculationActivityRepository queueSizeCalculationActivityRepository;
|
||||
@Mock
|
||||
HealthCheckRepository healthCheckRepository;
|
||||
@Mock
|
||||
ApplicationProperties applicationProperties;
|
||||
|
||||
@Captor
|
||||
private ArgumentCaptor<Iterable<ItemPlacementActivityEntity>> placementCaptor;
|
||||
|
@ -73,7 +78,7 @@ class StreamServiceTest {
|
|||
ModelMapper modelMapper = new ModelMapperConfig().modelMapper();
|
||||
this.streamService = new StreamService(resolutionRepository, itemLockActivityRepository,
|
||||
collectedQueueInfoRepository, queueSizeCalculationActivityRepository, performanceRepository,
|
||||
itemPlacementActivityRepository, modelMapper);
|
||||
itemPlacementActivityRepository, healthCheckRepository, applicationProperties, modelMapper);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -33,7 +33,7 @@ spring:
|
|||
scope: https://graph.microsoft.com/.default
|
||||
provider:
|
||||
azure-graph-api:
|
||||
token-uri: https://login.microsoftonline.com/${TENANT_ID}/oauth2/v2.0/token
|
||||
token-uri: https://login.microsoftonline.com/${CLIENT_TENANT_ID}/oauth2/v2.0/token
|
||||
|
||||
```
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-5.2.1-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.3-all.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
|
|
@ -131,6 +131,8 @@ public class AnalystClient {
|
|||
.uri(properties.getUserPhotoUrlTemplate().replace(USER_ID_PLACEHOLDER, id))
|
||||
.retrieve()
|
||||
.bodyToMono(byte[].class)
|
||||
.timeout(properties.getTimeout())
|
||||
.retry(properties.getRetries() == null ? 0 : properties.getRetries())
|
||||
.block();
|
||||
} catch (WebClientResponseException.NotFound e) {
|
||||
throw new EmptySourceException();
|
||||
|
@ -161,6 +163,8 @@ public class AnalystClient {
|
|||
.uri(properties.getAppServicePrincipalUrl())
|
||||
.retrieve()
|
||||
.bodyToMono(ServicePrincipalDTO.class)
|
||||
.timeout(properties.getTimeout())
|
||||
.retry(properties.getRetries() == null ? 0 : properties.getRetries())
|
||||
.block(Duration.of(1, ChronoUnit.MINUTES));
|
||||
|
||||
return Stream.ofNullable(res);
|
||||
|
@ -173,6 +177,8 @@ public class AnalystClient {
|
|||
.uri(properties.getUserUrlTemplate().replace(USER_ID_PLACEHOLDER, id))
|
||||
.retrieve()
|
||||
.bodyToMono(UserDTO.class)
|
||||
.timeout(properties.getTimeout())
|
||||
.retry(properties.getRetries() == null ? 0 : properties.getRetries())
|
||||
.block();
|
||||
}
|
||||
|
||||
|
@ -213,6 +219,8 @@ public class AnalystClient {
|
|||
.uri(url)
|
||||
.retrieve()
|
||||
.bodyToMono(cls)
|
||||
.timeout(properties.getTimeout())
|
||||
.retry(properties.getRetries() == null ? 0 : properties.getRetries())
|
||||
.block();
|
||||
url = null;
|
||||
if (response != null) {
|
||||
|
|
|
@ -8,6 +8,7 @@ import lombok.Getter;
|
|||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.boot.context.properties.ConstructorBinding;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.Map;
|
||||
|
||||
@Getter
|
||||
|
@ -31,5 +32,7 @@ public class AnalystClientProperties {
|
|||
private final String usersUrl;
|
||||
private final String userUrlTemplate;
|
||||
private final String userPhotoUrlTemplate;
|
||||
private final Duration timeout;
|
||||
private final Long retries;
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-5.2.1-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.3-all.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
|
|
@ -55,7 +55,9 @@ public class ExtendedCosmosContainer {
|
|||
final FeedOptions feedOptions = new FeedOptions();
|
||||
feedOptions.enableCrossPartitionQuery(true);
|
||||
feedOptions.maxItemCount(size);
|
||||
feedOptions.requestContinuation(continuationToken);
|
||||
if (continuationToken != null) {
|
||||
feedOptions.requestContinuation(continuationToken);
|
||||
}
|
||||
Flux<FeedResponse<CosmosItemProperties>> feedResponseFlux =
|
||||
container.queryItems(query, feedOptions);
|
||||
FeedResponse<CosmosItemProperties> res = feedResponseFlux.blockFirst(Duration.ofSeconds(DEFAULT_COSMOS_TIMEOUT_SEC));
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-5.2.1-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.3-all.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-5.2.1-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.3-all.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
|
|
@ -18,13 +18,13 @@ AD_APP_NAME=${SOLUTION_NAME}
|
|||
GROUP_NAME=${SOLUTION_NAME}-rg
|
||||
ANALYTICS_APP_SERVICE_NAME=${SOLUTION_NAME}-analytics
|
||||
|
||||
TENANT_ID=$(az account show --query=tenantId)
|
||||
TENANT_ID="${TENANT_ID%\"}"
|
||||
export TENANT_ID="${TENANT_ID#\"}"
|
||||
CLIENT_TENANT_ID=$(az account show --query=tenantId)
|
||||
CLIENT_TENANT_ID="${CLIENT_TENANT_ID%\"}"
|
||||
export CLIENT_TENANT_ID="${CLIENT_TENANT_ID#\"}"
|
||||
|
||||
TENANT_SHORT_NAME=$(az account show --query=name)
|
||||
TENANT_SHORT_NAME="${TENANT_SHORT_NAME%.onmicrosoft.com\"}"
|
||||
export TENANT_SHORT_NAME="${TENANT_SHORT_NAME#\"}"
|
||||
CLIENT_TENANT_SHORT_NAME=$(az account show --query=name)
|
||||
CLIENT_TENANT_SHORT_NAME="${CLIENT_TENANT_SHORT_NAME%.onmicrosoft.com\"}"
|
||||
export CLIENT_TENANT_SHORT_NAME="${CLIENT_TENANT_SHORT_NAME#\"}"
|
||||
|
||||
COSMOSDB_ACCOUNT_NAME=${SOLUTION_NAME}-storage
|
||||
COSMOSDB_ENDPOINT=$(az cosmosdb show \
|
||||
|
@ -136,7 +136,10 @@ echo COSMOSDB_ENDPOINT=${COSMOSDB_ENDPOINT}
|
|||
echo COSMOSDB_KEY=${COSMOSDB_KEY}
|
||||
echo CLIENT_ID=${CLIENT_ID}
|
||||
echo CLIENT_SECRET=${CLIENT_SECRET}
|
||||
echo TENANT_ID=${TENANT_ID}
|
||||
echo MAP_CLIENT_ID=${CLIENT_ID}
|
||||
echo MAP_CLIENT_SECRET=${CLIENT_SECRET}
|
||||
echo TENANT_ID=${CLIENT_TENANT_ID}
|
||||
echo CLIENT_TENANT_ID=${CLIENT_TENANT_ID}
|
||||
echo APP_SP_ID=${APP_SP_ID}
|
||||
echo DFP_SP_ID=${DFP_SP_ID}
|
||||
echo EVENT_HUB_CONNECTION_STRING=${EVENT_HUB_CONNECTION_STRING}
|
||||
|
@ -148,5 +151,5 @@ echo MAIL_SMTP_PORT=${MAIL_SMTP_PORT}
|
|||
echo MAIL_USERNAME=${MAIL_USERNAME}
|
||||
echo MAIL_PASSWORD=${MAIL_PASSWORD}
|
||||
echo KEYVAULT_ENDPOINT=${KEYVAULT_ENDPOINT}
|
||||
echo TENANT_SHORT_NAME=${TENANT_SHORT_NAME}
|
||||
echo SPRING_PROFILES_ACTIVE=local
|
||||
echo CLIENT_TENANT_SHORT_NAME=${CLIENT_TENANT_SHORT_NAME}
|
||||
echo SPRING_PROFILES_ACTIVE=local
|
|
@ -1,5 +1,5 @@
|
|||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.5.1-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.3-all.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
|
|
@ -30,6 +30,8 @@ jar {
|
|||
dependencies {
|
||||
implementation 'com.fasterxml.jackson.core:jackson-annotations:2.11.2'
|
||||
implementation 'com.fasterxml.jackson.core:jackson-databind:2.11.2'
|
||||
implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.11.2'
|
||||
|
||||
implementation 'io.swagger.core.v3:swagger-annotations:2.1.2'
|
||||
implementation 'org.apache.commons:commons-lang3:3.9'
|
||||
implementation 'org.springframework:spring-core'
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-5.2.1-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.3-all.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
package com.griddynamics.msd365fp.manualreview.model;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class Constants {
|
||||
public static final String DFP_DATE_TIME_PATTERN = "MM/dd/yyyy HH:mm:ss xxxxx";
|
||||
public static final String ISO_OFFSET_DATE_TIME_PATTERN = "yyyy-MM-dd'T'HH:mm:ss.SSSSSSXXXXX";
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package com.griddynamics.msd365fp.manualreview.model;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
public class DisposabilityCheck {
|
||||
private Boolean disposable;
|
||||
private List<DisposabilityCheckServiceResponse> disposabilityResponses;
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
package com.griddynamics.msd365fp.manualreview.model;
|
||||
|
||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.griddynamics.msd365fp.manualreview.model.jackson.EpochSecondsDateTimeSerializer;
|
||||
import com.griddynamics.msd365fp.manualreview.model.jackson.FlexibleDateFormatDeserializer;
|
||||
import com.griddynamics.msd365fp.manualreview.model.jackson.ISOStringDateTimeSerializer;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.OffsetDateTime;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class DisposabilityCheckServiceResponse implements Serializable {
|
||||
private Boolean disposable;
|
||||
private String resource;
|
||||
@JsonDeserialize(using = FlexibleDateFormatDeserializer.class)
|
||||
@JsonSerialize(using = ISOStringDateTimeSerializer.class)
|
||||
private OffsetDateTime checked;
|
||||
private String rawResponse;
|
||||
|
||||
/**
|
||||
* Getter for advanced serialization.
|
||||
* Json object will contain both representation of DateTime field -
|
||||
* timestamp (for SQL queries) and string representation.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
@JsonSerialize(using = EpochSecondsDateTimeSerializer.class)
|
||||
public OffsetDateTime getCheckedEpochSeconds() {
|
||||
return checked;
|
||||
}
|
||||
|
||||
}
|
|
@ -3,21 +3,20 @@
|
|||
|
||||
package com.griddynamics.msd365fp.manualreview.model.dfp;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonAnySetter;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonNaming;
|
||||
import lombok.*;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
@NoArgsConstructor
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
@JsonNaming(PropertyNamingStrategy.UpperCamelCaseStrategy.class)
|
||||
public class Address implements Serializable {
|
||||
|
||||
private String addressId;
|
||||
private String type;
|
||||
private String firstName;
|
||||
|
@ -31,5 +30,14 @@ public class Address implements Serializable {
|
|||
private String district;
|
||||
private String zipCode;
|
||||
private String country;
|
||||
private String countryRegion;
|
||||
|
||||
private Map<String, String> additionalParams = new HashMap<>();
|
||||
|
||||
@JsonAnySetter
|
||||
public void setAdditionalParam(String name, String value) {
|
||||
additionalParams.put(name, value);
|
||||
}
|
||||
public void setAdditionalParams(Map<String, String> map) {
|
||||
additionalParams.putAll(map);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,19 +3,19 @@
|
|||
|
||||
package com.griddynamics.msd365fp.manualreview.model.dfp;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonAnySetter;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonNaming;
|
||||
import lombok.*;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
@NoArgsConstructor
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
@JsonNaming(PropertyNamingStrategy.UpperCamelCaseStrategy.class)
|
||||
public class AssesmentResult implements Serializable {
|
||||
|
@ -27,4 +27,14 @@ public class AssesmentResult implements Serializable {
|
|||
private String policyApplied;
|
||||
private List<PurchaseStatus> purchaseStatusList;
|
||||
|
||||
private Map<String, String> additionalParams = new HashMap<>();
|
||||
|
||||
@JsonAnySetter
|
||||
public void setAdditionalParam(String name, String value) {
|
||||
additionalParams.put(name, value);
|
||||
}
|
||||
public void setAdditionalParams(Map<String, String> map) {
|
||||
additionalParams.putAll(map);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -3,24 +3,31 @@
|
|||
|
||||
package com.griddynamics.msd365fp.manualreview.model.dfp;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonAnySetter;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonNaming;
|
||||
import lombok.*;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.griddynamics.msd365fp.manualreview.model.jackson.EpochSecondsDateTimeSerializer;
|
||||
import com.griddynamics.msd365fp.manualreview.model.jackson.FlexibleDateFormatDeserializer;
|
||||
import com.griddynamics.msd365fp.manualreview.model.jackson.ISOStringDateTimeSerializer;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
@NoArgsConstructor
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
@JsonNaming(PropertyNamingStrategy.UpperCamelCaseStrategy.class)
|
||||
public class BankEvent implements Serializable {
|
||||
private String bankEventId;
|
||||
private String type;
|
||||
@JsonDeserialize(using = FlexibleDateFormatDeserializer.class)
|
||||
@JsonSerialize(using = ISOStringDateTimeSerializer.class)
|
||||
private OffsetDateTime bankEventTimestamp;
|
||||
private String status;
|
||||
private String bankResponseCode;
|
||||
|
@ -29,4 +36,25 @@ public class BankEvent implements Serializable {
|
|||
private String mrn;
|
||||
@JsonProperty("MID")
|
||||
private String mid;
|
||||
|
||||
private Map<String, String> additionalParams = new HashMap<>();
|
||||
|
||||
@JsonAnySetter
|
||||
public void setAdditionalParam(String name, String value) {
|
||||
additionalParams.put(name, value);
|
||||
}
|
||||
public void setAdditionalParams(Map<String, String> map) {
|
||||
additionalParams.putAll(map);
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for advanced serialization.
|
||||
* Json object will contain both representation of DateTime field -
|
||||
* timestamp (for SQL queries) and string representation.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
@JsonSerialize(using = EpochSecondsDateTimeSerializer.class)
|
||||
public OffsetDateTime getBankEventTimestampEpochSeconds() {
|
||||
return bankEventTimestamp;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,13 @@
|
|||
package com.griddynamics.msd365fp.manualreview.model.dfp;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import lombok.*;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.griddynamics.msd365fp.manualreview.model.DisposabilityCheckServiceResponse;
|
||||
import com.griddynamics.msd365fp.manualreview.model.jackson.EpochSecondsDateTimeSerializer;
|
||||
import com.griddynamics.msd365fp.manualreview.model.jackson.FlexibleDateFormatDeserializer;
|
||||
import com.griddynamics.msd365fp.manualreview.model.jackson.ISOStringDateTimeSerializer;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
|
@ -13,75 +19,56 @@ import java.util.List;
|
|||
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
@NoArgsConstructor
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
public class CalculatedFields implements Serializable {
|
||||
|
||||
// Geo data
|
||||
private Boolean matchingOfCountriesForShippingAndIP;
|
||||
private Boolean matchingOfCountriesForBillingAndShipping;
|
||||
private Boolean matchingOfCountriesForBillingAndIP;
|
||||
|
||||
private List<String> billingCountries;
|
||||
private List<String> billingZipCodes;
|
||||
private List<String> billingAddresses;
|
||||
private BigDecimal distanceToPreviousTransactionIP;
|
||||
|
||||
private Integer accountAgeInDays;
|
||||
private Integer activityAgeInDays;
|
||||
// Account statistic
|
||||
private Long accountAgeInDays;
|
||||
private Long activityAgeInDays;
|
||||
@JsonDeserialize(using = FlexibleDateFormatDeserializer.class)
|
||||
@JsonSerialize(using = ISOStringDateTimeSerializer.class)
|
||||
private OffsetDateTime firstTransactionDateTime;
|
||||
|
||||
private Boolean aggregatedEmailConfirmed;
|
||||
private String aggregatedEmailDomain;
|
||||
private Boolean disposableEmailDomain;
|
||||
private List<DisposabilityCheckServiceResponse> disposabilityChecks;
|
||||
|
||||
private List<String> authResultCodes;
|
||||
private List<String> approveResultCodes;
|
||||
private List<String> declineResultCodes;
|
||||
// Bank data
|
||||
private List<String> authBankEventResultCodes;
|
||||
private List<String> approveBankEventResultCodes;
|
||||
private List<String> declineBankEventResultCodes;
|
||||
|
||||
private Integer lastHourTransactionCount;
|
||||
private Integer lastDayTransactionCount;
|
||||
private Integer lastWeekTransactionCount;
|
||||
// Previous transactions statistic
|
||||
private Velocity<Long> transactionCount;
|
||||
private Velocity<BigDecimal> transactionAmount;
|
||||
private Velocity<Long> rejectedTransactionCount;
|
||||
private Velocity<BigDecimal> rejectedTransactionAmount;
|
||||
private Velocity<Long> failedTransactionCount;
|
||||
private Velocity<BigDecimal> failedTransactionAmount;
|
||||
private Velocity<Long> successfulTransactionCount;
|
||||
private Velocity<BigDecimal> successfulTransactionAmount;
|
||||
private Velocity<Long> currentPaymentInstrumentTransactionCount;
|
||||
private Velocity<BigDecimal> currentPaymentInstrumentTransactionAmount;
|
||||
private Velocity<Long> uniquePaymentInstrumentCount;
|
||||
private Velocity<Long> uniqueIPCountries;
|
||||
|
||||
private BigDecimal lastHourTransactionAmount;
|
||||
private BigDecimal lastDayTransactionAmount;
|
||||
private BigDecimal lastWeekTransactionAmount;
|
||||
|
||||
private Integer lastHourRejectedTransactionCount;
|
||||
private Integer lastDayRejectedTransactionCount;
|
||||
private Integer lastWeekRejectedTransactionCount;
|
||||
|
||||
private BigDecimal lastHourRejectedTransactionAmount;
|
||||
private BigDecimal lastDayRejectedTransactionAmount;
|
||||
private BigDecimal lastWeekRejectedTransactionAmount;
|
||||
|
||||
private Integer lastHourFailedTransactionCount;
|
||||
private Integer lastDayFailedTransactionCount;
|
||||
private Integer lastWeekFailedTransactionCount;
|
||||
|
||||
private BigDecimal lastHourFailedTransactionAmount;
|
||||
private BigDecimal lastDayFailedTransactionAmount;
|
||||
private BigDecimal lastWeekFailedTransactionAmount;
|
||||
|
||||
private Integer lastHourSuccessfulTransactionCount;
|
||||
private Integer lastDaySuccessfulTransactionCount;
|
||||
private Integer lastWeekSuccessfulTransactionCount;
|
||||
|
||||
private BigDecimal lastHourSuccessfulTransactionAmount;
|
||||
private BigDecimal lastDaySuccessfulTransactionAmount;
|
||||
private BigDecimal lastWeekSuccessfulTransactionAmount;
|
||||
|
||||
private Integer lastHourUniquePaymentInstrumentCount;
|
||||
private Integer lastDayUniquePaymentInstrumentCount;
|
||||
private Integer lastWeekUniquePaymentInstrumentCount;
|
||||
|
||||
private Integer lastHourTransactionCountWithCurrentPaymentInstrument;
|
||||
private Integer lastDayTransactionCountWithCurrentPaymentInstrument;
|
||||
private Integer lastWeekTransactionCountWithCurrentPaymentInstrument;
|
||||
|
||||
private BigDecimal lastHourTransactionAmountWithCurrentPaymentInstrument;
|
||||
private BigDecimal lastDayTransactionAmountWithCurrentPaymentInstrument;
|
||||
private BigDecimal lastWeekTransactionAmountWithCurrentPaymentInstrument;
|
||||
|
||||
private Integer lastHourUniqueIPCountries;
|
||||
private Integer lastDayUniqueIPCountries;
|
||||
private Integer lastWeekUniqueIPCountries;
|
||||
/**
|
||||
* Getter for advanced serialization.
|
||||
* Json object will contain both representation of DateTime field -
|
||||
* timestamp (for SQL queries) and string representation.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
@JsonSerialize(using = EpochSecondsDateTimeSerializer.class)
|
||||
public OffsetDateTime getFirstTransactionDateTimeEpochSeconds() {
|
||||
return firstTransactionDateTime;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,21 +3,26 @@
|
|||
|
||||
package com.griddynamics.msd365fp.manualreview.model.dfp;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonAnySetter;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonNaming;
|
||||
import lombok.*;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.griddynamics.msd365fp.manualreview.model.jackson.EpochSecondsDateTimeSerializer;
|
||||
import com.griddynamics.msd365fp.manualreview.model.jackson.FlexibleDateFormatDeserializer;
|
||||
import com.griddynamics.msd365fp.manualreview.model.jackson.ISOStringDateTimeSerializer;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
@NoArgsConstructor
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
@JsonNaming(PropertyNamingStrategy.UpperCamelCaseStrategy.class)
|
||||
public class DeviceContext implements Serializable {
|
||||
|
@ -48,5 +53,28 @@ public class DeviceContext implements Serializable {
|
|||
@JsonProperty("IPState")
|
||||
private String ipState;
|
||||
private String purchaseId;
|
||||
@JsonDeserialize(using = FlexibleDateFormatDeserializer.class)
|
||||
@JsonSerialize(using = ISOStringDateTimeSerializer.class)
|
||||
private OffsetDateTime merchantLocalDate;
|
||||
|
||||
private Map<String, String> additionalParams = new HashMap<>();
|
||||
|
||||
@JsonAnySetter
|
||||
public void setAdditionalParam(String name, String value) {
|
||||
additionalParams.put(name, value);
|
||||
}
|
||||
public void setAdditionalParams(Map<String, String> map) {
|
||||
additionalParams.putAll(map);
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for advanced serialization.
|
||||
* Json object will contain both representation of DateTime field -
|
||||
* timestamp (for SQL queries) and string representation.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
@JsonSerialize(using = EpochSecondsDateTimeSerializer.class)
|
||||
public OffsetDateTime getMerchantLocalDateEpochSeconds() {
|
||||
return merchantLocalDate;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,9 @@ package com.griddynamics.msd365fp.manualreview.model.dfp;
|
|||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonNaming;
|
||||
import lombok.*;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
@ -14,18 +16,11 @@ import java.util.Map;
|
|||
@Data
|
||||
@ToString(callSuper = true)
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Builder
|
||||
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
@NoArgsConstructor
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
@JsonNaming(PropertyNamingStrategy.UpperCamelCaseStrategy.class)
|
||||
public class MainPurchase extends Purchase {
|
||||
private User user;
|
||||
private DeviceContext deviceContext;
|
||||
private List<Address> addressList;
|
||||
private List<PaymentInstrument> paymentInstrumentList;
|
||||
private List<Product> productList;
|
||||
private List<BankEvent> bankEventsList;
|
||||
private Map<String, String> customData;
|
||||
private Map<String, Map<String, Object>> additionalInfo;
|
||||
private List<PreviousPurchase> previousPurchaseList;
|
||||
|
|
|
@ -3,20 +3,25 @@
|
|||
|
||||
package com.griddynamics.msd365fp.manualreview.model.dfp;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonAnySetter;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonNaming;
|
||||
import lombok.*;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.griddynamics.msd365fp.manualreview.model.jackson.EpochSecondsDateTimeSerializer;
|
||||
import com.griddynamics.msd365fp.manualreview.model.jackson.FlexibleDateFormatDeserializer;
|
||||
import com.griddynamics.msd365fp.manualreview.model.jackson.ISOStringDateTimeSerializer;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
@NoArgsConstructor
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
@JsonNaming(PropertyNamingStrategy.UpperCamelCaseStrategy.class)
|
||||
public class PaymentInstrument implements Serializable {
|
||||
|
@ -25,7 +30,11 @@ public class PaymentInstrument implements Serializable {
|
|||
private BigDecimal purchaseAmountInUSD;
|
||||
private String merchantPaymentInstrumentId;
|
||||
private String type;
|
||||
@JsonDeserialize(using = FlexibleDateFormatDeserializer.class)
|
||||
@JsonSerialize(using = ISOStringDateTimeSerializer.class)
|
||||
private OffsetDateTime creationDate;
|
||||
@JsonDeserialize(using = FlexibleDateFormatDeserializer.class)
|
||||
@JsonSerialize(using = ISOStringDateTimeSerializer.class)
|
||||
private OffsetDateTime updateDate;
|
||||
private String state;
|
||||
private String cardType;
|
||||
|
@ -42,5 +51,50 @@ public class PaymentInstrument implements Serializable {
|
|||
@JsonProperty("IMEI")
|
||||
private String imei;
|
||||
private String addressId;
|
||||
@JsonDeserialize(using = FlexibleDateFormatDeserializer.class)
|
||||
@JsonSerialize(using = ISOStringDateTimeSerializer.class)
|
||||
private OffsetDateTime merchantLocalDate;
|
||||
|
||||
private Map<String, String> additionalParams = new HashMap<>();
|
||||
|
||||
@JsonAnySetter
|
||||
public void setAdditionalParam(String name, String value) {
|
||||
additionalParams.put(name, value);
|
||||
}
|
||||
public void setAdditionalParams(Map<String, String> map) {
|
||||
additionalParams.putAll(map);
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for advanced serialization.
|
||||
* Json object will contain both representation of DateTime field -
|
||||
* timestamp (for SQL queries) and string representation.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
@JsonSerialize(using = EpochSecondsDateTimeSerializer.class)
|
||||
public OffsetDateTime getCreationDateEpochSeconds() {
|
||||
return creationDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for advanced serialization.
|
||||
* Json object will contain both representation of DateTime field -
|
||||
* timestamp (for SQL queries) and string representation.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
@JsonSerialize(using = EpochSecondsDateTimeSerializer.class)
|
||||
public OffsetDateTime getUpdateDateEpochSeconds() {
|
||||
return updateDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for advanced serialization.
|
||||
* Json object will contain both representation of DateTime field -
|
||||
* timestamp (for SQL queries) and string representation.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
@JsonSerialize(using = EpochSecondsDateTimeSerializer.class)
|
||||
public OffsetDateTime getMerchantLocalDateEpochSeconds() {
|
||||
return merchantLocalDate;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,26 +5,60 @@ package com.griddynamics.msd365fp.manualreview.model.dfp;
|
|||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonNaming;
|
||||
import lombok.*;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.griddynamics.msd365fp.manualreview.model.jackson.EpochSecondsDateTimeSerializer;
|
||||
import com.griddynamics.msd365fp.manualreview.model.jackson.FlexibleDateFormatDeserializer;
|
||||
import com.griddynamics.msd365fp.manualreview.model.jackson.ISOStringDateTimeSerializer;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
import java.util.List;
|
||||
import java.time.OffsetDateTime;
|
||||
|
||||
@Data
|
||||
@ToString(callSuper = true)
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Builder
|
||||
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
@NoArgsConstructor
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
@JsonNaming(PropertyNamingStrategy.UpperCamelCaseStrategy.class)
|
||||
public class PreviousPurchase extends Purchase {
|
||||
private Integer riskScore;
|
||||
private String reasonCodes;
|
||||
private String policyApplied;
|
||||
|
||||
private String lastMerchantStatus;
|
||||
private DeviceContext deviceContext;
|
||||
private List<Address> addressList;
|
||||
private List<PaymentInstrument> paymentInstrumentList;
|
||||
private List<BankEvent> bankEventsList;
|
||||
private String lastMerchantStatusReason;
|
||||
@JsonDeserialize(using = FlexibleDateFormatDeserializer.class)
|
||||
@JsonSerialize(using = ISOStringDateTimeSerializer.class)
|
||||
private OffsetDateTime lastMerchantStatusDate;
|
||||
private String lastBankEventStatus;
|
||||
private String lastBankEventResponseCode;
|
||||
@JsonDeserialize(using = FlexibleDateFormatDeserializer.class)
|
||||
@JsonSerialize(using = ISOStringDateTimeSerializer.class)
|
||||
private OffsetDateTime lastBankEventDate;
|
||||
|
||||
|
||||
/**
|
||||
* Getter for advanced serialization.
|
||||
* Json object will contain both representation of DateTime field -
|
||||
* timestamp (for SQL queries) and string representation.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
@JsonSerialize(using = EpochSecondsDateTimeSerializer.class)
|
||||
public OffsetDateTime getLastMerchantStatusDateEpochSeconds() {
|
||||
return lastMerchantStatusDate;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Getter for advanced serialization.
|
||||
* Json object will contain both representation of DateTime field -
|
||||
* timestamp (for SQL queries) and string representation.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
@JsonSerialize(using = EpochSecondsDateTimeSerializer.class)
|
||||
public OffsetDateTime getLastBankEventDateEpochSeconds() {
|
||||
return lastBankEventDate;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,19 +3,19 @@
|
|||
|
||||
package com.griddynamics.msd365fp.manualreview.model.dfp;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonAnySetter;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonNaming;
|
||||
import lombok.*;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
@NoArgsConstructor
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
@JsonNaming(PropertyNamingStrategy.UpperCamelCaseStrategy.class)
|
||||
public class Product implements Serializable {
|
||||
|
@ -43,4 +43,14 @@ public class Product implements Serializable {
|
|||
private BigDecimal quantity;
|
||||
private Boolean isPreorder;
|
||||
private String shippingMethod;
|
||||
|
||||
private Map<String, String> additionalParams = new HashMap<>();
|
||||
|
||||
@JsonAnySetter
|
||||
public void setAdditionalParam(String name, String value) {
|
||||
additionalParams.put(name, value);
|
||||
}
|
||||
public void setAdditionalParams(Map<String, String> map) {
|
||||
additionalParams.putAll(map);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,14 +3,23 @@
|
|||
|
||||
package com.griddynamics.msd365fp.manualreview.model.dfp;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonAnySetter;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonNaming;
|
||||
import lombok.*;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.griddynamics.msd365fp.manualreview.model.jackson.EpochSecondsDateTimeSerializer;
|
||||
import com.griddynamics.msd365fp.manualreview.model.jackson.FlexibleDateFormatDeserializer;
|
||||
import com.griddynamics.msd365fp.manualreview.model.jackson.ISOStringDateTimeSerializer;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Data
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
|
@ -19,7 +28,11 @@ public abstract class Purchase implements Serializable {
|
|||
private String purchaseId;
|
||||
private String assessmentType;
|
||||
private String originalOrderId;
|
||||
@JsonDeserialize(using = FlexibleDateFormatDeserializer.class)
|
||||
@JsonSerialize(using = ISOStringDateTimeSerializer.class)
|
||||
private OffsetDateTime customerLocalDate;
|
||||
@JsonDeserialize(using = FlexibleDateFormatDeserializer.class)
|
||||
@JsonSerialize(using = ISOStringDateTimeSerializer.class)
|
||||
private OffsetDateTime merchantLocalDate;
|
||||
private BigDecimal totalAmount;
|
||||
private BigDecimal totalAmountInUSD;
|
||||
|
@ -30,4 +43,42 @@ public abstract class Purchase implements Serializable {
|
|||
private String shippingMethod;
|
||||
private String bankName;
|
||||
private String hashedEvaluationId;
|
||||
|
||||
private DeviceContext deviceContext;
|
||||
private List<Address> addressList;
|
||||
private List<PaymentInstrument> paymentInstrumentList;
|
||||
private List<BankEvent> bankEventsList;
|
||||
|
||||
private Map<String, String> additionalParams = new HashMap<>();
|
||||
|
||||
@JsonAnySetter
|
||||
public void setAdditionalParam(String name, String value) {
|
||||
additionalParams.put(name, value);
|
||||
}
|
||||
public void setAdditionalParams(Map<String, String> map) {
|
||||
additionalParams.putAll(map);
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for advanced serialization.
|
||||
* Json object will contain both representation of DateTime field -
|
||||
* timestamp (for SQL queries) and string representation.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
@JsonSerialize(using = EpochSecondsDateTimeSerializer.class)
|
||||
public OffsetDateTime getCustomerLocalDateEpochSeconds() {
|
||||
return customerLocalDate;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Getter for advanced serialization.
|
||||
* Json object will contain both representation of DateTime field -
|
||||
* timestamp (for SQL queries) and string representation.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
@JsonSerialize(using = EpochSecondsDateTimeSerializer.class)
|
||||
public OffsetDateTime getMerchantLocalDateEpochSeconds() {
|
||||
return merchantLocalDate;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,22 +3,52 @@
|
|||
|
||||
package com.griddynamics.msd365fp.manualreview.model.dfp;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonAnySetter;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonNaming;
|
||||
import lombok.*;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.griddynamics.msd365fp.manualreview.model.jackson.EpochSecondsDateTimeSerializer;
|
||||
import com.griddynamics.msd365fp.manualreview.model.jackson.FlexibleDateFormatDeserializer;
|
||||
import com.griddynamics.msd365fp.manualreview.model.jackson.ISOStringDateTimeSerializer;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
@NoArgsConstructor
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
@JsonNaming(PropertyNamingStrategy.UpperCamelCaseStrategy.class)
|
||||
public class PurchaseStatus implements Serializable {
|
||||
private String purchaseId;
|
||||
private String statusType;
|
||||
private String statusDate;
|
||||
@JsonDeserialize(using = FlexibleDateFormatDeserializer.class)
|
||||
@JsonSerialize(using = ISOStringDateTimeSerializer.class)
|
||||
private OffsetDateTime statusDate;
|
||||
private String reason;
|
||||
|
||||
private Map<String, String> additionalParams = new HashMap<>();
|
||||
|
||||
@JsonAnySetter
|
||||
public void setAdditionalParam(String name, String value) {
|
||||
additionalParams.put(name, value);
|
||||
}
|
||||
public void setAdditionalParams(Map<String, String> map) {
|
||||
additionalParams.putAll(map);
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for advanced serialization.
|
||||
* Json object will contain both representation of DateTime field -
|
||||
* timestamp (for SQL queries) and string representation.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
@JsonSerialize(using = EpochSecondsDateTimeSerializer.class)
|
||||
public OffsetDateTime getStatusDateEpochSeconds() {
|
||||
return statusDate;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -3,24 +3,33 @@
|
|||
|
||||
package com.griddynamics.msd365fp.manualreview.model.dfp;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonAnySetter;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonNaming;
|
||||
import lombok.*;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.griddynamics.msd365fp.manualreview.model.jackson.EpochSecondsDateTimeSerializer;
|
||||
import com.griddynamics.msd365fp.manualreview.model.jackson.FlexibleDateFormatDeserializer;
|
||||
import com.griddynamics.msd365fp.manualreview.model.jackson.ISOStringDateTimeSerializer;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
@NoArgsConstructor
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
@JsonNaming(PropertyNamingStrategy.UpperCamelCaseStrategy.class)
|
||||
public class User implements Serializable {
|
||||
private String userId;
|
||||
@JsonDeserialize(using = FlexibleDateFormatDeserializer.class)
|
||||
@JsonSerialize(using = ISOStringDateTimeSerializer.class)
|
||||
private OffsetDateTime creationDate;
|
||||
@JsonDeserialize(using = FlexibleDateFormatDeserializer.class)
|
||||
@JsonSerialize(using = ISOStringDateTimeSerializer.class)
|
||||
private OffsetDateTime updateDate;
|
||||
private String firstName;
|
||||
private String lastName;
|
||||
|
@ -36,8 +45,12 @@ public class User implements Serializable {
|
|||
private String authenticationProvider;
|
||||
private String displayName;
|
||||
private Boolean isEmailValidated;
|
||||
@JsonDeserialize(using = FlexibleDateFormatDeserializer.class)
|
||||
@JsonSerialize(using = ISOStringDateTimeSerializer.class)
|
||||
private OffsetDateTime emailValidatedDate;
|
||||
private Boolean isPhoneNumberValidated;
|
||||
@JsonDeserialize(using = FlexibleDateFormatDeserializer.class)
|
||||
@JsonSerialize(using = ISOStringDateTimeSerializer.class)
|
||||
private OffsetDateTime phoneNumberValidatedDate;
|
||||
private BigDecimal totalSpend;
|
||||
private BigDecimal totalTransactions;
|
||||
|
@ -53,6 +66,87 @@ public class User implements Serializable {
|
|||
private BigDecimal monthlyAverageTransactions;
|
||||
private BigDecimal monthlyAverageRefundAmount;
|
||||
private BigDecimal monthlyAverageChargebackAmount;
|
||||
@JsonDeserialize(using = FlexibleDateFormatDeserializer.class)
|
||||
@JsonSerialize(using = ISOStringDateTimeSerializer.class)
|
||||
private OffsetDateTime measuresIngestionDateTimeUTC;
|
||||
@JsonDeserialize(using = FlexibleDateFormatDeserializer.class)
|
||||
@JsonSerialize(using = ISOStringDateTimeSerializer.class)
|
||||
private OffsetDateTime merchantLocalDate;
|
||||
|
||||
private Map<String, String> additionalParams = new HashMap<>();
|
||||
|
||||
@JsonAnySetter
|
||||
public void setAdditionalParam(String name, String value) {
|
||||
additionalParams.put(name, value);
|
||||
}
|
||||
public void setAdditionalParams(Map<String, String> map) {
|
||||
additionalParams.putAll(map);
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for advanced serialization.
|
||||
* Json object will contain both representation of DateTime field -
|
||||
* timestamp (for SQL queries) and string representation.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
@JsonSerialize(using = EpochSecondsDateTimeSerializer.class)
|
||||
public OffsetDateTime getCreationDateEpochSeconds() {
|
||||
return creationDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for advanced serialization.
|
||||
* Json object will contain both representation of DateTime field -
|
||||
* timestamp (for SQL queries) and string representation.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
@JsonSerialize(using = EpochSecondsDateTimeSerializer.class)
|
||||
public OffsetDateTime getUpdateDateEpochSeconds() {
|
||||
return updateDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for advanced serialization.
|
||||
* Json object will contain both representation of DateTime field -
|
||||
* timestamp (for SQL queries) and string representation.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
@JsonSerialize(using = EpochSecondsDateTimeSerializer.class)
|
||||
public OffsetDateTime getMerchantLocalDateEpochSeconds() {
|
||||
return merchantLocalDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for advanced serialization.
|
||||
* Json object will contain both representation of DateTime field -
|
||||
* timestamp (for SQL queries) and string representation.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
@JsonSerialize(using = EpochSecondsDateTimeSerializer.class)
|
||||
public OffsetDateTime getEmailValidatedDateEpochSeconds() {
|
||||
return emailValidatedDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for advanced serialization.
|
||||
* Json object will contain both representation of DateTime field -
|
||||
* timestamp (for SQL queries) and string representation.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
@JsonSerialize(using = EpochSecondsDateTimeSerializer.class)
|
||||
public OffsetDateTime getPhoneNumberValidatedDateEpochSeconds() {
|
||||
return phoneNumberValidatedDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for advanced serialization.
|
||||
* Json object will contain both representation of DateTime field -
|
||||
* timestamp (for SQL queries) and string representation.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
@JsonSerialize(using = EpochSecondsDateTimeSerializer.class)
|
||||
public OffsetDateTime getMeasuresIngestionDateTimeUTCEpochSeconds() {
|
||||
return measuresIngestionDateTimeUTC;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
package com.griddynamics.msd365fp.manualreview.model.dfp;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
public class Velocity<T extends Serializable> implements Serializable {
|
||||
private T hour;
|
||||
private T day;
|
||||
private T week;
|
||||
}
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
package com.griddynamics.msd365fp.manualreview.model.dfp.raw;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonNaming;
|
||||
import lombok.Data;
|
||||
|
@ -19,6 +20,8 @@ import lombok.ToString;
|
|||
@EqualsAndHashCode(callSuper = true)
|
||||
@JsonNaming(PropertyNamingStrategy.UpperCamelCaseStrategy.class)
|
||||
public class AddressNodeData extends NodeData {
|
||||
public static final String NODE_NAME = "Address";
|
||||
|
||||
private String addressId;
|
||||
private String street1;
|
||||
private String street2;
|
||||
|
@ -26,6 +29,7 @@ public class AddressNodeData extends NodeData {
|
|||
private String city;
|
||||
private String state;
|
||||
private String zipCode;
|
||||
private String countryRegion;
|
||||
@JsonProperty("CountryRegion")
|
||||
private String country;
|
||||
|
||||
}
|
||||
|
|
|
@ -5,11 +5,15 @@ package com.griddynamics.msd365fp.manualreview.model.dfp.raw;
|
|||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonNaming;
|
||||
import com.griddynamics.msd365fp.manualreview.model.jackson.FlexibleDateFormatDeserializer;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
import java.time.OffsetDateTime;
|
||||
|
||||
/**
|
||||
* Implementation of {@link NodeData}
|
||||
*
|
||||
|
@ -20,9 +24,12 @@ import lombok.ToString;
|
|||
@EqualsAndHashCode(callSuper = true)
|
||||
@JsonNaming(PropertyNamingStrategy.UpperCamelCaseStrategy.class)
|
||||
public class BankEventNodeData extends NodeData {
|
||||
public static final String NODE_NAME = "BankEvent";
|
||||
|
||||
private String bankEventId;
|
||||
private String type;
|
||||
private String bankEventTimestamp;
|
||||
@JsonDeserialize(using = FlexibleDateFormatDeserializer.class)
|
||||
private OffsetDateTime bankEventTimestamp;
|
||||
private String status;
|
||||
private String bankResponseCode;
|
||||
private String paymentProcessor;
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
package com.griddynamics.msd365fp.manualreview.model.dfp.raw;
|
||||
|
||||
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonNaming;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
/**
|
||||
* Implementation of {@link EdgeData}
|
||||
*
|
||||
* @see EdgeData
|
||||
*/
|
||||
@Data
|
||||
@ToString(callSuper = true)
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@JsonNaming(PropertyNamingStrategy.UpperCamelCaseStrategy.class)
|
||||
public class DefaultEdgeData extends EdgeData {
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
package com.griddynamics.msd365fp.manualreview.model.dfp.raw;
|
||||
|
||||
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonNaming;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
/**
|
||||
* Implementation of {@link NodeData}
|
||||
*
|
||||
* @see NodeData
|
||||
*/
|
||||
@Data
|
||||
@ToString(callSuper = true)
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@JsonNaming(PropertyNamingStrategy.UpperCamelCaseStrategy.class)
|
||||
public class DefaultNodeData extends NodeData {
|
||||
}
|
|
@ -20,6 +20,8 @@ import lombok.ToString;
|
|||
@EqualsAndHashCode(callSuper = true)
|
||||
@JsonNaming(PropertyNamingStrategy.UpperCamelCaseStrategy.class)
|
||||
public class DeviceContextNodeData extends NodeData {
|
||||
public static final String NODE_NAME = "DeviceContext";
|
||||
|
||||
private String deviceContextId;
|
||||
private String provider;
|
||||
private String deviceContextDC;
|
||||
|
|
|
@ -22,18 +22,29 @@ public class Edge {
|
|||
private Object edgeIdAttributeList;
|
||||
private String id;
|
||||
private String name;
|
||||
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXTERNAL_PROPERTY, property = "name", visible = true)
|
||||
@JsonTypeInfo(
|
||||
use = JsonTypeInfo.Id.NAME,
|
||||
include = JsonTypeInfo.As.EXTERNAL_PROPERTY,
|
||||
property = "name",
|
||||
visible = true,
|
||||
defaultImpl = DefaultEdgeData.class)
|
||||
@JsonSubTypes({
|
||||
@JsonSubTypes.Type(value = PaymentInstrumentAddressEdgeData.class, name = "PaymentInstrumentAddress"),
|
||||
@JsonSubTypes.Type(value = PurchaseAddressEdgeData.class, name = "PurchaseAddress"),
|
||||
@JsonSubTypes.Type(value = PurchaseBankEventEdgeData.class, name = "PurchaseBankEvent"),
|
||||
@JsonSubTypes.Type(value = PurchaseDeviceContextEdgeData.class, name = "PurchaseDeviceContext"),
|
||||
@JsonSubTypes.Type(value = PurchasePaymentInstrumentEdgeData.class, name = "PurchasePaymentInstrument"),
|
||||
@JsonSubTypes.Type(value = PurchasePaymentInstrumentEdgeData.class, name = "PaymentInstrumentPurchase"),
|
||||
@JsonSubTypes.Type(value = PurchaseProductEdgeData.class, name = "PurchaseProduct"),
|
||||
@JsonSubTypes.Type(value = PurchaseStatusEdgeData.class, name = "PurchaseStatus"),
|
||||
@JsonSubTypes.Type(value = PurchaseUserEdgeData.class, name = "PurchaseUser"),
|
||||
@JsonSubTypes.Type(value = PurchaseUserEdgeData.class, name = "UserPurchase")
|
||||
@JsonSubTypes.Type(value = PaymentInstrumentAddressEdgeData.class, name = PaymentInstrumentAddressEdgeData.EDGE_DIRECT_NAME),
|
||||
@JsonSubTypes.Type(value = PaymentInstrumentAddressEdgeData.class, name = PaymentInstrumentAddressEdgeData.EDGE_REVERSED_NAME),
|
||||
@JsonSubTypes.Type(value = PurchaseAddressEdgeData.class, name = PurchaseAddressEdgeData.EDGE_DIRECT_NAME),
|
||||
@JsonSubTypes.Type(value = PurchaseAddressEdgeData.class, name = PurchaseAddressEdgeData.EDGE_REVERSED_NAME),
|
||||
@JsonSubTypes.Type(value = PurchaseBankEventEdgeData.class, name = PurchaseBankEventEdgeData.EDGE_DIRECT_NAME),
|
||||
@JsonSubTypes.Type(value = PurchaseBankEventEdgeData.class, name = PurchaseBankEventEdgeData.EDGE_REVERSED_NAME),
|
||||
@JsonSubTypes.Type(value = PurchaseDeviceContextEdgeData.class, name = PurchaseDeviceContextEdgeData.EDGE_DIRECT_NAME),
|
||||
@JsonSubTypes.Type(value = PurchaseDeviceContextEdgeData.class, name = PurchaseDeviceContextEdgeData.EDGE_REVERSED_NAME),
|
||||
@JsonSubTypes.Type(value = PurchasePaymentInstrumentEdgeData.class, name = PurchasePaymentInstrumentEdgeData.EDGE_DIRECT_NAME),
|
||||
@JsonSubTypes.Type(value = PurchasePaymentInstrumentEdgeData.class, name = PurchasePaymentInstrumentEdgeData.EDGE_REVERSED_NAME),
|
||||
@JsonSubTypes.Type(value = PurchaseProductEdgeData.class, name = PurchaseProductEdgeData.EDGE_DIRECT_NAME),
|
||||
@JsonSubTypes.Type(value = PurchaseProductEdgeData.class, name = PurchaseProductEdgeData.EDGE_REVERSED_NAME),
|
||||
@JsonSubTypes.Type(value = PurchaseStatusEdgeData.class, name = PurchaseStatusEdgeData.EDGE_DIRECT_NAME),
|
||||
@JsonSubTypes.Type(value = PurchaseStatusEdgeData.class, name = PurchaseStatusEdgeData.EDGE_REVERSED_NAME),
|
||||
@JsonSubTypes.Type(value = PurchaseUserEdgeData.class, name = PurchaseUserEdgeData.EDGE_DIRECT_NAME),
|
||||
@JsonSubTypes.Type(value = PurchaseUserEdgeData.class, name = PurchaseUserEdgeData.EDGE_REVERSED_NAME)
|
||||
})
|
||||
private EdgeData data;
|
||||
}
|
||||
|
|
|
@ -3,13 +3,12 @@
|
|||
|
||||
package com.griddynamics.msd365fp.manualreview.model.dfp.raw;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import org.springframework.lang.NonNull;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* The info returned by the {@code azure.dfp.graph-explorer-url} DFP endpoint.
|
||||
|
@ -19,18 +18,22 @@ import java.util.Objects;
|
|||
* @see Edge
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class ExplorerEntity {
|
||||
public static final ExplorerEntity EMPTY = new ExplorerEntity(
|
||||
null,
|
||||
null,
|
||||
List.of(),
|
||||
List.of());
|
||||
|
||||
private String requestAttributeName;
|
||||
private String requestAttributeValue;
|
||||
|
||||
private List<Node> nodes = null;
|
||||
private List<Edge> edges = null;
|
||||
|
||||
public void extend(@NonNull ExplorerEntity entity) {
|
||||
if (!CollectionUtils.isEmpty(entity.getNodes())) {
|
||||
this.nodes = Objects.requireNonNullElseGet(this.nodes, LinkedList::new);
|
||||
this.nodes.addAll(entity.getNodes());
|
||||
}
|
||||
if (!CollectionUtils.isEmpty(entity.getEdges())) {
|
||||
this.edges = Objects.requireNonNullElseGet(this.edges, LinkedList::new);
|
||||
this.edges.addAll(entity.getEdges());
|
||||
}
|
||||
public boolean isEmpty() {
|
||||
return CollectionUtils.isEmpty(nodes) && CollectionUtils.isEmpty(edges);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,15 +18,20 @@ public class Node {
|
|||
private String nodeIdAttribute;
|
||||
private String id;
|
||||
private String name;
|
||||
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXTERNAL_PROPERTY, property = "name", visible = true)
|
||||
@JsonTypeInfo(
|
||||
use = JsonTypeInfo.Id.NAME,
|
||||
include = JsonTypeInfo.As.EXTERNAL_PROPERTY,
|
||||
property = "name",
|
||||
visible = true,
|
||||
defaultImpl = DefaultNodeData.class)
|
||||
@JsonSubTypes({
|
||||
@JsonSubTypes.Type(value = AddressNodeData.class, name = "Address"),
|
||||
@JsonSubTypes.Type(value = BankEventNodeData.class, name = "BankEvent"),
|
||||
@JsonSubTypes.Type(value = DeviceContextNodeData.class, name = "DeviceContext"),
|
||||
@JsonSubTypes.Type(value = PaymentInstrumentNodeData.class, name = "PaymentInstrument"),
|
||||
@JsonSubTypes.Type(value = ProductNodeData.class, name = "Product"),
|
||||
@JsonSubTypes.Type(value = UserNodeData.class, name = "User"),
|
||||
@JsonSubTypes.Type(value = PurchaseNodeData.class, name = "Purchase")
|
||||
@JsonSubTypes.Type(value = AddressNodeData.class, name = AddressNodeData.NODE_NAME),
|
||||
@JsonSubTypes.Type(value = BankEventNodeData.class, name = BankEventNodeData.NODE_NAME),
|
||||
@JsonSubTypes.Type(value = DeviceContextNodeData.class, name = DeviceContextNodeData.NODE_NAME),
|
||||
@JsonSubTypes.Type(value = PaymentInstrumentNodeData.class, name = PaymentInstrumentNodeData.NODE_NAME),
|
||||
@JsonSubTypes.Type(value = ProductNodeData.class, name = ProductNodeData.NODE_NAME),
|
||||
@JsonSubTypes.Type(value = UserNodeData.class, name = UserNodeData.NODE_NAME),
|
||||
@JsonSubTypes.Type(value = PurchaseNodeData.class, name = PurchaseNodeData.NODE_NAME)
|
||||
})
|
||||
private NodeData data;
|
||||
}
|
||||
|
|
|
@ -19,6 +19,9 @@ import lombok.ToString;
|
|||
@EqualsAndHashCode(callSuper = true)
|
||||
@JsonNaming(PropertyNamingStrategy.UpperCamelCaseStrategy.class)
|
||||
public class PaymentInstrumentAddressEdgeData extends EdgeData {
|
||||
public static final String EDGE_DIRECT_NAME = "PaymentInstrumentAddress";
|
||||
public static final String EDGE_REVERSED_NAME = "AddressPaymentInstrument";
|
||||
|
||||
private String paymentInstrumentId;
|
||||
private String addressId;
|
||||
private String type;
|
||||
|
|
|
@ -5,11 +5,15 @@ package com.griddynamics.msd365fp.manualreview.model.dfp.raw;
|
|||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonNaming;
|
||||
import com.griddynamics.msd365fp.manualreview.model.jackson.FlexibleDateFormatDeserializer;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
import java.time.OffsetDateTime;
|
||||
|
||||
/**
|
||||
* Implementation of {@link NodeData}
|
||||
*
|
||||
|
@ -20,11 +24,15 @@ import lombok.ToString;
|
|||
@EqualsAndHashCode(callSuper = true)
|
||||
@JsonNaming(PropertyNamingStrategy.UpperCamelCaseStrategy.class)
|
||||
public class PaymentInstrumentNodeData extends NodeData {
|
||||
public static final String NODE_NAME = "PaymentInstrument";
|
||||
|
||||
private String paymentInstrumentId;
|
||||
private String merchantPaymentInstrumentId;
|
||||
private String type;
|
||||
private String creationDate;
|
||||
private String updateDate;
|
||||
@JsonDeserialize(using = FlexibleDateFormatDeserializer.class)
|
||||
private OffsetDateTime creationDate;
|
||||
@JsonDeserialize(using = FlexibleDateFormatDeserializer.class)
|
||||
private OffsetDateTime updateDate;
|
||||
private String state;
|
||||
private String cardType;
|
||||
private String holderName;
|
||||
|
|
|
@ -20,6 +20,8 @@ import lombok.ToString;
|
|||
@EqualsAndHashCode(callSuper = true)
|
||||
@JsonNaming(PropertyNamingStrategy.UpperCamelCaseStrategy.class)
|
||||
public class ProductNodeData extends NodeData {
|
||||
public static final String NODE_NAME = "Product";
|
||||
|
||||
private String productId;
|
||||
private String productName;
|
||||
private String type;
|
||||
|
|
|
@ -19,6 +19,9 @@ import lombok.ToString;
|
|||
@EqualsAndHashCode(callSuper = true)
|
||||
@JsonNaming(PropertyNamingStrategy.UpperCamelCaseStrategy.class)
|
||||
public class PurchaseAddressEdgeData extends EdgeData {
|
||||
public static final String EDGE_DIRECT_NAME = "PurchaseAddress";
|
||||
public static final String EDGE_REVERSED_NAME = "AddressPurchase";
|
||||
|
||||
private String purchaseId;
|
||||
private String addressId;
|
||||
private String type;
|
||||
|
|
|
@ -19,6 +19,9 @@ import lombok.ToString;
|
|||
@EqualsAndHashCode(callSuper = true)
|
||||
@JsonNaming(PropertyNamingStrategy.UpperCamelCaseStrategy.class)
|
||||
public class PurchaseBankEventEdgeData extends EdgeData {
|
||||
public static final String EDGE_DIRECT_NAME = "PurchaseBankEvent";
|
||||
public static final String EDGE_REVERSED_NAME = "BankEventPurchase";
|
||||
|
||||
private String purchaseId;
|
||||
private String bankEventId;
|
||||
}
|
||||
|
|
|
@ -5,11 +5,15 @@ package com.griddynamics.msd365fp.manualreview.model.dfp.raw;
|
|||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonNaming;
|
||||
import com.griddynamics.msd365fp.manualreview.model.jackson.FlexibleDateFormatDeserializer;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
import java.time.OffsetDateTime;
|
||||
|
||||
/**
|
||||
* Implementation of {@link EdgeData}
|
||||
*
|
||||
|
@ -20,6 +24,9 @@ import lombok.ToString;
|
|||
@EqualsAndHashCode(callSuper = true)
|
||||
@JsonNaming(PropertyNamingStrategy.UpperCamelCaseStrategy.class)
|
||||
public class PurchaseDeviceContextEdgeData extends EdgeData {
|
||||
public static final String EDGE_DIRECT_NAME = "PurchaseDeviceContext";
|
||||
public static final String EDGE_REVERSED_NAME = "DeviceContextPurchase";
|
||||
|
||||
private String purchaseId;
|
||||
private String deviceContextId;
|
||||
@JsonProperty("IPAddress")
|
||||
|
@ -36,5 +43,6 @@ public class PurchaseDeviceContextEdgeData extends EdgeData {
|
|||
private String ipCountry;
|
||||
@JsonProperty("IPState")
|
||||
private String ipState;
|
||||
private String merchantLocalDate;
|
||||
@JsonDeserialize(using = FlexibleDateFormatDeserializer.class)
|
||||
private OffsetDateTime merchantLocalDate;
|
||||
}
|
||||
|
|
|
@ -5,12 +5,15 @@ package com.griddynamics.msd365fp.manualreview.model.dfp.raw;
|
|||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonNaming;
|
||||
import com.griddynamics.msd365fp.manualreview.model.jackson.FlexibleDateFormatDeserializer;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
|
@ -24,11 +27,15 @@ import java.util.Map;
|
|||
@EqualsAndHashCode(callSuper = true)
|
||||
@JsonNaming(PropertyNamingStrategy.UpperCamelCaseStrategy.class)
|
||||
public class PurchaseNodeData extends NodeData {
|
||||
public static final String NODE_NAME = "Purchase";
|
||||
|
||||
private String purchaseId;
|
||||
private String assessmentType;
|
||||
private String originalOrderId;
|
||||
private String merchantLocalDate;
|
||||
private String customerLocalDate;
|
||||
@JsonDeserialize(using = FlexibleDateFormatDeserializer.class)
|
||||
private OffsetDateTime merchantLocalDate;
|
||||
@JsonDeserialize(using = FlexibleDateFormatDeserializer.class)
|
||||
private OffsetDateTime customerLocalDate;
|
||||
private Double totalAmount;
|
||||
private Double totalAmountInUSD;
|
||||
private Double salesTax;
|
||||
|
|
|
@ -4,11 +4,15 @@
|
|||
package com.griddynamics.msd365fp.manualreview.model.dfp.raw;
|
||||
|
||||
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonNaming;
|
||||
import com.griddynamics.msd365fp.manualreview.model.jackson.FlexibleDateFormatDeserializer;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
import java.time.OffsetDateTime;
|
||||
|
||||
/**
|
||||
* Implementation of {@link EdgeData}
|
||||
*
|
||||
|
@ -19,8 +23,12 @@ import lombok.ToString;
|
|||
@EqualsAndHashCode(callSuper = true)
|
||||
@JsonNaming(PropertyNamingStrategy.UpperCamelCaseStrategy.class)
|
||||
public class PurchasePaymentInstrumentEdgeData extends EdgeData {
|
||||
public static final String EDGE_DIRECT_NAME = "PurchasePaymentInstrument";
|
||||
public static final String EDGE_REVERSED_NAME = "PaymentInstrumentPurchase";
|
||||
|
||||
private String purchaseId;
|
||||
private String merchantLocalDate;
|
||||
@JsonDeserialize(using = FlexibleDateFormatDeserializer.class)
|
||||
private OffsetDateTime merchantLocalDate;
|
||||
private String paymentInstrumentId;
|
||||
private Double purchaseAmount;
|
||||
private Double purchaseAmountInUSD;
|
||||
|
|
|
@ -19,6 +19,9 @@ import lombok.ToString;
|
|||
@EqualsAndHashCode(callSuper = true)
|
||||
@JsonNaming(PropertyNamingStrategy.UpperCamelCaseStrategy.class)
|
||||
public class PurchaseProductEdgeData extends EdgeData {
|
||||
public static final String EDGE_DIRECT_NAME = "PurchaseProduct";
|
||||
public static final String EDGE_REVERSED_NAME = "ProductPurchase";
|
||||
|
||||
private String purchaseId;
|
||||
private String productId;
|
||||
private Double purchasePrice;
|
||||
|
|
|
@ -4,11 +4,15 @@
|
|||
package com.griddynamics.msd365fp.manualreview.model.dfp.raw;
|
||||
|
||||
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonNaming;
|
||||
import com.griddynamics.msd365fp.manualreview.model.jackson.FlexibleDateFormatDeserializer;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
import java.time.OffsetDateTime;
|
||||
|
||||
/**
|
||||
* Implementation of {@link EdgeData}
|
||||
*
|
||||
|
@ -19,8 +23,12 @@ import lombok.ToString;
|
|||
@EqualsAndHashCode(callSuper = true)
|
||||
@JsonNaming(PropertyNamingStrategy.UpperCamelCaseStrategy.class)
|
||||
public class PurchaseStatusEdgeData extends EdgeData {
|
||||
public static final String EDGE_DIRECT_NAME = "PurchaseStatus";
|
||||
public static final String EDGE_REVERSED_NAME = "StatusPurchase";
|
||||
|
||||
private String purchaseId;
|
||||
private String statusType;
|
||||
private String statusDate;
|
||||
@JsonDeserialize(using = FlexibleDateFormatDeserializer.class)
|
||||
private OffsetDateTime statusDate;
|
||||
private String reason;
|
||||
}
|
||||
|
|
|
@ -4,11 +4,15 @@
|
|||
package com.griddynamics.msd365fp.manualreview.model.dfp.raw;
|
||||
|
||||
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonNaming;
|
||||
import com.griddynamics.msd365fp.manualreview.model.jackson.FlexibleDateFormatDeserializer;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
import java.time.OffsetDateTime;
|
||||
|
||||
/**
|
||||
* Implementation of {@link EdgeData}
|
||||
*
|
||||
|
@ -19,8 +23,12 @@ import lombok.ToString;
|
|||
@EqualsAndHashCode(callSuper = true)
|
||||
@JsonNaming(PropertyNamingStrategy.UpperCamelCaseStrategy.class)
|
||||
public class PurchaseUserEdgeData extends EdgeData {
|
||||
public static final String EDGE_DIRECT_NAME = "PurchaseUser";
|
||||
public static final String EDGE_REVERSED_NAME = "UserPurchase";
|
||||
|
||||
private String purchaseId;
|
||||
private String merchantLocalDate;
|
||||
@JsonDeserialize(using = FlexibleDateFormatDeserializer.class)
|
||||
private OffsetDateTime merchantLocalDate;
|
||||
private String userId;
|
||||
|
||||
}
|
||||
|
|
|
@ -5,11 +5,17 @@ package com.griddynamics.msd365fp.manualreview.model.dfp.raw;
|
|||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonNaming;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.griddynamics.msd365fp.manualreview.model.jackson.FlexibleDateFormatDeserializer;
|
||||
import com.griddynamics.msd365fp.manualreview.model.jackson.ISOStringDateTimeSerializer;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
import java.time.OffsetDateTime;
|
||||
|
||||
/**
|
||||
* Implementation of {@link NodeData}
|
||||
*
|
||||
|
@ -20,9 +26,13 @@ import lombok.ToString;
|
|||
@EqualsAndHashCode(callSuper = true)
|
||||
@JsonNaming(PropertyNamingStrategy.UpperCamelCaseStrategy.class)
|
||||
public class UserNodeData extends NodeData {
|
||||
public static final String NODE_NAME = "User";
|
||||
|
||||
private String userId;
|
||||
private String creationDate;
|
||||
private String updateDate;
|
||||
@JsonDeserialize(using = FlexibleDateFormatDeserializer.class)
|
||||
private OffsetDateTime creationDate;
|
||||
@JsonDeserialize(using = FlexibleDateFormatDeserializer.class)
|
||||
private OffsetDateTime updateDate;
|
||||
private String firstName;
|
||||
private String lastName;
|
||||
@JsonProperty("CountryRegion")
|
||||
|
@ -37,7 +47,11 @@ public class UserNodeData extends NodeData {
|
|||
private String displayName;
|
||||
private String authenticationProvider;
|
||||
private Boolean isEmailValidated;
|
||||
@JsonDeserialize(using = FlexibleDateFormatDeserializer.class)
|
||||
private OffsetDateTime emailValidatedDate;
|
||||
private Boolean isPhoneNumberValidated;
|
||||
@JsonDeserialize(using = FlexibleDateFormatDeserializer.class)
|
||||
private OffsetDateTime phoneNumberValidatedDate;
|
||||
private Double totalSpend;
|
||||
private Double totalTransactions;
|
||||
private Double totalRefundAmount;
|
||||
|
@ -52,7 +66,8 @@ public class UserNodeData extends NodeData {
|
|||
private Double monthlyAverageTransactions;
|
||||
private Double monthlyAverageRefundAmount;
|
||||
private Double monthlyAverageChargebackAmount;
|
||||
private String measuresIngestionDateTimeUTC;
|
||||
@JsonDeserialize(using = FlexibleDateFormatDeserializer.class)
|
||||
private OffsetDateTime measuresIngestionDateTimeUTC;
|
||||
private String membershipId;
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
package com.griddynamics.msd365fp.manualreview.model.jackson;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.databind.SerializerProvider;
|
||||
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.time.OffsetDateTime;
|
||||
|
||||
public class EpochSecondsDateTimeSerializer extends StdSerializer<OffsetDateTime> {
|
||||
|
||||
protected EpochSecondsDateTimeSerializer() {
|
||||
super(OffsetDateTime.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serialize(final OffsetDateTime value, final JsonGenerator gen, final SerializerProvider serializers) throws IOException {
|
||||
if (value != null) {
|
||||
gen.writeNumber(value.toEpochSecond());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
package com.griddynamics.msd365fp.manualreview.model.jackson;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.core.JsonTokenId;
|
||||
import com.fasterxml.jackson.databind.DeserializationContext;
|
||||
import com.fasterxml.jackson.datatype.jsr310.deser.InstantDeserializer;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.format.DateTimeParseException;
|
||||
|
||||
import static com.griddynamics.msd365fp.manualreview.model.Constants.DFP_DATE_TIME_PATTERN;
|
||||
import static com.griddynamics.msd365fp.manualreview.model.Constants.ISO_OFFSET_DATE_TIME_PATTERN;
|
||||
|
||||
public class FlexibleDateFormatDeserializer extends InstantDeserializer<OffsetDateTime> {
|
||||
|
||||
public FlexibleDateFormatDeserializer() {
|
||||
super(InstantDeserializer.OFFSET_DATE_TIME, DateTimeFormatter.ofPattern(ISO_OFFSET_DATE_TIME_PATTERN));
|
||||
}
|
||||
|
||||
@Override
|
||||
public OffsetDateTime deserialize(final JsonParser jp, final DeserializationContext ctxt) throws IOException, JsonProcessingException {
|
||||
if (jp.getCurrentTokenId() == JsonTokenId.ID_STRING) {
|
||||
try {
|
||||
return OffsetDateTime.parse(jp.getText());
|
||||
} catch (DateTimeParseException ignored) {
|
||||
// ignored
|
||||
}
|
||||
try {
|
||||
return OffsetDateTime.parse(jp.getText(), DateTimeFormatter.ofPattern(DFP_DATE_TIME_PATTERN));
|
||||
} catch (DateTimeParseException ignored) {
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
return super.deserialize(jp, ctxt);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package com.griddynamics.msd365fp.manualreview.model.jackson;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.databind.SerializerProvider;
|
||||
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
|
||||
import static com.griddynamics.msd365fp.manualreview.model.Constants.ISO_OFFSET_DATE_TIME_PATTERN;
|
||||
|
||||
public class ISOStringDateTimeSerializer extends StdSerializer<OffsetDateTime> {
|
||||
|
||||
private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern(ISO_OFFSET_DATE_TIME_PATTERN);
|
||||
|
||||
protected ISOStringDateTimeSerializer() {
|
||||
super(OffsetDateTime.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serialize(final OffsetDateTime value, final JsonGenerator gen, final SerializerProvider serializers) throws IOException {
|
||||
gen.writeString(value == null ? null : value.format(formatter));
|
||||
}
|
||||
}
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -45,6 +45,7 @@ dependencies {
|
|||
implementation 'org.springframework.boot:spring-boot-starter-actuator'
|
||||
implementation 'com.nimbusds:nimbus-jose-jwt:7.9'
|
||||
implementation 'com.google.guava:guava:25.0-jre'
|
||||
implementation 'org.gavaghan:geodesy:1.1.3'
|
||||
|
||||
// Web
|
||||
implementation 'org.modelmapper:modelmapper:2.3.7'
|
||||
|
|
|
@ -3,18 +3,33 @@
|
|||
|
||||
package com.griddynamics.msd365fp.manualreview.queues.config;
|
||||
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.griddynamics.msd365fp.manualreview.queues.config.properties.ApplicationProperties;
|
||||
import com.griddynamics.msd365fp.manualreview.queues.config.properties.CacheProperties;
|
||||
import com.griddynamics.msd365fp.manualreview.queues.config.properties.CachePropertyEntry;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.cache.annotation.EnableCaching;
|
||||
import org.springframework.cache.concurrent.ConcurrentMapCache;
|
||||
import org.springframework.cache.concurrent.ConcurrentMapCacheManager;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.util.Objects;
|
||||
|
||||
import static com.griddynamics.msd365fp.manualreview.queues.config.Constants.DEFAULT_CACHE_INVALIDATION_INTERVAL;
|
||||
import static com.griddynamics.msd365fp.manualreview.queues.config.Constants.DEFAULT_CACHE_SIZE;
|
||||
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableConfigurationProperties({ApplicationProperties.class})
|
||||
@EnableConfigurationProperties({ApplicationProperties.class, CacheProperties.class})
|
||||
@EnableCaching
|
||||
public class ApplicationConfig {
|
||||
|
||||
private final ApplicationProperties applicationProperties;
|
||||
|
@ -30,4 +45,30 @@ public class ApplicationConfig {
|
|||
threadPoolTaskExecutor.getMaxPoolSize(), threadPoolTaskExecutor.getCorePoolSize());
|
||||
return threadPoolTaskExecutor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cache manager configuration bean.
|
||||
* This implementation allows to configure
|
||||
* time-to-live for entries per each cache
|
||||
*
|
||||
* @param cacheProperties - a config bean
|
||||
* @return the new CacheManager bean is based on guava cache
|
||||
*/
|
||||
@Bean
|
||||
public CacheManager cacheManager(final CacheProperties cacheProperties) {
|
||||
return new ConcurrentMapCacheManager() {
|
||||
@Override
|
||||
@Nonnull
|
||||
protected Cache createConcurrentMapCache(@Nonnull final String name) {
|
||||
CachePropertyEntry config = Objects.requireNonNull(cacheProperties.get(name));
|
||||
CacheBuilder<Object, Object> cacheBuilder = CacheBuilder.newBuilder()
|
||||
.expireAfterWrite(Objects.requireNonNullElse(
|
||||
config.getInvalidationInterval(), DEFAULT_CACHE_INVALIDATION_INTERVAL))
|
||||
.maximumSize(Objects.requireNonNullElse(
|
||||
config.getMaxSize(), DEFAULT_CACHE_SIZE));
|
||||
return new ConcurrentMapCache(name,
|
||||
cacheBuilder.build().asMap(), false);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,8 @@ package com.griddynamics.msd365fp.manualreview.queues.config;
|
|||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
@SuppressWarnings("java:S2386")
|
||||
public class Constants {
|
||||
|
@ -13,6 +15,10 @@ public class Constants {
|
|||
public static final int TOP_ELEMENT_IN_CONTAINER_PAGE_SIZE = 1;
|
||||
public static final String TOP_ELEMENT_IN_CONTAINER_CONTINUATION = null;
|
||||
|
||||
|
||||
public static final Duration DEFAULT_CACHE_INVALIDATION_INTERVAL = Duration.ZERO;
|
||||
public static final long DEFAULT_CACHE_SIZE = 0;
|
||||
|
||||
public static final String DEFAULT_QUEUE_PAGE_SIZE_STR = "20";
|
||||
public static final int DEFAULT_QUEUE_PAGE_SIZE = 20;
|
||||
public static final String DEFAULT_QUEUE_VIEW_PARAMETER_STR = "REGULAR";
|
||||
|
@ -26,6 +32,7 @@ public class Constants {
|
|||
public static final String DICTIONARIES_CONTAINER_NAME = "Dictionaries";
|
||||
public static final String SETTINGS_CONTAINER_NAME = "ConfigurableAppSettings";
|
||||
public static final String SEARCH_QUERIES_CONTAINER_NAME = "SearchQueries";
|
||||
public static final String EMAIL_DOMAINS_CONTAINER_NAME = "EmailDomains";
|
||||
|
||||
public static final int DEFAULT_CACHE_CONTROL_SECONDS = 1800;
|
||||
|
||||
|
@ -65,8 +72,6 @@ public class Constants {
|
|||
public static final String PRIM_HEALTH_ANALYSIS_TASK_NAME = "prim-health-analysis-task";
|
||||
public static final String SEC_HEALTH_ANALYSIS_TASK_NAME = "sec-health-analysis-task";
|
||||
|
||||
public static final String DATETIME_PATTERN_DFP = "MM/dd/yyyy HH:mm:ss xxxxx";
|
||||
|
||||
public static final String SECURITY_SCHEMA_IMPLICIT = "mr_user_auth";
|
||||
public static final String CLIENT_REGISTRATION_AZURE_DFP_API = "azure-dfp-api";
|
||||
|
||||
|
|
|
@ -3,11 +3,7 @@
|
|||
|
||||
package com.griddynamics.msd365fp.manualreview.queues.config;
|
||||
|
||||
import com.griddynamics.msd365fp.manualreview.model.Decision;
|
||||
import com.griddynamics.msd365fp.manualreview.model.dfp.*;
|
||||
import com.griddynamics.msd365fp.manualreview.model.dfp.raw.*;
|
||||
import com.griddynamics.msd365fp.manualreview.queues.model.persistence.Item;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.modelmapper.Converter;
|
||||
import org.modelmapper.ModelMapper;
|
||||
import org.modelmapper.TypeMap;
|
||||
|
@ -17,14 +13,12 @@ import org.springframework.context.annotation.Configuration;
|
|||
|
||||
import java.time.OffsetDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import static com.griddynamics.msd365fp.manualreview.queues.config.Constants.DATETIME_PATTERN_DFP;
|
||||
import static com.griddynamics.msd365fp.manualreview.model.Constants.DFP_DATE_TIME_PATTERN;
|
||||
|
||||
|
||||
@Configuration
|
||||
@Slf4j
|
||||
public class DFPModelMapperConfig {
|
||||
|
||||
@Bean
|
||||
|
@ -35,153 +29,19 @@ public class DFPModelMapperConfig {
|
|||
.setCollectionsMergeEnabled(false)
|
||||
.setMatchingStrategy(MatchingStrategies.STRICT);
|
||||
addStringToDateConverter(modelMapper);
|
||||
addGeneralModelConvertor(modelMapper);
|
||||
return modelMapper;
|
||||
}
|
||||
|
||||
|
||||
@Deprecated
|
||||
private void addStringToDateConverter(ModelMapper modelMapper) {
|
||||
TypeMap<String, OffsetDateTime> typeMap = modelMapper.createTypeMap(String.class, OffsetDateTime.class);
|
||||
Converter<String, OffsetDateTime> dateConverter = ctx ->
|
||||
ctx.getSource() == null ?
|
||||
null :
|
||||
OffsetDateTime.parse(ctx.getSource(), DateTimeFormatter.ofPattern(DATETIME_PATTERN_DFP));
|
||||
Converter<String, OffsetDateTime> dateConverter = ctx ->{
|
||||
log.error("Incorrect mapper usage, parsing of datetime in mapper is deprecated in favor of Jackson conversion: {}", ctx.getSource());
|
||||
return ctx.getSource() == null ?
|
||||
null :
|
||||
OffsetDateTime.parse(ctx.getSource(), DateTimeFormatter.ofPattern(DFP_DATE_TIME_PATTERN));
|
||||
};
|
||||
typeMap.setConverter(dateConverter);
|
||||
}
|
||||
|
||||
private void addGeneralModelConvertor(ModelMapper modelMapper) {
|
||||
TypeMap<ExplorerEntity, Item> typeMap = modelMapper.createTypeMap(ExplorerEntity.class, Item.class);
|
||||
Converter<ExplorerEntity, Item> converter = ctx ->
|
||||
{
|
||||
Item item = Objects.requireNonNullElse(ctx.getDestination(), new Item());
|
||||
ExplorerEntity entity = Objects.requireNonNull(ctx.getSource());
|
||||
mapExplorerEntityToItem(modelMapper, item, entity);
|
||||
return item;
|
||||
};
|
||||
typeMap.setConverter(converter);
|
||||
}
|
||||
|
||||
private void mapExplorerEntityToItem(final ModelMapper modelMapper, final Item item, final ExplorerEntity entity) {
|
||||
DeviceContext deviceContext = new DeviceContext();
|
||||
Map<String, PaymentInstrument> paymentInstrumentMap = new HashMap<>();
|
||||
Map<String, Product> productMap = new HashMap<>();
|
||||
Map<String, BankEvent> bankEventMap = new HashMap<>();
|
||||
Map<String, Address> shippingAddressMap = new HashMap<>();
|
||||
Map<String, Address> billingAddressMap = new HashMap<>();
|
||||
Map<String, PreviousPurchase> previousPurchaseMap = new HashMap<>();
|
||||
AssesmentResult assesmentResult = new AssesmentResult();
|
||||
Map<String, PurchaseStatus> purchaseStatusMap = new HashMap<>();
|
||||
User user = new User();
|
||||
MainPurchase purchase = new MainPurchase();
|
||||
Map<String, Map<String, Object>> additionalInfo = new HashMap<>();
|
||||
|
||||
entity.getEdges().forEach(edge -> {
|
||||
switch (edge.getName()) {
|
||||
case "PurchaseAddress":
|
||||
modelMapper.map(edge.getData(), shippingAddressMap.computeIfAbsent(
|
||||
((PurchaseAddressEdgeData) edge.getData()).getAddressId(),
|
||||
key -> new Address()));
|
||||
break;
|
||||
case "PaymentInstrumentAddress":
|
||||
PaymentInstrumentAddressEdgeData edgeData =
|
||||
((PaymentInstrumentAddressEdgeData) edge.getData());
|
||||
modelMapper.map(edge.getData(), billingAddressMap.computeIfAbsent(
|
||||
edgeData.getAddressId(),
|
||||
key -> new Address()));
|
||||
paymentInstrumentMap
|
||||
.computeIfAbsent(
|
||||
edgeData.getPaymentInstrumentId(),
|
||||
key -> new PaymentInstrument())
|
||||
.setAddressId(edgeData.getAddressId());
|
||||
break;
|
||||
case "PurchaseBankEvent":
|
||||
modelMapper.map(edge.getData(), bankEventMap.computeIfAbsent(
|
||||
((PurchaseBankEventEdgeData) edge.getData()).getBankEventId(),
|
||||
key -> new BankEvent()));
|
||||
break;
|
||||
case "PurchaseDeviceContext":
|
||||
modelMapper.map(edge.getData(), deviceContext);
|
||||
break;
|
||||
case "PaymentInstrumentPurchase":
|
||||
case "PurchasePaymentInstrument":
|
||||
modelMapper.map(edge.getData(), paymentInstrumentMap.computeIfAbsent(
|
||||
((PurchasePaymentInstrumentEdgeData) edge.getData()).getPaymentInstrumentId(),
|
||||
key -> new PaymentInstrument()));
|
||||
break;
|
||||
case "PurchaseProduct":
|
||||
modelMapper.map(edge.getData(), productMap.computeIfAbsent(
|
||||
((PurchaseProductEdgeData) edge.getData()).getProductId(),
|
||||
key -> new Product()));
|
||||
break;
|
||||
case "PurchaseStatus":
|
||||
modelMapper.map(edge.getData(), purchaseStatusMap.computeIfAbsent(
|
||||
edge.getId(),
|
||||
key -> new PurchaseStatus()));
|
||||
modelMapper.map(edge.getData(), assesmentResult);
|
||||
break;
|
||||
case "PurchaseUser":
|
||||
modelMapper.map(edge.getData(), user);
|
||||
break;
|
||||
default:
|
||||
modelMapper.map(edge.getData(), additionalInfo.computeIfAbsent(
|
||||
edge.getName() + edge.getId(),
|
||||
key -> new HashMap<>()));
|
||||
}
|
||||
});
|
||||
entity.getNodes().forEach(node -> {
|
||||
switch (node.getName()) {
|
||||
case "Address":
|
||||
if (shippingAddressMap.containsKey(node.getId())) {
|
||||
modelMapper.map(node.getData(), shippingAddressMap.get(node.getId()));
|
||||
}
|
||||
if (billingAddressMap.containsKey(node.getId())) {
|
||||
modelMapper.map(node.getData(), billingAddressMap.get(node.getId()));
|
||||
}
|
||||
break;
|
||||
case "BankEvent":
|
||||
modelMapper.map(node.getData(), bankEventMap.computeIfAbsent(node.getId(), key -> new BankEvent()));
|
||||
break;
|
||||
case "DeviceContext":
|
||||
modelMapper.map(node.getData(), deviceContext);
|
||||
break;
|
||||
case "PaymentInstrument":
|
||||
modelMapper.map(node.getData(), paymentInstrumentMap.computeIfAbsent(node.getId(), key -> new PaymentInstrument()));
|
||||
break;
|
||||
case "Product":
|
||||
modelMapper.map(node.getData(), productMap.computeIfAbsent(node.getId(), key -> new Product()));
|
||||
break;
|
||||
case "Purchase":
|
||||
if (node.getId().equals(item.getId())) {
|
||||
modelMapper.map(node.getData(), purchase);
|
||||
modelMapper.map(node.getData(), assesmentResult);
|
||||
} else {
|
||||
modelMapper.map(node.getData(), previousPurchaseMap.computeIfAbsent(node.getId(), key -> new PreviousPurchase()));
|
||||
}
|
||||
break;
|
||||
case "User":
|
||||
modelMapper.map(node.getData(), user);
|
||||
break;
|
||||
default:
|
||||
modelMapper.map(node.getData(), additionalInfo.computeIfAbsent(
|
||||
node.getName() + node.getId(),
|
||||
key -> new HashMap<>()));
|
||||
}
|
||||
});
|
||||
|
||||
purchase.setPreviousPurchaseList(new ArrayList<>(previousPurchaseMap.values()));
|
||||
purchase.setAddressList(new ArrayList<>(CollectionUtils.union(shippingAddressMap.values(), billingAddressMap.values())));
|
||||
purchase.setBankEventsList(new ArrayList<>(bankEventMap.values()));
|
||||
purchase.setDeviceContext(deviceContext);
|
||||
purchase.setPaymentInstrumentList(new ArrayList<>(paymentInstrumentMap.values()));
|
||||
purchase.setProductList(new ArrayList<>(productMap.values()));
|
||||
purchase.setUser(user);
|
||||
assesmentResult.setPurchaseStatusList(new ArrayList<>(purchaseStatusMap.values()));
|
||||
// Create and save the item
|
||||
item.setPurchase(purchase);
|
||||
item.setAssessmentResult(assesmentResult);
|
||||
item.setDecision(Decision.builder()
|
||||
.riskScore(assesmentResult.getRiskScore())
|
||||
.reasonCodes(assesmentResult.getReasonCodes())
|
||||
.build());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
|
|||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.codec.ClientCodecConfigurer;
|
||||
import org.springframework.http.codec.json.Jackson2JsonDecoder;
|
||||
|
@ -45,6 +46,7 @@ public class WebClientConfig {
|
|||
}
|
||||
|
||||
@Bean
|
||||
@Primary
|
||||
WebClient azureDFPAPIWebClient(OAuth2AuthorizedClientManager authorizedClientManager, ObjectMapper mapper) {
|
||||
ServletOAuth2AuthorizedClientExchangeFilterFunction oauth2Client =
|
||||
new ServletOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager);
|
||||
|
@ -63,6 +65,12 @@ public class WebClientConfig {
|
|||
.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
WebClient nonAuthorizingWebClient() {
|
||||
return WebClient.builder()
|
||||
.build();
|
||||
}
|
||||
|
||||
private static ExchangeFilterFunction logRequestFilter() {
|
||||
return ExchangeFilterFunction.ofRequestProcessor(clientRequest -> {
|
||||
log.info("Calling Azure DFP API via Web Client: {} {}", clientRequest.method(), clientRequest.url());
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
package com.griddynamics.msd365fp.manualreview.queues.config.properties;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.boot.context.properties.ConstructorBinding;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
@ConstructorBinding
|
||||
@ConfigurationProperties("mr.cache")
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public class CacheProperties extends HashMap<String, CachePropertyEntry> {
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
package com.griddynamics.msd365fp.manualreview.queues.config.properties;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import org.springframework.boot.context.properties.ConstructorBinding;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
@ConstructorBinding
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public class CachePropertyEntry {
|
||||
private final Duration invalidationInterval;
|
||||
private final Long maxSize;
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
package com.griddynamics.msd365fp.manualreview.queues.controller;
|
||||
|
||||
|
||||
import com.griddynamics.msd365fp.manualreview.model.exception.IncorrectConfigurationException;
|
||||
import com.griddynamics.msd365fp.manualreview.queues.model.dto.MapTokenDTO;
|
||||
import com.griddynamics.msd365fp.manualreview.queues.service.MapService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.security.access.annotation.Secured;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import static com.griddynamics.msd365fp.manualreview.queues.config.Constants.*;
|
||||
|
||||
@Tag(name = "maps", description = "The Maps API")
|
||||
@SecurityRequirement(name = SECURITY_SCHEMA_IMPLICIT)
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/api/maps")
|
||||
@Secured({ADMIN_MANAGER_ROLE})
|
||||
public class MapController {
|
||||
|
||||
private final MapService mapService;
|
||||
|
||||
@Operation(summary = "Get token for read-only map access")
|
||||
@GetMapping(value = "/token/read", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Secured({ADMIN_MANAGER_ROLE, SENIOR_ANALYST_ROLE, ANALYST_ROLE})
|
||||
public MapTokenDTO getReadToken() throws IncorrectConfigurationException {
|
||||
return mapService.getReadToken();
|
||||
}
|
||||
|
||||
}
|
|
@ -20,18 +20,21 @@ import com.griddynamics.msd365fp.manualreview.cosmos.utilities.PageProcessingUti
|
|||
import com.griddynamics.msd365fp.manualreview.dfpauth.util.UserPrincipalUtility;
|
||||
import com.griddynamics.msd365fp.manualreview.ehub.durable.config.properties.EventHubProperties;
|
||||
import com.griddynamics.msd365fp.manualreview.ehub.durable.model.DurableEventHubProducerClientRegistry;
|
||||
import com.griddynamics.msd365fp.manualreview.model.DisposabilityCheck;
|
||||
import com.griddynamics.msd365fp.manualreview.model.ItemLabel;
|
||||
import com.griddynamics.msd365fp.manualreview.model.ItemLock;
|
||||
import com.griddynamics.msd365fp.manualreview.model.PageableCollection;
|
||||
import com.griddynamics.msd365fp.manualreview.model.event.Event;
|
||||
import com.griddynamics.msd365fp.manualreview.model.exception.BusyException;
|
||||
import com.griddynamics.msd365fp.manualreview.model.exception.IncorrectConditionException;
|
||||
import com.griddynamics.msd365fp.manualreview.model.exception.NotFoundException;
|
||||
import com.griddynamics.msd365fp.manualreview.queues.model.ItemDataField;
|
||||
import com.griddynamics.msd365fp.manualreview.queues.model.ItemFilterField;
|
||||
import com.griddynamics.msd365fp.manualreview.queues.model.QueueViewType;
|
||||
import com.griddynamics.msd365fp.manualreview.queues.model.persistence.Item;
|
||||
import com.griddynamics.msd365fp.manualreview.queues.model.testing.MicrosoftDynamicsFraudProtectionV1ModelsBankEventActivityBankEvent;
|
||||
import com.griddynamics.msd365fp.manualreview.queues.model.testing.MicrosoftDynamicsFraudProtectionV1ModelsPurchaseActivityPurchase;
|
||||
import com.griddynamics.msd365fp.manualreview.queues.repository.ItemRepository;
|
||||
import com.griddynamics.msd365fp.manualreview.queues.service.ItemEnrichmentService;
|
||||
import com.griddynamics.msd365fp.manualreview.queues.service.TestingService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
|
@ -42,6 +45,7 @@ import lombok.extern.slf4j.Slf4j;
|
|||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.security.access.annotation.Secured;
|
||||
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
||||
|
@ -73,6 +77,7 @@ public class TestingController {
|
|||
|
||||
private final ItemRepository itemRepository;
|
||||
private final TestingService testingService;
|
||||
private final ItemEnrichmentService itemEnrichmentService;
|
||||
private final EventHubProperties ehProperties;
|
||||
@Qualifier("cosmosdbObjectMapper")
|
||||
private final ObjectMapper mapper;
|
||||
|
@ -80,6 +85,7 @@ public class TestingController {
|
|||
private final CosmosClient cosmosClient;
|
||||
@Setter(onMethod = @__({@Autowired, @Qualifier("azureDFPAPIWebClient")}))
|
||||
private WebClient dfpClient;
|
||||
private final Random rand = new Random();
|
||||
|
||||
@Value("${azure.dfp.purchase-event-url}")
|
||||
private String purchaseEventUrl;
|
||||
|
@ -106,10 +112,30 @@ public class TestingController {
|
|||
return res;
|
||||
}
|
||||
|
||||
@Operation(summary = "Duplicate all items in the queue")
|
||||
@PostMapping(value = "/items/duplicate/queue/{queueId}")
|
||||
public void duplicateItems(@PathVariable("queueId") final String queueId) throws NotFoundException, BusyException {
|
||||
testingService.duplicate(queueId);
|
||||
@Operation(summary = "Trigger forced item enrichment")
|
||||
@PostMapping(value = "/items/{id}/enrichment")
|
||||
public void enrichItemById(@PathVariable final String id) {
|
||||
itemEnrichmentService.enrichItem(id, true);
|
||||
}
|
||||
|
||||
@Operation(summary = "Randomize scores for items in a queue")
|
||||
@PostMapping(value = "/queue/{queueId}/score/randomize")
|
||||
public void randomizeScore(@PathVariable final String queueId) throws BusyException {
|
||||
PageProcessingUtility.executeForAllPages(
|
||||
continuationToken -> itemRepository.findActiveItemsByQueueView(
|
||||
QueueViewType.DIRECT,
|
||||
queueId,
|
||||
20,
|
||||
continuationToken,
|
||||
new Sort.Order(Sort.Direction.ASC, ItemDataField.IMPORT_DATE.getPath()),
|
||||
null,
|
||||
null),
|
||||
items -> items.getValues().forEach(item -> {
|
||||
int score = rand.nextInt(999);
|
||||
item.getAssessmentResult().setRiskScore(score);
|
||||
item.getDecision().setRiskScore(score);
|
||||
itemRepository.save(item);
|
||||
}));
|
||||
}
|
||||
|
||||
@Operation(summary = "Get filter samples")
|
||||
|
@ -305,6 +331,12 @@ public class TestingController {
|
|||
return result;
|
||||
}
|
||||
|
||||
@Operation(summary = "Check disposable email domains for all the items")
|
||||
@PostMapping(value = "/check-email-domains")
|
||||
public List<DisposabilityCheck> checkEmailDomains() {
|
||||
return testingService.checkDisposableEmails();
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class EventResponse {
|
||||
private EventResultDetails resultDetails;
|
||||
|
|
|
@ -41,27 +41,30 @@ public enum ItemDataField implements Serializable {
|
|||
AUTHENTICATION_PROVIDER("purchase.User.AuthenticationProvider"),
|
||||
AGGREGATED_EMAIL_DOMAIN("purchase.CalculatedFields.aggregatedEmailDomain"),
|
||||
AGGREGATED_EMAIL_CONFIRMED("purchase.CalculatedFields.aggregatedEmailConfirmed"),
|
||||
EMAIL_DOMAIN_DISPOSABLE("purchase.CalculatedFields.disposableEmailDomain"),
|
||||
|
||||
// payment
|
||||
MERCHANT_PAYMENT_INSTRUMENT_ID("purchase.PaymentInstrumentList[].PaymentInstrumentId"),
|
||||
CUSTOM_CC_HASH("purchase.CustomData.cc_hash"),
|
||||
PAYMENT_GATEWAY("purchase.BankEventsList[].PaymentProcessor"),
|
||||
BANK_RESPONSE_CODE("purchase.BankEventsList[].BankResponseCode"),
|
||||
AUTH_RESULT_CODE("purchase.CalculatedFields.authResultCodes[]"),
|
||||
APPROVE_RESULT_CODE("purchase.CalculatedFields.approveResultCodes[]"),
|
||||
DECLINE_RESULT_CODE("purchase.CalculatedFields.declineResultCodes[]"),
|
||||
BANK_EVENT_RESULT_CODE("purchase.BankEventsList[].BankResponseCode"),
|
||||
AUTH_BANK_EVENT_RESULT_CODE("purchase.CalculatedFields.authBankEventResultCodes[]"),
|
||||
APPROVE_BANK_EVENT_RESULT_CODE("purchase.CalculatedFields.approveBankEventResultCodes[]"),
|
||||
DECLINE_BANK_EVENT_RESULT_CODE("purchase.CalculatedFields.declineBankEventResultCodes[]"),
|
||||
PI_BIN("purchase.PaymentInstrumentList[].BIN"),
|
||||
PI_COUNTRY("purchase.CalculatedField.billingCountries[]"),
|
||||
PI_ZIP("purchase.CalculatedField.billingZipCodes[]"),
|
||||
PI_ADDRESS("purchase.CalculatedField.billingAddresses[]"),
|
||||
PI_COUNTRY("purchase.CalculatedFields.billingCountries[]"),
|
||||
PI_ZIP("purchase.CalculatedFields.billingZipCodes[]"),
|
||||
PI_ADDRESS("purchase.CalculatedFields.billingAddresses[]"),
|
||||
BILLING_COUNTRY_MATCHES_SHIPPING_COUNTRY("purchase.CalculatedFields.matchingOfCountriesForBillingAndShipping"),
|
||||
BILLING_COUNTRY_MATCHES_IP_COUNTRY("purchase.CalculatedFields.matchingOfCountriesForBillingAndIP"),
|
||||
|
||||
// device
|
||||
DEVICE_CONTEXT_ID("purchase.DeviceContext.DeviceContextId"),
|
||||
EXTERNAL_DEVICE_ID("purchase.DeviceContext.ExternalDeviceId"),
|
||||
DEVICE_CONTEXT_USER_AGENT("purchase.DeviceContext.UserAgent"),
|
||||
IP_COUNTRY("purchase.DeviceContext.IPCountry"),
|
||||
IP_COUNTRY_MATCHES_SHIPPING_COUNTRY("purchase.CalculatedFields.matchingOfCountriesForShippingAndIP"),
|
||||
DISTANCE_TO_PREVIOUS_TRANSACTION_IP("purchase.CalculatedFields.distanceToPreviousTransactionIP"),
|
||||
|
||||
// velocity
|
||||
CUSTOM_CONNECTION_COUNT_BUCKET("purchase.CustomData.connection_count_bucket"),
|
||||
|
@ -69,43 +72,47 @@ public enum ItemDataField implements Serializable {
|
|||
TOTAL_TRANSACTION_COUNT("purchase.User.TotalTransactions"),
|
||||
LAST_30DAYS_TRANSACTION_AMOUNT("purchase.User.last30DaysSpend"),
|
||||
LAST_30DAYS_TRANSACTION_COUNT("purchase.User.last30DaysTransactions"),
|
||||
LAST_HOUR_TRANSACTION_COUNT("purchase.CalculatedFields.lastHourTransactionCount"),
|
||||
LAST_DAY_TRANSACTION_COUNT("purchase.CalculatedFields.lastDayTransactionCount"),
|
||||
LAST_WEEK_TRANSACTION_COUNT("purchase.CalculatedFields.lastWeekTransactionCount"),
|
||||
LAST_HOUR_SUCCESSFUL_TRANSACTION_COUNT("purchase.CalculatedFields.lastHourSuccessfulTransactionCount"),
|
||||
LAST_DAY_SUCCESSFUL_TRANSACTION_COUNT("purchase.CalculatedFields.lastDaySuccessfulTransactionCount"),
|
||||
LAST_WEEK_SUCCESSFUL_TRANSACTION_COUNT("purchase.CalculatedFields.lastWeekSuccessfulTransactionCount"),
|
||||
LAST_HOUR_REJECTED_TRANSACTION_COUNT("purchase.CalculatedFields.lastHourRejectedTransactionCount"),
|
||||
LAST_DAY_REJECTED_TRANSACTION_COUNT("purchase.CalculatedFields.lastDayRejectedTransactionCount"),
|
||||
LAST_WEEK_REJECTED_TRANSACTION_COUNT("purchase.CalculatedFields.lastWeekRejectedTransactionCount"),
|
||||
LAST_HOUR_FAILED_TRANSACTION_COUNT("purchase.CalculatedFields.lastHourFailedTransactionCount"),
|
||||
LAST_DAY_FAILED_TRANSACTION_COUNT("purchase.CalculatedFields.lastDayFailedTransactionCount"),
|
||||
LAST_WEEK_FAILED_TRANSACTION_COUNT("purchase.CalculatedFields.lastWeekFailedTransactionCount"),
|
||||
LAST_HOUR_TRANSACTION_AMOUNT("purchase.CalculatedFields.lastHourTransactionAmount"),
|
||||
LAST_DAY_TRANSACTION_AMOUNT("purchase.CalculatedFields.lastDayTransactionAmount"),
|
||||
LAST_WEEK_TRANSACTION_AMOUNT("purchase.CalculatedFields.lastWeekTransactionAmount"),
|
||||
LAST_HOUR_SUCCESSFUL_TRANSACTION_AMOUNT("purchase.CalculatedFields.lastHourSuccessfulTransactionAmount"),
|
||||
LAST_DAY_SUCCESSFUL_TRANSACTION_AMOUNT("purchase.CalculatedFields.lastDaySuccessfulTransactionAmount"),
|
||||
LAST_WEEK_SUCCESSFUL_TRANSACTION_AMOUNT("purchase.CalculatedFields.lastWeekSuccessfulTransactionAmount"),
|
||||
LAST_HOUR_REJECTED_TRANSACTION_AMOUNT("purchase.CalculatedFields.lastHourRejectedTransactionAmount"),
|
||||
LAST_DAY_REJECTED_TRANSACTION_AMOUNT("purchase.CalculatedFields.lastDayRejectedTransactionAmount"),
|
||||
LAST_WEEK_REJECTED_TRANSACTION_AMOUNT("purchase.CalculatedFields.lastWeekRejectedTransactionAmount"),
|
||||
LAST_HOUR_FAILED_TRANSACTION_AMOUNT("purchase.CalculatedFields.lastHourFailedTransactionAmount"),
|
||||
LAST_DAY_FAILED_TRANSACTION_AMOUNT("purchase.CalculatedFields.lastDayFailedTransactionAmount"),
|
||||
LAST_WEEK_FAILED_TRANSACTION_AMOUNT("purchase.CalculatedFields.lastWeekFailedTransactionAmount"),
|
||||
LAST_HOUR_TRANSACTION_COUNT("purchase.CalculatedFields.transactionCount.hour"),
|
||||
LAST_DAY_TRANSACTION_COUNT("purchase.CalculatedFields.transactionCount.day"),
|
||||
LAST_WEEK_TRANSACTION_COUNT("purchase.CalculatedFields.transactionCount.week"),
|
||||
LAST_HOUR_SUCCESSFUL_TRANSACTION_COUNT("purchase.CalculatedFields.successfulTransactionCount.hour"),
|
||||
LAST_DAY_SUCCESSFUL_TRANSACTION_COUNT("purchase.CalculatedFields.successfulTransactionCount.day"),
|
||||
LAST_WEEK_SUCCESSFUL_TRANSACTION_COUNT("purchase.CalculatedFields.successfulTransactionCount.week"),
|
||||
LAST_HOUR_REJECTED_TRANSACTION_COUNT("purchase.CalculatedFields.rejectedTransactionCount.hour"),
|
||||
LAST_DAY_REJECTED_TRANSACTION_COUNT("purchase.CalculatedFields.rejectedTransactionCount.day"),
|
||||
LAST_WEEK_REJECTED_TRANSACTION_COUNT("purchase.CalculatedFields.rejectedTransactionCount.week"),
|
||||
LAST_HOUR_FAILED_TRANSACTION_COUNT("purchase.CalculatedFields.failedTransactionCount.hour"),
|
||||
LAST_DAY_FAILED_TRANSACTION_COUNT("purchase.CalculatedFields.failedTransactionCount.day"),
|
||||
LAST_WEEK_FAILED_TRANSACTION_COUNT("purchase.CalculatedFields.failedTransactionCount.week"),
|
||||
LAST_HOUR_TRANSACTION_AMOUNT("purchase.CalculatedFields.transactionAmount.hour"),
|
||||
LAST_DAY_TRANSACTION_AMOUNT("purchase.CalculatedFields.transactionAmount.day"),
|
||||
LAST_WEEK_TRANSACTION_AMOUNT("purchase.CalculatedFields.transactionAmount.week"),
|
||||
LAST_HOUR_SUCCESSFUL_TRANSACTION_AMOUNT("purchase.CalculatedFields.successfulTransactionCount.hour"),
|
||||
LAST_DAY_SUCCESSFUL_TRANSACTION_AMOUNT("purchase.CalculatedFields.successfulTransactionCount.day"),
|
||||
LAST_WEEK_SUCCESSFUL_TRANSACTION_AMOUNT("purchase.CalculatedFields.successfulTransactionCount.week"),
|
||||
LAST_HOUR_REJECTED_TRANSACTION_AMOUNT("purchase.CalculatedFields.rejectedTransactionAmount.hour"),
|
||||
LAST_DAY_REJECTED_TRANSACTION_AMOUNT("purchase.CalculatedFields.rejectedTransactionAmount.day"),
|
||||
LAST_WEEK_REJECTED_TRANSACTION_AMOUNT("purchase.CalculatedFields.rejectedTransactionAmount.week"),
|
||||
LAST_HOUR_FAILED_TRANSACTION_AMOUNT("purchase.CalculatedFields.failedTransactionAmount.hour"),
|
||||
LAST_DAY_FAILED_TRANSACTION_AMOUNT("purchase.CalculatedFields.failedTransactionAmount.day"),
|
||||
LAST_WEEK_FAILED_TRANSACTION_AMOUNT("purchase.CalculatedFields.failedTransactionAmount.week"),
|
||||
|
||||
LAST_HOUR_UNIQUE_PI("purchase.CalculatedFields.lastHourUniquePaymentInstrumentCount"),
|
||||
LAST_DAY_UNIQUE_PI("purchase.CalculatedFields.lastDayUniquePaymentInstrumentCount"),
|
||||
LAST_WEEK_UNIQUE_PI("purchase.CalculatedFields.lastWeekUniquePaymentInstrumentCount"),
|
||||
LAST_HOUR_TRANSACTION_COUNT_CURRENT_PI("purchase.CalculatedFields.lastHourTransactionCountWithCurrentPaymentInstrument"),
|
||||
LAST_DAY_TRANSACTION_COUNT_CURRENT_PI("purchase.CalculatedFields.lastDayTransactionCountWithCurrentPaymentInstrument"),
|
||||
LAST_WEEK_TRANSACTION_COUNT_CURRENT_PI("purchase.CalculatedFields.lastWeekTransactionCountWithCurrentPaymentInstrument"),
|
||||
LAST_HOUR_TRANSACTION_AMOUNT_CURRENT_PI("purchase.CalculatedFields.lastHourTransactionAmountWithCurrentPaymentInstrument"),
|
||||
LAST_DAY_TRANSACTION_AMOUNT_CURRENT_PI("purchase.CalculatedFields.lastDayTransactionAmountWithCurrentPaymentInstrument"),
|
||||
LAST_WEEK_TRANSACTION_AMOUNT_CURRENT_PI("purchase.CalculatedFields.lastWeekTransactionAmountWithCurrentPaymentInstrument"),
|
||||
LAST_HOUR_UNIQUE_PI("purchase.CalculatedFields.uniquePaymentInstrumentCount.hour"),
|
||||
LAST_DAY_UNIQUE_PI("purchase.CalculatedFields.uniquePaymentInstrumentCount.day"),
|
||||
LAST_WEEK_UNIQUE_PI("purchase.CalculatedFields.uniquePaymentInstrumentCount.week"),
|
||||
LAST_HOUR_TRANSACTION_COUNT_CURRENT_PI("purchase.CalculatedFields.currentPaymentInstrumentTransactionCount.hour"),
|
||||
LAST_DAY_TRANSACTION_COUNT_CURRENT_PI("purchase.CalculatedFields.currentPaymentInstrumentTransactionCount.day"),
|
||||
LAST_WEEK_TRANSACTION_COUNT_CURRENT_PI("purchase.CalculatedFields.currentPaymentInstrumentTransactionCount.week"),
|
||||
LAST_HOUR_TRANSACTION_AMOUNT_CURRENT_PI("purchase.CalculatedFields.currentPaymentInstrumentTransactionAmount.hour"),
|
||||
LAST_DAY_TRANSACTION_AMOUNT_CURRENT_PI("purchase.CalculatedFields.currentPaymentInstrumentTransactionAmount.day"),
|
||||
LAST_WEEK_TRANSACTION_AMOUNT_CURRENT_PI("purchase.CalculatedFields.currentPaymentInstrumentTransactionAmount.week"),
|
||||
|
||||
CUSTOM_LAST6MONTHS_INVITATIONS_SENT("purchase.CustomData.num_invitations_sent_last_6_months"),
|
||||
CUSTOM_LAST_DAY_CARD_USAGE_COUNT("purchase.CustomData.purchases_per_card_24_hours");
|
||||
CUSTOM_LAST_DAY_CARD_USAGE_COUNT("purchase.CustomData.purchases_per_card_24_hours"),
|
||||
|
||||
LAST_HOUR_UNIQUE_IP_COUNTRIES("purchase.CalculatedFields.uniqueIPCountries.hour"),
|
||||
LAST_DAY_UNIQUE_IP_COUNTRIES("purchase.CalculatedFields.uniqueIPCountries.day"),
|
||||
LAST_WEEK_UNIQUE_IP_COUNTRIES("purchase.CalculatedFields.uniqueIPCountries.week");
|
||||
|
||||
|
||||
@Getter
|
||||
|
|
|
@ -17,8 +17,13 @@ public enum ItemDataFieldCondition implements Serializable {
|
|||
BETWEEN,
|
||||
BETWEEN_ALPH,
|
||||
BETWEEN_DATE,
|
||||
NOT_BETWEEN,
|
||||
NOT_BETWEEN_ALPH,
|
||||
NOT_BETWEEN_DATE,
|
||||
EQUAL,
|
||||
EQUAL_ALPH,
|
||||
NOT_EQUAL,
|
||||
NOT_EQUAL_ALPH,
|
||||
GREATER,
|
||||
GREATER_ALPH,
|
||||
GREATER_DATE,
|
||||
|
|
|
@ -27,12 +27,17 @@ import java.util.List;
|
|||
@JsonSubTypes.Type(value = ItemFilterBetween.class, name = "BETWEEN"),
|
||||
@JsonSubTypes.Type(value = ItemFilterBetweenAlph.class, name = "BETWEEN_ALPH"),
|
||||
@JsonSubTypes.Type(value = ItemFilterBetweenDate.class, name = "BETWEEN_DATE"),
|
||||
@JsonSubTypes.Type(value = ItemFilterBetween.class, name = "NOT_BETWEEN"),
|
||||
@JsonSubTypes.Type(value = ItemFilterBetweenAlph.class, name = "NOT_BETWEEN_ALPH"),
|
||||
@JsonSubTypes.Type(value = ItemFilterBetweenDate.class, name = "NOT_BETWEEN_DATE"),
|
||||
@JsonSubTypes.Type(value = ItemFilterComparison.class, name = "EQUAL"),
|
||||
@JsonSubTypes.Type(value = ItemFilterComparison.class, name = "NOT_EQUAL"),
|
||||
@JsonSubTypes.Type(value = ItemFilterComparison.class, name = "GREATER"),
|
||||
@JsonSubTypes.Type(value = ItemFilterComparison.class, name = "LESS"),
|
||||
@JsonSubTypes.Type(value = ItemFilterComparison.class, name = "GREATER_OR_EQUAL"),
|
||||
@JsonSubTypes.Type(value = ItemFilterComparison.class, name = "LESS_OR_EQUAL"),
|
||||
@JsonSubTypes.Type(value = ItemFilterComparisonAlph.class, name = "EQUAL_ALPH"),
|
||||
@JsonSubTypes.Type(value = ItemFilterComparisonAlph.class, name = "NOT_EQUAL_ALPH"),
|
||||
@JsonSubTypes.Type(value = ItemFilterComparisonAlph.class, name = "GREATER_ALPH"),
|
||||
@JsonSubTypes.Type(value = ItemFilterComparisonAlph.class, name = "LESS_ALPH"),
|
||||
@JsonSubTypes.Type(value = ItemFilterComparisonAlph.class, name = "GREATER_OR_EQUAL_ALPH"),
|
||||
|
|
|
@ -16,117 +16,123 @@ import static com.griddynamics.msd365fp.manualreview.queues.model.ItemDataFieldC
|
|||
public enum ItemFilterField implements Serializable {
|
||||
IMPORT_DATE("Other signals", "Import date",
|
||||
ItemDataField.IMPORT_DATE,
|
||||
Set.of(CONTAINS, REGEXP, BETWEEN_DATE, LESS_DATE, GREATER_DATE, LESS_OR_EQUAL_DATE, GREATER_OR_EQUAL_DATE),
|
||||
Set.of(CONTAINS, REGEXP, BETWEEN_DATE, NOT_BETWEEN_DATE, LESS_DATE, GREATER_DATE, LESS_OR_EQUAL_DATE, GREATER_OR_EQUAL_DATE),
|
||||
null, null,
|
||||
"The moment of adding item to MR Tool."),
|
||||
TOTAL_AMOUNT("Transaction", "Total amount",
|
||||
ItemDataField.TOTAL_AMOUNT,
|
||||
Set.of(BETWEEN, EQUAL, LESS, GREATER, LESS_OR_EQUAL, GREATER_OR_EQUAL),
|
||||
Set.of(BETWEEN, NOT_BETWEEN, EQUAL, NOT_EQUAL, LESS, GREATER, LESS_OR_EQUAL, GREATER_OR_EQUAL),
|
||||
"0", null,
|
||||
"Total amount charged to the customer. Provided by the Merchant."),
|
||||
"Total amount charged to the customer. Provided by the merchant."),
|
||||
USER_COUNTRY("Account", "User country",
|
||||
ItemDataField.USER_COUNTRY,
|
||||
Set.of(IN, CONTAINS, REGEXP, BETWEEN_ALPH, EQUAL_ALPH, LESS_ALPH, GREATER_ALPH, LESS_OR_EQUAL_ALPH, GREATER_OR_EQUAL_ALPH),
|
||||
Set.of(IN, CONTAINS, REGEXP, BETWEEN_ALPH, NOT_BETWEEN_ALPH, EQUAL_ALPH, NOT_EQUAL_ALPH, LESS_ALPH, GREATER_ALPH, LESS_OR_EQUAL_ALPH, GREATER_OR_EQUAL_ALPH),
|
||||
null, null,
|
||||
"The user's country or region."),
|
||||
PRODUCT_SKU("Transaction", "Product SKU",
|
||||
ItemDataField.PRODUCT_SKU,
|
||||
Set.of(IN, CONTAINS, REGEXP, BETWEEN_ALPH, EQUAL_ALPH, LESS_ALPH, GREATER_ALPH, LESS_OR_EQUAL_ALPH, GREATER_OR_EQUAL_ALPH),
|
||||
Set.of(IN, CONTAINS, REGEXP, BETWEEN_ALPH, NOT_BETWEEN_ALPH, EQUAL_ALPH, NOT_EQUAL_ALPH, LESS_ALPH, GREATER_ALPH, LESS_OR_EQUAL_ALPH, GREATER_OR_EQUAL_ALPH),
|
||||
null, null,
|
||||
"Product SKU."),
|
||||
SCORE("Other signals", "Risk score",
|
||||
ItemDataField.SCORE,
|
||||
Set.of(BETWEEN, EQUAL, LESS, GREATER, LESS_OR_EQUAL, GREATER_OR_EQUAL),
|
||||
"-1", "999",
|
||||
Set.of(BETWEEN, NOT_BETWEEN, EQUAL, NOT_EQUAL, LESS, GREATER, LESS_OR_EQUAL, GREATER_OR_EQUAL),
|
||||
"-1", "1000",
|
||||
"Risk score calculated by Fraud Protection risk models in the range from -1 to 1000. -1 indicates an error determining a risk score."
|
||||
),
|
||||
AGGREGATED_EMAIL_CONFIRMED("Account", "Email confirmed",
|
||||
ItemDataField.AGGREGATED_EMAIL_CONFIRMED,
|
||||
Set.of(IS_TRUE),
|
||||
null, null,
|
||||
"An indicator whether the user-provided email address has been verified as owned by the user. Value is aggregated from user data and 'email_confirmed' field in custom purchase data."
|
||||
"An indicator of whether the user-provided email address has been verified as owned by the user. Value is aggregated from user data and 'email_confirmed' field in custom purchase data."
|
||||
),
|
||||
EMAIL_DOMAIN_DISPOSABLE("Other signals", "Disposable email domain",
|
||||
ItemDataField.EMAIL_DOMAIN_DISPOSABLE,
|
||||
Set.of(IS_TRUE),
|
||||
null, null,
|
||||
"An indicator of whether the aggregated email domain is treated as disposable in connected verification systems. Collected near to time of purchase receiving."
|
||||
),
|
||||
AGGREGATED_EMAIL_DOMAIN("Account", "Email domain",
|
||||
ItemDataField.AGGREGATED_EMAIL_DOMAIN,
|
||||
Set.of(IN, CONTAINS, REGEXP, BETWEEN_ALPH, EQUAL_ALPH, LESS_ALPH, GREATER_ALPH, LESS_OR_EQUAL_ALPH, GREATER_OR_EQUAL_ALPH),
|
||||
Set.of(IN, CONTAINS, REGEXP, BETWEEN_ALPH, NOT_BETWEEN_ALPH, EQUAL_ALPH, NOT_EQUAL_ALPH, LESS_ALPH, GREATER_ALPH, LESS_OR_EQUAL_ALPH, GREATER_OR_EQUAL_ALPH),
|
||||
null, null,
|
||||
"An user's email domain. Value is aggregated from user data and 'email_domain' field in custom purchase data."
|
||||
"A user's email domain. Value is aggregated from user data and 'email_domain' field in custom purchase data."
|
||||
),
|
||||
ACCOUNT_AGE("Account", "Account age",
|
||||
ItemDataField.ACCOUNT_AGE,
|
||||
Set.of(BETWEEN, EQUAL, LESS, GREATER, LESS_OR_EQUAL, GREATER_OR_EQUAL),
|
||||
Set.of(BETWEEN, NOT_BETWEEN, EQUAL, NOT_EQUAL, LESS, GREATER, LESS_OR_EQUAL, GREATER_OR_EQUAL),
|
||||
"0", null,
|
||||
"Account age in days on moment of purchase making."
|
||||
),
|
||||
CUSTOM_ACCOUNT_AGE_BUCKET("Account", "Account age bucket",
|
||||
ItemDataField.CUSTOM_ACCOUNT_AGE_BUCKET,
|
||||
Set.of(CONTAINS, REGEXP, BETWEEN_ALPH, EQUAL_ALPH, LESS_ALPH, GREATER_ALPH, LESS_OR_EQUAL_ALPH, GREATER_OR_EQUAL_ALPH),
|
||||
Set.of(CONTAINS, REGEXP, BETWEEN_ALPH, NOT_BETWEEN_ALPH, EQUAL_ALPH, NOT_EQUAL_ALPH, LESS_ALPH, GREATER_ALPH, LESS_OR_EQUAL_ALPH, GREATER_OR_EQUAL_ALPH),
|
||||
null, null,
|
||||
"It is retrieved from 'account_age_in_days_bucket ' field in custom purchase data."
|
||||
),
|
||||
AGE_OF_FIRST_KNOWN_TRANSACTION("Account", "Age of first known transaction",
|
||||
ItemDataField.AGE_OF_FIRST_KNOWN_TRANSACTION,
|
||||
Set.of(BETWEEN, EQUAL, LESS, GREATER, LESS_OR_EQUAL, GREATER_OR_EQUAL),
|
||||
Set.of(BETWEEN, NOT_BETWEEN, EQUAL, NOT_EQUAL, LESS, GREATER, LESS_OR_EQUAL, GREATER_OR_EQUAL),
|
||||
"0", null,
|
||||
"Age in days of first transaction registered in DFP. Calculated on moment of purchase making."
|
||||
"Age in days of first transaction registered in DFP. Calculated near to time of purchase receiving."
|
||||
),
|
||||
AUTHENTICATION_PROVIDER("Account", "Authentication provider",
|
||||
ItemDataField.AUTHENTICATION_PROVIDER,
|
||||
Set.of(IN, CONTAINS, REGEXP, BETWEEN_ALPH, EQUAL_ALPH, LESS_ALPH, GREATER_ALPH, LESS_OR_EQUAL_ALPH, GREATER_OR_EQUAL_ALPH),
|
||||
Set.of(IN, CONTAINS, REGEXP, BETWEEN_ALPH, NOT_BETWEEN_ALPH, EQUAL_ALPH, NOT_EQUAL_ALPH, LESS_ALPH, GREATER_ALPH, LESS_OR_EQUAL_ALPH, GREATER_OR_EQUAL_ALPH),
|
||||
null, null,
|
||||
"The user's authentication provider, if different from the merchant's."
|
||||
),
|
||||
PRODUCT_CATEGORY("Transaction", "Product category",
|
||||
ItemDataField.PRODUCT_CATEGORY,
|
||||
Set.of(IN, CONTAINS, REGEXP, BETWEEN_ALPH, EQUAL_ALPH, LESS_ALPH, GREATER_ALPH, LESS_OR_EQUAL_ALPH, GREATER_OR_EQUAL_ALPH),
|
||||
Set.of(IN, CONTAINS, REGEXP, BETWEEN_ALPH, NOT_BETWEEN_ALPH, EQUAL_ALPH, NOT_EQUAL_ALPH, LESS_ALPH, GREATER_ALPH, LESS_OR_EQUAL_ALPH, GREATER_OR_EQUAL_ALPH),
|
||||
null, null,
|
||||
"Category of product."
|
||||
),
|
||||
PRODUCT_TYPE("Transaction", "Product type",
|
||||
ItemDataField.PRODUCT_TYPE,
|
||||
Set.of(IN, CONTAINS, REGEXP, BETWEEN_ALPH, EQUAL_ALPH, LESS_ALPH, GREATER_ALPH, LESS_OR_EQUAL_ALPH, GREATER_OR_EQUAL_ALPH),
|
||||
Set.of(IN, CONTAINS, REGEXP, BETWEEN_ALPH, NOT_BETWEEN_ALPH, EQUAL_ALPH, NOT_EQUAL_ALPH, LESS_ALPH, GREATER_ALPH, LESS_OR_EQUAL_ALPH, GREATER_OR_EQUAL_ALPH),
|
||||
null, null,
|
||||
"Type of product sold."
|
||||
),
|
||||
CUSTOM_PRODUCT_FAMILIES("Transaction", "Product families",
|
||||
ItemDataField.CUSTOM_PRODUCT_FAMILIES,
|
||||
Set.of(CONTAINS, REGEXP, BETWEEN_ALPH, EQUAL_ALPH, LESS_ALPH, GREATER_ALPH, LESS_OR_EQUAL_ALPH, GREATER_OR_EQUAL_ALPH),
|
||||
Set.of(CONTAINS, REGEXP, BETWEEN_ALPH, NOT_BETWEEN_ALPH, EQUAL_ALPH, NOT_EQUAL_ALPH, LESS_ALPH, GREATER_ALPH, LESS_OR_EQUAL_ALPH, GREATER_OR_EQUAL_ALPH),
|
||||
null, null,
|
||||
"Product families sent by merchant as 'product_families' field in custom purchase data."
|
||||
"Product families sent by the merchant as 'product_families' field in custom purchase data."
|
||||
),
|
||||
MERCHANT_PAYMENT_INSTRUMENT_ID("Credit card", "Merchant payment instrument ID",
|
||||
ItemDataField.MERCHANT_PAYMENT_INSTRUMENT_ID,
|
||||
Set.of(CONTAINS, REGEXP, BETWEEN_ALPH, EQUAL_ALPH, LESS_ALPH, GREATER_ALPH, LESS_OR_EQUAL_ALPH, GREATER_OR_EQUAL_ALPH),
|
||||
Set.of(CONTAINS, REGEXP, BETWEEN_ALPH, NOT_BETWEEN_ALPH, EQUAL_ALPH, NOT_EQUAL_ALPH, LESS_ALPH, GREATER_ALPH, LESS_OR_EQUAL_ALPH, GREATER_OR_EQUAL_ALPH),
|
||||
null, null,
|
||||
"The identifier of the payment instrument. This information is provided by the merchant."
|
||||
),
|
||||
CUSTOM_CC_HASH("Credit card", "Card hash",
|
||||
ItemDataField.PI_BIN,
|
||||
Set.of(CONTAINS, REGEXP, BETWEEN_ALPH, EQUAL_ALPH, LESS_ALPH, GREATER_ALPH, LESS_OR_EQUAL_ALPH, GREATER_OR_EQUAL_ALPH),
|
||||
ItemDataField.CUSTOM_CC_HASH,
|
||||
Set.of(CONTAINS, REGEXP, BETWEEN_ALPH, NOT_BETWEEN_ALPH, EQUAL_ALPH, NOT_EQUAL_ALPH, LESS_ALPH, GREATER_ALPH, LESS_OR_EQUAL_ALPH, GREATER_OR_EQUAL_ALPH),
|
||||
null, null,
|
||||
"Cryptographically hashed card information. This attribute is used only for payments of the Credit/Debit Card type. It is retrieved from 'cc_hash' field in custom purchase data."
|
||||
),
|
||||
PI_BIN("Credit card", "Card BIN",
|
||||
ItemDataField.PI_BIN,
|
||||
Set.of(IN, CONTAINS, REGEXP, BETWEEN_ALPH, EQUAL_ALPH, LESS_ALPH, GREATER_ALPH, LESS_OR_EQUAL_ALPH, GREATER_OR_EQUAL_ALPH),
|
||||
Set.of(IN, CONTAINS, REGEXP, BETWEEN_ALPH, NOT_BETWEEN_ALPH, EQUAL_ALPH, NOT_EQUAL_ALPH, LESS_ALPH, GREATER_ALPH, LESS_OR_EQUAL_ALPH, GREATER_OR_EQUAL_ALPH),
|
||||
null, null,
|
||||
"The term bank identification number. This attribute is used only for payments of the Credit/Debit Card type."
|
||||
),
|
||||
PI_COUNTRY("Credit card", "Billing address: Country",
|
||||
ItemDataField.PI_COUNTRY,
|
||||
Set.of(IN, CONTAINS, REGEXP, BETWEEN_ALPH, EQUAL_ALPH, LESS_ALPH, GREATER_ALPH, LESS_OR_EQUAL_ALPH, GREATER_OR_EQUAL_ALPH),
|
||||
Set.of(IN, CONTAINS, REGEXP, BETWEEN_ALPH, NOT_BETWEEN_ALPH, EQUAL_ALPH, NOT_EQUAL_ALPH, LESS_ALPH, GREATER_ALPH, LESS_OR_EQUAL_ALPH, GREATER_OR_EQUAL_ALPH),
|
||||
null, null,
|
||||
"Country that used in billing address."
|
||||
"Country that is used in a billing address."
|
||||
),
|
||||
PI_ZIP("Credit card", "Billing address: zip",
|
||||
ItemDataField.PI_ZIP,
|
||||
Set.of(IN, CONTAINS, REGEXP, BETWEEN_ALPH, EQUAL_ALPH, LESS_ALPH, GREATER_ALPH, LESS_OR_EQUAL_ALPH, GREATER_OR_EQUAL_ALPH),
|
||||
Set.of(IN, CONTAINS, REGEXP, BETWEEN_ALPH, NOT_BETWEEN_ALPH, EQUAL_ALPH, NOT_EQUAL_ALPH, LESS_ALPH, GREATER_ALPH, LESS_OR_EQUAL_ALPH, GREATER_OR_EQUAL_ALPH),
|
||||
null, null,
|
||||
"Postal code that used in billing address."
|
||||
"Postal code that is used in a billing address."
|
||||
),
|
||||
PI_ADDRESS("Credit card", "Billing address: Address",
|
||||
ItemDataField.PI_ADDRESS,
|
||||
Set.of(CONTAINS, REGEXP, BETWEEN_ALPH, EQUAL_ALPH, LESS_ALPH, GREATER_ALPH, LESS_OR_EQUAL_ALPH, GREATER_OR_EQUAL_ALPH),
|
||||
Set.of(CONTAINS, REGEXP, BETWEEN_ALPH, NOT_BETWEEN_ALPH, EQUAL_ALPH, NOT_EQUAL_ALPH, LESS_ALPH, GREATER_ALPH, LESS_OR_EQUAL_ALPH, GREATER_OR_EQUAL_ALPH),
|
||||
null, null,
|
||||
"The whole billing address string concatenated from all address details."
|
||||
),
|
||||
|
@ -134,308 +140,339 @@ public enum ItemFilterField implements Serializable {
|
|||
ItemDataField.BILLING_COUNTRY_MATCHES_SHIPPING_COUNTRY,
|
||||
Set.of(IS_TRUE),
|
||||
null, null,
|
||||
"Matching with shipping address. Calculated on moment of purchase making."
|
||||
"Matching with shipping address. Calculated near to time of purchase receiving."
|
||||
),
|
||||
BILLING_COUNTRY_MATCHES_IP_COUNTRY("Credit card", "Matching with IP address",
|
||||
ItemDataField.BILLING_COUNTRY_MATCHES_IP_COUNTRY,
|
||||
Set.of(IS_TRUE),
|
||||
null, null,
|
||||
"Matching with IP address. Calculated on moment of purchase making."
|
||||
"Matching with IP address. Calculated near to time of purchase receiving."
|
||||
),
|
||||
PAYMENT_GATEWAY("Transaction", "Payment gateway",
|
||||
ItemDataField.PAYMENT_GATEWAY,
|
||||
Set.of(IN, CONTAINS, REGEXP, BETWEEN_ALPH, EQUAL_ALPH, LESS_ALPH, GREATER_ALPH, LESS_OR_EQUAL_ALPH, GREATER_OR_EQUAL_ALPH),
|
||||
Set.of(IN, CONTAINS, REGEXP, BETWEEN_ALPH, NOT_BETWEEN_ALPH, EQUAL_ALPH, NOT_EQUAL_ALPH, LESS_ALPH, GREATER_ALPH, LESS_OR_EQUAL_ALPH, GREATER_OR_EQUAL_ALPH),
|
||||
null, null,
|
||||
"The value sent by banks as a payment processor."
|
||||
),
|
||||
BANK_RESPONSE_CODE("CC Authentication", "Bank response code",
|
||||
ItemDataField.BANK_RESPONSE_CODE,
|
||||
Set.of(CONTAINS, REGEXP, BETWEEN_ALPH, EQUAL_ALPH, LESS_ALPH, GREATER_ALPH, LESS_OR_EQUAL_ALPH, GREATER_OR_EQUAL_ALPH),
|
||||
BANK_EVENT_RESULT_CODE("CC Authentication", "Bank response code",
|
||||
ItemDataField.BANK_EVENT_RESULT_CODE,
|
||||
Set.of(CONTAINS, REGEXP, BETWEEN_ALPH, NOT_BETWEEN_ALPH, EQUAL_ALPH, NOT_EQUAL_ALPH, LESS_ALPH, GREATER_ALPH, LESS_OR_EQUAL_ALPH, GREATER_OR_EQUAL_ALPH),
|
||||
null, null,
|
||||
"The 'BankResponseCode' field through all bank events."
|
||||
),
|
||||
AUTH_RESULT_CODE("CC Authentication", "Auth result code",
|
||||
ItemDataField.AUTH_RESULT_CODE,
|
||||
Set.of(CONTAINS, REGEXP, BETWEEN_ALPH, EQUAL_ALPH, LESS_ALPH, GREATER_ALPH, LESS_OR_EQUAL_ALPH, GREATER_OR_EQUAL_ALPH),
|
||||
AUTH_BANK_EVENT_RESULT_CODE("CC Authentication", "Auth result code",
|
||||
ItemDataField.AUTH_BANK_EVENT_RESULT_CODE,
|
||||
Set.of(CONTAINS, REGEXP, BETWEEN_ALPH, NOT_BETWEEN_ALPH, EQUAL_ALPH, NOT_EQUAL_ALPH, LESS_ALPH, GREATER_ALPH, LESS_OR_EQUAL_ALPH, GREATER_OR_EQUAL_ALPH),
|
||||
null, null,
|
||||
"Result of CVV/AVS/other verifications. Collected as 'BankResponseCode' field in 'Auth' and 'AuthCancel' bank event types."
|
||||
),
|
||||
APPROVE_RESULT_CODE("CC Authentication", "Approve result code",
|
||||
ItemDataField.APPROVE_RESULT_CODE,
|
||||
Set.of(CONTAINS, REGEXP, BETWEEN_ALPH, EQUAL_ALPH, LESS_ALPH, GREATER_ALPH, LESS_OR_EQUAL_ALPH, GREATER_OR_EQUAL_ALPH),
|
||||
APPROVE_BANK_EVENT_RESULT_CODE("CC Authentication", "Approve result code",
|
||||
ItemDataField.APPROVE_BANK_EVENT_RESULT_CODE,
|
||||
Set.of(CONTAINS, REGEXP, BETWEEN_ALPH, NOT_BETWEEN_ALPH, EQUAL_ALPH, NOT_EQUAL_ALPH, LESS_ALPH, GREATER_ALPH, LESS_OR_EQUAL_ALPH, GREATER_OR_EQUAL_ALPH),
|
||||
null, null,
|
||||
"Results of approval bank events. Collected as 'BankResponseCode' field."
|
||||
),
|
||||
DECLINE_RESULT_CODE("CC Authentication", "Decline result code",
|
||||
ItemDataField.DECLINE_RESULT_CODE,
|
||||
Set.of(CONTAINS, REGEXP, BETWEEN_ALPH, EQUAL_ALPH, LESS_ALPH, GREATER_ALPH, LESS_OR_EQUAL_ALPH, GREATER_OR_EQUAL_ALPH),
|
||||
DECLINE_BANK_EVENT_RESULT_CODE("CC Authentication", "Decline result code",
|
||||
ItemDataField.DECLINE_BANK_EVENT_RESULT_CODE,
|
||||
Set.of(CONTAINS, REGEXP, BETWEEN_ALPH, NOT_BETWEEN_ALPH, EQUAL_ALPH, NOT_EQUAL_ALPH, LESS_ALPH, GREATER_ALPH, LESS_OR_EQUAL_ALPH, GREATER_OR_EQUAL_ALPH),
|
||||
|
||||
null, null,
|
||||
"Results of refusal bank events. Collected as 'BankResponseCode' field."
|
||||
),
|
||||
DEVICE_CONTEXT_ID("Device", "Device context ID",
|
||||
ItemDataField.DEVICE_CONTEXT_ID,
|
||||
Set.of(CONTAINS, REGEXP, BETWEEN_ALPH, NOT_BETWEEN_ALPH, EQUAL_ALPH, NOT_EQUAL_ALPH, LESS_ALPH, GREATER_ALPH, LESS_OR_EQUAL_ALPH, GREATER_OR_EQUAL_ALPH),
|
||||
null, null,
|
||||
"The customer's fingerprinting session ID, or the event ID if the session is not available."
|
||||
),
|
||||
EXTERNAL_DEVICE_ID("Device", "External device ID",
|
||||
ItemDataField.EXTERNAL_DEVICE_ID,
|
||||
Set.of(CONTAINS, REGEXP, BETWEEN_ALPH, EQUAL_ALPH, LESS_ALPH, GREATER_ALPH, LESS_OR_EQUAL_ALPH, GREATER_OR_EQUAL_ALPH),
|
||||
Set.of(CONTAINS, REGEXP, BETWEEN_ALPH, NOT_BETWEEN_ALPH, EQUAL_ALPH, NOT_EQUAL_ALPH, LESS_ALPH, GREATER_ALPH, LESS_OR_EQUAL_ALPH, GREATER_OR_EQUAL_ALPH),
|
||||
null, null,
|
||||
"The customer's device ID, as provided and mastered by the merchant."
|
||||
),
|
||||
DEVICE_CONTEXT_USER_AGENT("Device", "User agent",
|
||||
ItemDataField.DEVICE_CONTEXT_USER_AGENT,
|
||||
Set.of(IN, CONTAINS, REGEXP, BETWEEN_ALPH, EQUAL_ALPH, LESS_ALPH, GREATER_ALPH, LESS_OR_EQUAL_ALPH, GREATER_OR_EQUAL_ALPH),
|
||||
Set.of(IN, CONTAINS, REGEXP, BETWEEN_ALPH, NOT_BETWEEN_ALPH, EQUAL_ALPH, NOT_EQUAL_ALPH, LESS_ALPH, GREATER_ALPH, LESS_OR_EQUAL_ALPH, GREATER_OR_EQUAL_ALPH),
|
||||
null, null,
|
||||
"User Agent collected during purchase making."
|
||||
),
|
||||
IP_COUNTRY("Device", "IP country",
|
||||
ItemDataField.IP_COUNTRY,
|
||||
Set.of(IN, CONTAINS, REGEXP, BETWEEN_ALPH, EQUAL_ALPH, LESS_ALPH, GREATER_ALPH, LESS_OR_EQUAL_ALPH, GREATER_OR_EQUAL_ALPH),
|
||||
Set.of(IN, CONTAINS, REGEXP, BETWEEN_ALPH, NOT_BETWEEN_ALPH, EQUAL_ALPH, NOT_EQUAL_ALPH, LESS_ALPH, GREATER_ALPH, LESS_OR_EQUAL_ALPH, GREATER_OR_EQUAL_ALPH),
|
||||
null, null,
|
||||
"A country that us related to purchse IP address."
|
||||
"A country that is related to the purchase IP address."
|
||||
),
|
||||
IP_COUNTRY_MATCHES_SHIPPING_COUNTRY("Device", "Matching with shipping address",
|
||||
ItemDataField.IP_COUNTRY_MATCHES_SHIPPING_COUNTRY,
|
||||
Set.of(IS_TRUE),
|
||||
null, null,
|
||||
"Matching with shipping address. Calculated on moment of purchase making."
|
||||
"Matching with shipping address. Calculated near to time of purchase receiving."
|
||||
),
|
||||
DISTANCE_TO_PREVIOUS_TRANSACTION_IP("Device", "Distance to previous transaction IP",
|
||||
ItemDataField.DISTANCE_TO_PREVIOUS_TRANSACTION_IP,
|
||||
Set.of(BETWEEN, NOT_BETWEEN, EQUAL, NOT_EQUAL, LESS, GREATER, LESS_OR_EQUAL, GREATER_OR_EQUAL),
|
||||
"0", null,
|
||||
"Distance between current transaction IP location and previous transaction IP location. Location is taken from DFP data. Calculated near to time of purchase receiving."
|
||||
),
|
||||
LAST_HOUR_UNIQUE_IP_COUNTRIES("Velocity/Stats", "Transactions with unique IP Countries (1 hour)",
|
||||
ItemDataField.LAST_HOUR_UNIQUE_IP_COUNTRIES,
|
||||
Set.of(BETWEEN, NOT_BETWEEN, EQUAL, NOT_EQUAL, LESS, GREATER, LESS_OR_EQUAL, GREATER_OR_EQUAL),
|
||||
"0", null,
|
||||
"Count of transactions with unique IP Countries made by the user last hour before current purchase making. Collected near to time of purchase receiving."
|
||||
),
|
||||
LAST_DAY_UNIQUE_IP_COUNTRIES("Velocity/Stats", "Transactions with unique IP Countries (1 day)",
|
||||
ItemDataField.LAST_DAY_UNIQUE_IP_COUNTRIES,
|
||||
Set.of(BETWEEN, NOT_BETWEEN, EQUAL, NOT_EQUAL, LESS, GREATER, LESS_OR_EQUAL, GREATER_OR_EQUAL),
|
||||
"0", null,
|
||||
"Count of transactions with unique IP Countries made by the user last day before current purchase making. Collected near to time of purchase receiving."
|
||||
),
|
||||
LAST_WEEK_UNIQUE_IP_COUNTRIES("Velocity/Stats", "Transactions with unique IP Countries (1 week)",
|
||||
ItemDataField.LAST_WEEK_UNIQUE_IP_COUNTRIES,
|
||||
Set.of(BETWEEN, NOT_BETWEEN, EQUAL, NOT_EQUAL, LESS, GREATER, LESS_OR_EQUAL, GREATER_OR_EQUAL),
|
||||
"0", null,
|
||||
"Count of transactions with unique IP Countries made by the user last week before current purchase making. Collected near to time of purchase receiving."
|
||||
),
|
||||
CUSTOM_CONNECTION_COUNT_BUCKET("Velocity/Stats", "Connection count bucket",
|
||||
ItemDataField.CUSTOM_CONNECTION_COUNT_BUCKET,
|
||||
Set.of(CONTAINS, REGEXP, BETWEEN_ALPH, EQUAL_ALPH, LESS_ALPH, GREATER_ALPH, LESS_OR_EQUAL_ALPH, GREATER_OR_EQUAL_ALPH),
|
||||
Set.of(CONTAINS, REGEXP, BETWEEN_ALPH, NOT_BETWEEN_ALPH, EQUAL_ALPH, NOT_EQUAL_ALPH, LESS_ALPH, GREATER_ALPH, LESS_OR_EQUAL_ALPH, GREATER_OR_EQUAL_ALPH),
|
||||
null, null,
|
||||
"The parameter is retrieved from 'connection_count_bucket' field in custom purchase data."
|
||||
),
|
||||
TOTAL_TRANSACTION_AMOUNT("Velocity/Stats", "Transaction amount (total)",
|
||||
ItemDataField.TOTAL_TRANSACTION_AMOUNT,
|
||||
Set.of(BETWEEN, EQUAL, LESS, GREATER, LESS_OR_EQUAL, GREATER_OR_EQUAL),
|
||||
Set.of(BETWEEN, NOT_BETWEEN, EQUAL, NOT_EQUAL, LESS, GREATER, LESS_OR_EQUAL, GREATER_OR_EQUAL),
|
||||
"0", null,
|
||||
"Total expenses. Registered in DFP on moment of purchase making."
|
||||
),
|
||||
TOTAL_TRANSACTION_COUNT("Velocity/Stats", "Transaction count (total)",
|
||||
ItemDataField.TOTAL_TRANSACTION_COUNT,
|
||||
Set.of(BETWEEN, EQUAL, LESS, GREATER, LESS_OR_EQUAL, GREATER_OR_EQUAL),
|
||||
Set.of(BETWEEN, NOT_BETWEEN, EQUAL, NOT_EQUAL, LESS, GREATER, LESS_OR_EQUAL, GREATER_OR_EQUAL),
|
||||
"0", null,
|
||||
"Total amount of made transactions. Registered in DFP on moment of purchase making."
|
||||
),
|
||||
LAST_30DAYS_TRANSACTION_AMOUNT("Velocity/Stats", "Transaction amount (30 days)",
|
||||
ItemDataField.LAST_30DAYS_TRANSACTION_AMOUNT,
|
||||
Set.of(BETWEEN, EQUAL, LESS, GREATER, LESS_OR_EQUAL, GREATER_OR_EQUAL),
|
||||
Set.of(BETWEEN, NOT_BETWEEN, EQUAL, NOT_EQUAL, LESS, GREATER, LESS_OR_EQUAL, GREATER_OR_EQUAL),
|
||||
"0", null,
|
||||
"Expenses for last 30 days before purchase making. Registered in DFP."
|
||||
"Expenses for the last 30 days before purchase making. Registered in DFP."
|
||||
),
|
||||
LAST_30DAYS_TRANSACTION_COUNT("Velocity/Stats", "Transaction count (30 days)",
|
||||
ItemDataField.LAST_30DAYS_TRANSACTION_COUNT,
|
||||
Set.of(BETWEEN, EQUAL, LESS, GREATER, LESS_OR_EQUAL, GREATER_OR_EQUAL),
|
||||
Set.of(BETWEEN, NOT_BETWEEN, EQUAL, NOT_EQUAL, LESS, GREATER, LESS_OR_EQUAL, GREATER_OR_EQUAL),
|
||||
"0", null,
|
||||
"Amount of made transactions for last 30 days before purchase making. Registered in DFP."
|
||||
"Amount of made transactions for the last 30 days before purchase making. Registered in DFP."
|
||||
),
|
||||
CUSTOM_LAST6MONTHS_INVITATIONS_SENT("Velocity/Stats", "Invitation sent count (6 months)",
|
||||
ItemDataField.CUSTOM_LAST6MONTHS_INVITATIONS_SENT,
|
||||
Set.of(BETWEEN, EQUAL, LESS, GREATER, LESS_OR_EQUAL, GREATER_OR_EQUAL),
|
||||
Set.of(BETWEEN, NOT_BETWEEN, EQUAL, NOT_EQUAL, LESS, GREATER, LESS_OR_EQUAL, GREATER_OR_EQUAL),
|
||||
"0", null,
|
||||
"The parameter is retrieved from 'num_invitations_sent_last_6_months' field in custom purchase data."
|
||||
),
|
||||
CUSTOM_LAST_DAY_CARD_USAGE_COUNT("Velocity/Stats", "Transactions through the same card or member (24 hours)",
|
||||
ItemDataField.CUSTOM_LAST_DAY_CARD_USAGE_COUNT,
|
||||
Set.of(BETWEEN, EQUAL, LESS, GREATER, LESS_OR_EQUAL, GREATER_OR_EQUAL),
|
||||
Set.of(BETWEEN, NOT_BETWEEN, EQUAL, NOT_EQUAL, LESS, GREATER, LESS_OR_EQUAL, GREATER_OR_EQUAL),
|
||||
"0", null,
|
||||
"The parameter is retrieved from 'purchases_per_member_24_hours' field in custom purchase data."
|
||||
),
|
||||
LAST_HOUR_TRANSACTION_COUNT("Velocity/Stats", "Transaction count (1 hour)",
|
||||
ItemDataField.LAST_HOUR_TRANSACTION_COUNT,
|
||||
Set.of(BETWEEN, EQUAL, LESS, GREATER, LESS_OR_EQUAL, GREATER_OR_EQUAL),
|
||||
Set.of(BETWEEN, NOT_BETWEEN, EQUAL, NOT_EQUAL, LESS, GREATER, LESS_OR_EQUAL, GREATER_OR_EQUAL),
|
||||
"0", null,
|
||||
"Amount of transactions for last hour before purchase making. Collected near to time of purchase receiving."
|
||||
"Amount of transactions for the last hour before purchase making. Collected near to time of purchase receiving."
|
||||
),
|
||||
LAST_DAY_TRANSACTION_COUNT("Velocity/Stats", "Transaction count (1 day)",
|
||||
ItemDataField.LAST_DAY_TRANSACTION_COUNT,
|
||||
Set.of(BETWEEN, EQUAL, LESS, GREATER, LESS_OR_EQUAL, GREATER_OR_EQUAL),
|
||||
Set.of(BETWEEN, NOT_BETWEEN, EQUAL, NOT_EQUAL, LESS, GREATER, LESS_OR_EQUAL, GREATER_OR_EQUAL),
|
||||
"0", null,
|
||||
"Amount of transactions for last day before purchase making. Collected near to time of purchase receiving."
|
||||
"Amount of transactions for the last day before purchase making. Collected near to time of purchase receiving."
|
||||
),
|
||||
LAST_WEEK_TRANSACTION_COUNT("Velocity/Stats", "Transaction count (1 week)",
|
||||
ItemDataField.LAST_WEEK_TRANSACTION_COUNT,
|
||||
Set.of(BETWEEN, EQUAL, LESS, GREATER, LESS_OR_EQUAL, GREATER_OR_EQUAL),
|
||||
Set.of(BETWEEN, NOT_BETWEEN, EQUAL, NOT_EQUAL, LESS, GREATER, LESS_OR_EQUAL, GREATER_OR_EQUAL),
|
||||
"0", null,
|
||||
"Amount of transactions for last hour before purchase making. Collected near to time of purchase receiving."
|
||||
"Amount of transactions for the last hour before purchase making. Collected near to time of purchase receiving."
|
||||
),
|
||||
LAST_HOUR_SUCCESSFUL_TRANSACTION_COUNT("Velocity/Stats", "Successful transaction count (1 hour)",
|
||||
ItemDataField.LAST_HOUR_SUCCESSFUL_TRANSACTION_COUNT,
|
||||
Set.of(BETWEEN, EQUAL, LESS, GREATER, LESS_OR_EQUAL, GREATER_OR_EQUAL),
|
||||
Set.of(BETWEEN, NOT_BETWEEN, EQUAL, NOT_EQUAL, LESS, GREATER, LESS_OR_EQUAL, GREATER_OR_EQUAL),
|
||||
"0", null,
|
||||
"Amount of approved transactions for last hour before purchase making. Collected near to time of purchase receiving."
|
||||
"Amount of approved transactions for the last hour before purchase making. Collected near to time of purchase receiving."
|
||||
),
|
||||
LAST_DAY_SUCCESSFUL_TRANSACTION_COUNT("Velocity/Stats", "Successful transaction count (1 day)",
|
||||
ItemDataField.LAST_DAY_SUCCESSFUL_TRANSACTION_COUNT,
|
||||
Set.of(BETWEEN, EQUAL, LESS, GREATER, LESS_OR_EQUAL, GREATER_OR_EQUAL),
|
||||
Set.of(BETWEEN, NOT_BETWEEN, EQUAL, NOT_EQUAL, LESS, GREATER, LESS_OR_EQUAL, GREATER_OR_EQUAL),
|
||||
"0", null,
|
||||
"Amount of approved transactions for last day before purchase making. Collected near to time of purchase receiving."
|
||||
"Amount of approved transactions for the last day before purchase making. Collected near to time of purchase receiving."
|
||||
),
|
||||
LAST_WEEK_SUCCESSFUL_TRANSACTION_COUNT("Velocity/Stats", "Successful transaction count (1 week)",
|
||||
ItemDataField.LAST_WEEK_SUCCESSFUL_TRANSACTION_COUNT,
|
||||
Set.of(BETWEEN, EQUAL, LESS, GREATER, LESS_OR_EQUAL, GREATER_OR_EQUAL),
|
||||
Set.of(BETWEEN, NOT_BETWEEN, EQUAL, NOT_EQUAL, LESS, GREATER, LESS_OR_EQUAL, GREATER_OR_EQUAL),
|
||||
"0", null,
|
||||
"Amount of approved transactions for last hour before purchase making. Collected near to time of purchase receiving."
|
||||
"Amount of approved transactions for the last hour before purchase making. Collected near to time of purchase receiving."
|
||||
),
|
||||
LAST_HOUR_REJECTED_TRANSACTION_COUNT("Velocity/Stats", "Rejected transaction count (1 hour)",
|
||||
ItemDataField.LAST_HOUR_REJECTED_TRANSACTION_COUNT,
|
||||
Set.of(BETWEEN, EQUAL, LESS, GREATER, LESS_OR_EQUAL, GREATER_OR_EQUAL),
|
||||
Set.of(BETWEEN, NOT_BETWEEN, EQUAL, NOT_EQUAL, LESS, GREATER, LESS_OR_EQUAL, GREATER_OR_EQUAL),
|
||||
"0", null,
|
||||
"Amount of rejected transactions for last hour before purchase making. Collected near to time of purchase receiving."
|
||||
"Amount of rejected transactions for the last hour before purchase making. Collected near to time of purchase receiving."
|
||||
),
|
||||
LAST_DAY_REJECTED_TRANSACTION_COUNT("Velocity/Stats", "Rejected transaction count (1 day)",
|
||||
ItemDataField.LAST_DAY_REJECTED_TRANSACTION_COUNT,
|
||||
Set.of(BETWEEN, EQUAL, LESS, GREATER, LESS_OR_EQUAL, GREATER_OR_EQUAL),
|
||||
Set.of(BETWEEN, NOT_BETWEEN, EQUAL, NOT_EQUAL, LESS, GREATER, LESS_OR_EQUAL, GREATER_OR_EQUAL),
|
||||
"0", null,
|
||||
"Amount of rejected transactions for last day before purchase making. Collected near to time of purchase receiving."
|
||||
"Amount of rejected transactions for the last day before purchase making. Collected near to time of purchase receiving."
|
||||
),
|
||||
LAST_WEEK_REJECTED_TRANSACTION_COUNT("Velocity/Stats", "Rejected transaction count (1 week)",
|
||||
ItemDataField.LAST_WEEK_REJECTED_TRANSACTION_COUNT,
|
||||
Set.of(BETWEEN, EQUAL, LESS, GREATER, LESS_OR_EQUAL, GREATER_OR_EQUAL),
|
||||
Set.of(BETWEEN, NOT_BETWEEN, EQUAL, NOT_EQUAL, LESS, GREATER, LESS_OR_EQUAL, GREATER_OR_EQUAL),
|
||||
"0", null,
|
||||
"Amount of rejected transactions for last hour before purchase making. Collected near to time of purchase receiving."
|
||||
"Amount of rejected transactions for the last hour before purchase making. Collected near to time of purchase receiving."
|
||||
),
|
||||
LAST_HOUR_FAILED_TRANSACTION_COUNT("Velocity/Stats", "Failed transaction count (1 hour)",
|
||||
ItemDataField.LAST_HOUR_FAILED_TRANSACTION_COUNT,
|
||||
Set.of(BETWEEN, EQUAL, LESS, GREATER, LESS_OR_EQUAL, GREATER_OR_EQUAL),
|
||||
Set.of(BETWEEN, NOT_BETWEEN, EQUAL, NOT_EQUAL, LESS, GREATER, LESS_OR_EQUAL, GREATER_OR_EQUAL),
|
||||
"0", null,
|
||||
"Amount of failed transactions for last hour before purchase making. Collected near to time of purchase receiving."
|
||||
"Amount of failed transactions for the last hour before purchase making. Collected near to time of purchase receiving."
|
||||
),
|
||||
LAST_DAY_FAILED_TRANSACTION_COUNT("Velocity/Stats", "Failed transaction count (1 day)",
|
||||
ItemDataField.LAST_DAY_FAILED_TRANSACTION_COUNT,
|
||||
Set.of(BETWEEN, EQUAL, LESS, GREATER, LESS_OR_EQUAL, GREATER_OR_EQUAL),
|
||||
Set.of(BETWEEN, NOT_BETWEEN, EQUAL, NOT_EQUAL, LESS, GREATER, LESS_OR_EQUAL, GREATER_OR_EQUAL),
|
||||
"0", null,
|
||||
"Amount of failed transactions for last day before purchase making. Collected near to time of purchase receiving."
|
||||
"Amount of failed transactions for the last day before purchase making. Collected near to time of purchase receiving."
|
||||
),
|
||||
LAST_WEEK_FAILED_TRANSACTION_COUNT("Velocity/Stats", "Failed transaction count (1 week)",
|
||||
ItemDataField.LAST_WEEK_FAILED_TRANSACTION_COUNT,
|
||||
Set.of(BETWEEN, EQUAL, LESS, GREATER, LESS_OR_EQUAL, GREATER_OR_EQUAL),
|
||||
Set.of(BETWEEN, NOT_BETWEEN, EQUAL, NOT_EQUAL, LESS, GREATER, LESS_OR_EQUAL, GREATER_OR_EQUAL),
|
||||
"0", null,
|
||||
"Amount of failed transactions for last hour before purchase making. Collected near to time of purchase receiving."
|
||||
"Amount of failed transactions for the last hour before purchase making. Collected near to time of purchase receiving."
|
||||
),
|
||||
LAST_HOUR_TRANSACTION_AMOUNT("Velocity/Stats", "Transaction amount (1 hour)",
|
||||
ItemDataField.LAST_HOUR_TRANSACTION_AMOUNT,
|
||||
Set.of(BETWEEN, EQUAL, LESS, GREATER, LESS_OR_EQUAL, GREATER_OR_EQUAL),
|
||||
Set.of(BETWEEN, NOT_BETWEEN, EQUAL, NOT_EQUAL, LESS, GREATER, LESS_OR_EQUAL, GREATER_OR_EQUAL),
|
||||
"0", null,
|
||||
"Expenses for last hour before purchase making. Collected near to time of purchase receiving."
|
||||
"Expenses for the last hour before purchase making. Collected near to time of purchase receiving."
|
||||
),
|
||||
LAST_DAY_TRANSACTION_AMOUNT("Velocity/Stats", "Transaction amount (1 day)",
|
||||
ItemDataField.LAST_DAY_TRANSACTION_AMOUNT,
|
||||
Set.of(BETWEEN, EQUAL, LESS, GREATER, LESS_OR_EQUAL, GREATER_OR_EQUAL),
|
||||
Set.of(BETWEEN, NOT_BETWEEN, EQUAL, NOT_EQUAL, LESS, GREATER, LESS_OR_EQUAL, GREATER_OR_EQUAL),
|
||||
"0", null,
|
||||
"Expenses for last day before purchase making. Collected near to time of purchase receiving."
|
||||
"Expenses for the last day before purchase making. Collected near to time of purchase receiving."
|
||||
),
|
||||
LAST_WEEK_TRANSACTION_AMOUNT("Velocity/Stats", "Transaction amount (1 week)",
|
||||
ItemDataField.LAST_WEEK_TRANSACTION_AMOUNT,
|
||||
Set.of(BETWEEN, EQUAL, LESS, GREATER, LESS_OR_EQUAL, GREATER_OR_EQUAL),
|
||||
Set.of(BETWEEN, NOT_BETWEEN, EQUAL, NOT_EQUAL, LESS, GREATER, LESS_OR_EQUAL, GREATER_OR_EQUAL),
|
||||
"0", null,
|
||||
"Expenses for last week before purchase making. Collected near to time of purchase receiving."
|
||||
"Expenses for the last week before purchase making. Collected near to time of purchase receiving."
|
||||
),
|
||||
LAST_HOUR_SUCCESSFUL_TRANSACTION_AMOUNT("Velocity/Stats", "Successful transaction amount (1 hour)",
|
||||
ItemDataField.LAST_HOUR_SUCCESSFUL_TRANSACTION_AMOUNT,
|
||||
Set.of(BETWEEN, EQUAL, LESS, GREATER, LESS_OR_EQUAL, GREATER_OR_EQUAL),
|
||||
Set.of(BETWEEN, NOT_BETWEEN, EQUAL, NOT_EQUAL, LESS, GREATER, LESS_OR_EQUAL, GREATER_OR_EQUAL),
|
||||
"0", null,
|
||||
"Expenses in approved transactions for last hour before purchase making. Collected near to time of purchase receiving."
|
||||
"Expenses in approved transactions for the last hour before purchase making. Collected near to time of purchase receiving."
|
||||
),
|
||||
LAST_DAY_SUCCESSFUL_TRANSACTION_AMOUNT("Velocity/Stats", "Successful transaction amount (1 day)",
|
||||
ItemDataField.LAST_DAY_SUCCESSFUL_TRANSACTION_AMOUNT,
|
||||
Set.of(BETWEEN, EQUAL, LESS, GREATER, LESS_OR_EQUAL, GREATER_OR_EQUAL),
|
||||
Set.of(BETWEEN, NOT_BETWEEN, EQUAL, NOT_EQUAL, LESS, GREATER, LESS_OR_EQUAL, GREATER_OR_EQUAL),
|
||||
"0", null,
|
||||
"Expenses in approved transactions for last day before purchase making. Collected near to time of purchase receiving."
|
||||
"Expenses in approved transactions for the last day before purchase making. Collected near to time of purchase receiving."
|
||||
),
|
||||
LAST_WEEK_SUCCESSFUL_TRANSACTION_AMOUNT("Velocity/Stats", "Successful transaction amount (1 week)",
|
||||
ItemDataField.LAST_WEEK_SUCCESSFUL_TRANSACTION_AMOUNT,
|
||||
Set.of(BETWEEN, EQUAL, LESS, GREATER, LESS_OR_EQUAL, GREATER_OR_EQUAL),
|
||||
Set.of(BETWEEN, NOT_BETWEEN, EQUAL, NOT_EQUAL, LESS, GREATER, LESS_OR_EQUAL, GREATER_OR_EQUAL),
|
||||
"0", null,
|
||||
"Expenses in approved transactions for last week before purchase making. Collected near to time of purchase receiving."
|
||||
"Expenses in approved transactions for the last week before purchase making. Collected near to time of purchase receiving."
|
||||
),
|
||||
LAST_HOUR_REJECTED_TRANSACTION_AMOUNT("Velocity/Stats", "Rejected transaction amount (1 hour)",
|
||||
ItemDataField.LAST_HOUR_REJECTED_TRANSACTION_AMOUNT,
|
||||
Set.of(BETWEEN, EQUAL, LESS, GREATER, LESS_OR_EQUAL, GREATER_OR_EQUAL),
|
||||
Set.of(BETWEEN, NOT_BETWEEN, EQUAL, NOT_EQUAL, LESS, GREATER, LESS_OR_EQUAL, GREATER_OR_EQUAL),
|
||||
"0", null,
|
||||
"Expenses in rejected transactions for last hour before purchase making. Collected near to time of purchase receiving."
|
||||
"Expenses in rejected transactions for the last hour before purchase making. Collected near to time of purchase receiving."
|
||||
),
|
||||
LAST_DAY_REJECTED_TRANSACTION_AMOUNT("Velocity/Stats", "Rejected transaction amount (1 day)",
|
||||
ItemDataField.LAST_DAY_REJECTED_TRANSACTION_AMOUNT,
|
||||
Set.of(BETWEEN, EQUAL, LESS, GREATER, LESS_OR_EQUAL, GREATER_OR_EQUAL),
|
||||
Set.of(BETWEEN, NOT_BETWEEN, EQUAL, NOT_EQUAL, LESS, GREATER, LESS_OR_EQUAL, GREATER_OR_EQUAL),
|
||||
"0", null,
|
||||
"Expenses in rejected transactions for last day before purchase making. Collected near to time of purchase receiving."
|
||||
"Expenses in rejected transactions for the last day before purchase making. Collected near to time of purchase receiving."
|
||||
),
|
||||
LAST_WEEK_REJECTED_TRANSACTION_AMOUNT("Velocity/Stats", "Rejected transaction amount (1 week)",
|
||||
ItemDataField.LAST_WEEK_REJECTED_TRANSACTION_AMOUNT,
|
||||
Set.of(BETWEEN, EQUAL, LESS, GREATER, LESS_OR_EQUAL, GREATER_OR_EQUAL),
|
||||
Set.of(BETWEEN, NOT_BETWEEN, EQUAL, NOT_EQUAL, LESS, GREATER, LESS_OR_EQUAL, GREATER_OR_EQUAL),
|
||||
"0", null,
|
||||
"Expenses in rejected transactions for last week before purchase making. Collected near to time of purchase receiving."
|
||||
"Expenses in rejected transactions for the last week before purchase making. Collected near to time of purchase receiving."
|
||||
),
|
||||
LAST_HOUR_FAILED_TRANSACTION_AMOUNT("Velocity/Stats", "Failed transaction amount (1 hour)",
|
||||
ItemDataField.LAST_HOUR_FAILED_TRANSACTION_AMOUNT,
|
||||
Set.of(BETWEEN, EQUAL, LESS, GREATER, LESS_OR_EQUAL, GREATER_OR_EQUAL),
|
||||
Set.of(BETWEEN, NOT_BETWEEN, EQUAL, NOT_EQUAL, LESS, GREATER, LESS_OR_EQUAL, GREATER_OR_EQUAL),
|
||||
"0", null,
|
||||
"Expenses in failed transactions for last hour before purchase making. Collected near to time of purchase receiving."
|
||||
"Expenses in failed transactions for the last hour before purchase making. Collected near to time of purchase receiving."
|
||||
),
|
||||
LAST_DAY_FAILED_TRANSACTION_AMOUNT("Velocity/Stats", "Failed transaction amount (1 day)",
|
||||
ItemDataField.LAST_DAY_FAILED_TRANSACTION_AMOUNT,
|
||||
Set.of(BETWEEN, EQUAL, LESS, GREATER, LESS_OR_EQUAL, GREATER_OR_EQUAL),
|
||||
Set.of(BETWEEN, NOT_BETWEEN, EQUAL, NOT_EQUAL, LESS, GREATER, LESS_OR_EQUAL, GREATER_OR_EQUAL),
|
||||
"0", null,
|
||||
"Expenses in failed transactions for last day before purchase making. Collected near to time of purchase receiving."
|
||||
"Expenses in failed transactions for the last day before purchase making. Collected near to time of purchase receiving."
|
||||
),
|
||||
LAST_WEEK_FAILED_TRANSACTION_AMOUNT("Velocity/Stats", "Failed transaction amount (1 week)",
|
||||
ItemDataField.LAST_WEEK_FAILED_TRANSACTION_AMOUNT,
|
||||
Set.of(BETWEEN, EQUAL, LESS, GREATER, LESS_OR_EQUAL, GREATER_OR_EQUAL),
|
||||
Set.of(BETWEEN, NOT_BETWEEN, EQUAL, NOT_EQUAL, LESS, GREATER, LESS_OR_EQUAL, GREATER_OR_EQUAL),
|
||||
"0", null,
|
||||
"Expenses in failed transactions for last week before purchase making. Collected near to time of purchase receiving."
|
||||
"Expenses in failed transactions for the last week before purchase making. Collected near to time of purchase receiving."
|
||||
),
|
||||
|
||||
LAST_HOUR_UNIQUE_PI("Velocity/Stats", "Unique used payment instruments count (1 hour)",
|
||||
ItemDataField.LAST_HOUR_UNIQUE_PI,
|
||||
Set.of(BETWEEN, EQUAL, LESS, GREATER, LESS_OR_EQUAL, GREATER_OR_EQUAL),
|
||||
Set.of(BETWEEN, NOT_BETWEEN, EQUAL, NOT_EQUAL, LESS, GREATER, LESS_OR_EQUAL, GREATER_OR_EQUAL),
|
||||
"0", null,
|
||||
"Count of unique payment instruments used by user last hour before purchase making. Collected near to time of purchase receiving."
|
||||
"Count of unique payment instruments used by the user last hour before purchase making. Collected near to time of purchase receiving."
|
||||
),
|
||||
LAST_DAY_UNIQUE_PI("Velocity/Stats", "Unique used payment instruments count (1 day)",
|
||||
ItemDataField.LAST_DAY_UNIQUE_PI,
|
||||
Set.of(BETWEEN, EQUAL, LESS, GREATER, LESS_OR_EQUAL, GREATER_OR_EQUAL),
|
||||
Set.of(BETWEEN, NOT_BETWEEN, EQUAL, NOT_EQUAL, LESS, GREATER, LESS_OR_EQUAL, GREATER_OR_EQUAL),
|
||||
"0", null,
|
||||
"Count of unique payment instruments used by user last day before purchase making. Collected near to time of purchase receiving."
|
||||
"Count of unique payment instruments used by the user last day before purchase making. Collected near to time of purchase receiving."
|
||||
),
|
||||
LAST_WEEK_UNIQUE_PI("Velocity/Stats", "Unique used payment instruments count (1 week)",
|
||||
ItemDataField.LAST_WEEK_UNIQUE_PI,
|
||||
Set.of(BETWEEN, EQUAL, LESS, GREATER, LESS_OR_EQUAL, GREATER_OR_EQUAL),
|
||||
Set.of(BETWEEN, NOT_BETWEEN, EQUAL, NOT_EQUAL, LESS, GREATER, LESS_OR_EQUAL, GREATER_OR_EQUAL),
|
||||
"0", null,
|
||||
"Count of unique payment instruments used by user last week before purchase making. Collected near to time of purchase receiving."
|
||||
"Count of unique payment instruments used by the user last week before purchase making. Collected near to time of purchase receiving."
|
||||
),
|
||||
LAST_HOUR_TRANSACTION_COUNT_CURRENT_PI("Velocity/Stats", "Transaction count with current payment instrument (1 hour)",
|
||||
ItemDataField.LAST_HOUR_TRANSACTION_COUNT_CURRENT_PI,
|
||||
Set.of(BETWEEN, EQUAL, LESS, GREATER, LESS_OR_EQUAL, GREATER_OR_EQUAL),
|
||||
Set.of(BETWEEN, NOT_BETWEEN, EQUAL, NOT_EQUAL, LESS, GREATER, LESS_OR_EQUAL, GREATER_OR_EQUAL),
|
||||
"0", null,
|
||||
"Count of Transactions made with usage of payment instruments from current transaction during last hour before purchase making. Collected near to time of purchase receiving."
|
||||
"Count of Transactions made with the usage of payment instruments from the current transaction during the last hour before purchase making. Collected near to time of purchase receiving."
|
||||
),
|
||||
LAST_DAY_TRANSACTION_COUNT_CURRENT_PI("Velocity/Stats", "Transaction count with current payment instrument (1 day)",
|
||||
ItemDataField.LAST_DAY_TRANSACTION_COUNT_CURRENT_PI,
|
||||
Set.of(BETWEEN, EQUAL, LESS, GREATER, LESS_OR_EQUAL, GREATER_OR_EQUAL),
|
||||
Set.of(BETWEEN, NOT_BETWEEN, EQUAL, NOT_EQUAL, LESS, GREATER, LESS_OR_EQUAL, GREATER_OR_EQUAL),
|
||||
"0", null,
|
||||
"Count of Transactions made with usage of payment instruments from current transaction during last day before purchase making. Collected near to time of purchase receiving."
|
||||
"Count of Transactions made with the usage of payment instruments from the current transaction during the last day before purchase making. Collected near to time of purchase receiving."
|
||||
),
|
||||
LAST_WEEK_TRANSACTION_COUNT_CURRENT_PI("Velocity/Stats", "Transaction count with current payment instrument (1 week)",
|
||||
ItemDataField.LAST_WEEK_TRANSACTION_COUNT_CURRENT_PI,
|
||||
Set.of(BETWEEN, EQUAL, LESS, GREATER, LESS_OR_EQUAL, GREATER_OR_EQUAL),
|
||||
Set.of(BETWEEN, NOT_BETWEEN, EQUAL, NOT_EQUAL, LESS, GREATER, LESS_OR_EQUAL, GREATER_OR_EQUAL),
|
||||
"0", null,
|
||||
"Count of Transactions made with usage of payment instruments from current transaction during last week before purchase making. Collected near to time of purchase receiving."
|
||||
"Count of Transactions made with the usage of payment instruments from the current transaction during the last week before purchase making. Collected near to time of purchase receiving."
|
||||
),
|
||||
LAST_HOUR_TRANSACTION_AMOUNT_CURRENT_PI("Velocity/Stats", "Transaction amount with current payment instrument (1 hour)",
|
||||
ItemDataField.LAST_HOUR_TRANSACTION_AMOUNT_CURRENT_PI,
|
||||
Set.of(BETWEEN, EQUAL, LESS, GREATER, LESS_OR_EQUAL, GREATER_OR_EQUAL),
|
||||
Set.of(BETWEEN, NOT_BETWEEN, EQUAL, NOT_EQUAL, LESS, GREATER, LESS_OR_EQUAL, GREATER_OR_EQUAL),
|
||||
"0", null,
|
||||
"Expenses processed with usage of payment instruments from current transaction during last hour before purchase making. Collected near to time of purchase receiving."
|
||||
"Expenses processed with the usage of payment instruments from the current transaction during the last hour before purchase making. Collected near to time of purchase receiving."
|
||||
),
|
||||
LAST_DAY_TRANSACTION_AMOUNT_CURRENT_PI("Velocity/Stats", "Transaction amount with current payment instrument (1 day)",
|
||||
ItemDataField.LAST_DAY_TRANSACTION_AMOUNT_CURRENT_PI,
|
||||
Set.of(BETWEEN, EQUAL, LESS, GREATER, LESS_OR_EQUAL, GREATER_OR_EQUAL),
|
||||
Set.of(BETWEEN, NOT_BETWEEN, EQUAL, NOT_EQUAL, LESS, GREATER, LESS_OR_EQUAL, GREATER_OR_EQUAL),
|
||||
"0", null,
|
||||
"Expenses processed with usage of payment instruments from current transaction during last day before purchase making. Collected near to time of purchase receiving."
|
||||
"Expenses processed with the usage of payment instruments from the current transaction during the last day before purchase making. Collected near to time of purchase receiving."
|
||||
),
|
||||
LAST_WEEK_TRANSACTION_AMOUNT_CURRENT_PI("Velocity/Stats", "Transaction amount with current payment instrument (1 week)",
|
||||
ItemDataField.LAST_WEEK_TRANSACTION_AMOUNT_CURRENT_PI,
|
||||
Set.of(BETWEEN, EQUAL, LESS, GREATER, LESS_OR_EQUAL, GREATER_OR_EQUAL),
|
||||
Set.of(BETWEEN, NOT_BETWEEN, EQUAL, NOT_EQUAL, LESS, GREATER, LESS_OR_EQUAL, GREATER_OR_EQUAL),
|
||||
"0", null,
|
||||
"Expenses processed with usage of payment instruments from current transaction during last week before purchase making. Collected near to time of purchase receiving."
|
||||
"Expenses processed with the usage of payment instruments from the current transaction during the last week before purchase making. Collected near to time of purchase receiving."
|
||||
);
|
||||
|
||||
@Getter
|
||||
|
|
|
@ -7,6 +7,8 @@ import lombok.Data;
|
|||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.Pattern;
|
||||
import javax.validation.constraints.Size;
|
||||
import java.util.List;
|
||||
|
||||
|
@ -14,6 +16,6 @@ import java.util.List;
|
|||
@ToString(callSuper = true)
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class ItemFilterIsTrue extends ItemFilter {
|
||||
@Size(max = 0, message = "there should not be any arguments for IS_TRUE filter")
|
||||
private List<String> values;
|
||||
@Size(min = 1, max = 1, message = "there should be exactly one argument for IS_TRUE filter")
|
||||
private List<@NotBlank @Pattern(regexp = "true|false", flags = {Pattern.Flag.CASE_INSENSITIVE}) String> values;
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ import lombok.extern.slf4j.Slf4j;
|
|||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.*;
|
||||
|
@ -38,8 +39,8 @@ public class ItemQuery {
|
|||
|
||||
private String alias;
|
||||
private final List<String> queryParts = new ArrayList<>();
|
||||
|
||||
private final Map<String, List<String>> joinParts = new TreeMap<>();
|
||||
private String orderPart = "";
|
||||
|
||||
ItemQueryConstructor alias(String alias) {
|
||||
this.alias = alias;
|
||||
|
@ -138,9 +139,10 @@ public class ItemQuery {
|
|||
break;
|
||||
case IS_TRUE:
|
||||
condition = String.format(
|
||||
"(IS_DEFINED(%1$s%2$s) AND NOT IS_NULL(%1$s%2$s) AND %1$s%2$s)", //TODO: check
|
||||
"%3$s (IS_DEFINED(%1$s%2$s) AND NOT IS_NULL(%1$s%2$s) AND %1$s%2$s)", //TODO: check
|
||||
decomposition.getLocalAlias(),
|
||||
decomposition.getPath()
|
||||
decomposition.getPath(),
|
||||
Boolean.parseBoolean(itemFilter.getValues().get(0)) ? "" : "NOT"
|
||||
);
|
||||
break;
|
||||
case REGEXP:
|
||||
|
@ -160,6 +162,15 @@ public class ItemQuery {
|
|||
itemFilter.getValues().get(1)
|
||||
);
|
||||
break;
|
||||
case NOT_BETWEEN:
|
||||
condition = String.format(
|
||||
"(%s%s NOT BETWEEN %s AND %s)",
|
||||
decomposition.getLocalAlias(),
|
||||
decomposition.getPath(),
|
||||
itemFilter.getValues().get(0),
|
||||
itemFilter.getValues().get(1)
|
||||
);
|
||||
break;
|
||||
case BETWEEN_ALPH:
|
||||
condition = String.format(
|
||||
"(%s%s BETWEEN '%s' AND '%s')",
|
||||
|
@ -169,6 +180,15 @@ public class ItemQuery {
|
|||
itemFilter.getValues().get(1)
|
||||
);
|
||||
break;
|
||||
case NOT_BETWEEN_ALPH:
|
||||
condition = String.format(
|
||||
"(%s%s NOT BETWEEN '%s' AND '%s')",
|
||||
decomposition.getLocalAlias(),
|
||||
decomposition.getPath(),
|
||||
itemFilter.getValues().get(0),
|
||||
itemFilter.getValues().get(1)
|
||||
);
|
||||
break;
|
||||
case BETWEEN_DATE:
|
||||
condition = String.format(
|
||||
"(%s%s BETWEEN %s AND %s)",
|
||||
|
@ -178,7 +198,17 @@ public class ItemQuery {
|
|||
OffsetDateTime.parse(itemFilter.getValues().get(1)).toEpochSecond()
|
||||
);
|
||||
break;
|
||||
case NOT_BETWEEN_DATE:
|
||||
condition = String.format(
|
||||
"(%s%s NOT BETWEEN %s AND %s)",
|
||||
decomposition.getLocalAlias(),
|
||||
decomposition.getPath(),
|
||||
OffsetDateTime.parse(itemFilter.getValues().get(0)).toEpochSecond(),
|
||||
OffsetDateTime.parse(itemFilter.getValues().get(1)).toEpochSecond()
|
||||
);
|
||||
break;
|
||||
case EQUAL:
|
||||
case NOT_EQUAL:
|
||||
case GREATER:
|
||||
case LESS:
|
||||
case GREATER_OR_EQUAL:
|
||||
|
@ -191,6 +221,7 @@ public class ItemQuery {
|
|||
itemFilter.getValues().get(0));
|
||||
break;
|
||||
case EQUAL_ALPH:
|
||||
case NOT_EQUAL_ALPH:
|
||||
case GREATER_ALPH:
|
||||
case LESS_ALPH:
|
||||
case GREATER_OR_EQUAL_ALPH:
|
||||
|
@ -234,6 +265,9 @@ public class ItemQuery {
|
|||
case EQUAL:
|
||||
case EQUAL_ALPH:
|
||||
return "=";
|
||||
case NOT_EQUAL:
|
||||
case NOT_EQUAL_ALPH:
|
||||
return "!=";
|
||||
case GREATER:
|
||||
case GREATER_ALPH:
|
||||
case GREATER_DATE:
|
||||
|
@ -256,12 +290,7 @@ public class ItemQuery {
|
|||
}
|
||||
|
||||
public ItemQueryConstructor order(Sort.Order order) {
|
||||
queryParts.add(String.format(
|
||||
"ORDER BY %s.%s %s",
|
||||
alias,
|
||||
order.getProperty(),
|
||||
order.getDirection())
|
||||
);
|
||||
orderPart = order.getProperty() + " " + order.getDirection();
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -420,11 +449,22 @@ public class ItemQuery {
|
|||
}
|
||||
|
||||
public String constructSelect() {
|
||||
return String.format(
|
||||
"SELECT %1$s FROM %1$s %2$s WHERE %3$s",
|
||||
alias,
|
||||
getJoinClause(),
|
||||
Joiner.on(" ").join(queryParts));
|
||||
String joinClause = getJoinClause();
|
||||
|
||||
if (StringUtils.isEmpty(joinClause)) {
|
||||
return String.format(
|
||||
"SELECT %1$s FROM %1$s WHERE %2$s %3$s",
|
||||
alias,
|
||||
Joiner.on(" ").join(queryParts),
|
||||
getOrderByClause(""));
|
||||
} else {
|
||||
return String.format(
|
||||
"SELECT VALUE root FROM (SELECT DISTINCT %1$s FROM %1$s %2$s WHERE %3$s) AS root %4$s",
|
||||
alias,
|
||||
joinClause,
|
||||
Joiner.on(" ").join(queryParts),
|
||||
getOrderByClause("root"));
|
||||
}
|
||||
}
|
||||
|
||||
public String constructCount() {
|
||||
|
@ -450,7 +490,7 @@ public class ItemQuery {
|
|||
return CollectionUtils.isEmpty(joinParts) ? "" :
|
||||
joinParts.entrySet().stream()
|
||||
.map(entry -> String.format(
|
||||
"JOIN (SELECT VALUE %1$s FROM %1$s IN %2$s.%3$s WHERE %4$s) %1$s",
|
||||
"JOIN (SELECT DISTINCT VALUE %1$s FROM %1$s IN %2$s.%3$s WHERE %4$s) %1$s",
|
||||
getJoinClauseAliasName(entry.getKey()),
|
||||
alias,
|
||||
entry.getKey(),
|
||||
|
@ -458,6 +498,15 @@ public class ItemQuery {
|
|||
.collect(Collectors.joining(" "));
|
||||
}
|
||||
|
||||
private String getOrderByClause(String rootAlias) {
|
||||
return StringUtils.isEmpty(orderPart) ? "" :
|
||||
String.format(
|
||||
"ORDER BY %s%s.%s",
|
||||
StringUtils.isEmpty(rootAlias) ? "" : rootAlias + ".",
|
||||
alias,
|
||||
orderPart);
|
||||
}
|
||||
|
||||
public ItemSelectQueryExecutor constructSelectExecutor(ExtendedCosmosContainer itemsContainer) {
|
||||
return (size, continuationToken) -> {
|
||||
String query = constructSelect();
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
package com.griddynamics.msd365fp.manualreview.queues.model;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class NameApiResponse {
|
||||
private DisposabilityStatus disposable;
|
||||
|
||||
public enum DisposabilityStatus {
|
||||
YES,
|
||||
NO,
|
||||
UNKNOWN
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
package com.griddynamics.msd365fp.manualreview.queues.model;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class OpenKickboxResponse {
|
||||
private boolean disposable;
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package com.griddynamics.msd365fp.manualreview.queues.model.dto;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.time.Duration;
|
||||
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@Data
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
public class AccessTokenDTO {
|
||||
@NotNull
|
||||
@JsonProperty("access_token")
|
||||
private String token;
|
||||
@JsonProperty("expires_in")
|
||||
private Duration expiresIn;
|
||||
@JsonProperty("token_type")
|
||||
private String tokenType;
|
||||
}
|
||||
|
|
@ -8,6 +8,7 @@ import com.griddynamics.msd365fp.manualreview.queues.model.ItemFilter;
|
|||
import com.griddynamics.msd365fp.manualreview.queues.validation.FieldConditionCombination;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import java.util.Set;
|
||||
|
||||
@Data
|
||||
|
@ -16,7 +17,7 @@ public class ItemSearchQueryDTO {
|
|||
private Boolean active;
|
||||
private Set<String> queueIds;
|
||||
private boolean residual = false;
|
||||
private Set<@FieldConditionCombination ItemFilter> itemFilters;
|
||||
private Set<@FieldConditionCombination @Valid ItemFilter> itemFilters;
|
||||
private Set<String> lockOwnerIds;
|
||||
private Set<String> holdOwnerIds;
|
||||
private Set<Label> labels;
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
package com.griddynamics.msd365fp.manualreview.queues.model.dto;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.time.Duration;
|
||||
import java.time.OffsetDateTime;
|
||||
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@Data
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
public class MapTokenDTO {
|
||||
@NotNull
|
||||
private String token;
|
||||
@NotNull
|
||||
private Duration expiresIn;
|
||||
@NotNull
|
||||
private OffsetDateTime expiresAt;
|
||||
@NotNull
|
||||
private String tokenType;
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
package com.griddynamics.msd365fp.manualreview.queues.model.persistence;
|
||||
|
||||
import com.griddynamics.msd365fp.manualreview.model.DisposabilityCheck;
|
||||
import com.microsoft.azure.spring.data.cosmosdb.core.mapping.Document;
|
||||
import com.microsoft.azure.spring.data.cosmosdb.core.mapping.PartitionKey;
|
||||
import lombok.*;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.annotation.Version;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import static com.griddynamics.msd365fp.manualreview.queues.config.Constants.EMAIL_DOMAINS_CONTAINER_NAME;
|
||||
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Data
|
||||
@Builder(toBuilder = true)
|
||||
@EqualsAndHashCode(exclude = "_etag")
|
||||
@Document(collection = EMAIL_DOMAINS_CONTAINER_NAME)
|
||||
public class EmailDomain implements Serializable {
|
||||
@Id
|
||||
@PartitionKey
|
||||
private String emailDomainName;
|
||||
private DisposabilityCheck disposabilityCheck;
|
||||
|
||||
@Version
|
||||
@SuppressWarnings("java:S116")
|
||||
String _etag;
|
||||
private long ttl;
|
||||
}
|
|
@ -33,6 +33,9 @@ public class Item implements Serializable {
|
|||
private String id;
|
||||
private OffsetDateTime imported;
|
||||
private OffsetDateTime enriched;
|
||||
private int enrichmentAttempts;
|
||||
private boolean enrichmentFailed;
|
||||
private String enrichmentFailReason;
|
||||
@JsonProperty(value = "_ts")
|
||||
private OffsetDateTime updated;
|
||||
|
||||
|
|
|
@ -28,7 +28,9 @@ public class Task {
|
|||
private TaskStatus status;
|
||||
private Map<String,String> variables;
|
||||
private OffsetDateTime previousRun;
|
||||
private String failedStatusMessage;
|
||||
private Boolean previousRunSuccessfull;
|
||||
private String lastFailedRunMessage;
|
||||
private String instanceId;
|
||||
|
||||
@Version
|
||||
@SuppressWarnings("java:S116")
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
package com.griddynamics.msd365fp.manualreview.queues.repository;
|
||||
|
||||
import com.griddynamics.msd365fp.manualreview.queues.model.persistence.EmailDomain;
|
||||
import com.microsoft.azure.spring.data.cosmosdb.repository.CosmosRepository;
|
||||
|
||||
public interface EmailDomainRepository extends CosmosRepository<EmailDomain, String> {
|
||||
|
||||
}
|
|
@ -55,7 +55,7 @@ public interface ItemRepositoryCustomMethods {
|
|||
final String continuationToken);
|
||||
|
||||
PageableCollection<String> findUnenrichedItemIds(
|
||||
final OffsetDateTime updatedUpperBoundary,
|
||||
final OffsetDateTime importedUpperBoundary,
|
||||
final int size,
|
||||
final String continuationToken);
|
||||
|
||||
|
|
|
@ -154,12 +154,18 @@ public class ItemRepositoryCustomMethodsImpl implements ItemRepositoryCustomMeth
|
|||
|
||||
@Override
|
||||
public PageableCollection<String> findUnenrichedItemIds(
|
||||
final OffsetDateTime updatedUpperBoundary,
|
||||
final OffsetDateTime importedUpperBoundary,
|
||||
final int size,
|
||||
final String continuationToken) {
|
||||
ExtendedCosmosContainer.Page res = itemsContainer.runCrossPartitionPageableQuery(
|
||||
String.format("SELECT i.id FROM i WHERE IS_NULL(i.enriched) AND i._ts <= %s",
|
||||
updatedUpperBoundary.toEpochSecond()),
|
||||
String.format("SELECT i.id FROM i WHERE IS_NULL(i.enriched) " +
|
||||
"AND (" +
|
||||
" NOT IS_DEFINED(i.enrichmentFailed) " +
|
||||
" OR IS_NULL(i.enrichmentFailed) " +
|
||||
" OR NOT i.enrichmentFailed " +
|
||||
") AND i.imported <= %s " +
|
||||
"ORDER BY i._ts",
|
||||
importedUpperBoundary.toEpochSecond()),
|
||||
size,
|
||||
continuationToken);
|
||||
List<String> queriedItems = res.getContent()
|
||||
|
@ -235,7 +241,6 @@ public class ItemRepositoryCustomMethodsImpl implements ItemRepositoryCustomMeth
|
|||
.and().notEscalation()
|
||||
.and().updatedAfter(enrichedSince)
|
||||
.and().includeLocked(includeLocked)
|
||||
.order(order)
|
||||
.constructSelectExecutor(itemsContainer)
|
||||
.execute(size, continuationToken);
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ import lombok.extern.slf4j.Slf4j;
|
|||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.cache.annotation.Cacheable;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
@ -31,6 +32,7 @@ public class DFPExplorerService {
|
|||
@Value("${azure.dfp.graph-explorer-url}")
|
||||
private String dfpExplorerUrl;
|
||||
|
||||
@Cacheable(value = "traversal-purchase", unless = "#result.isEmpty()")
|
||||
public ExplorerEntity explorePurchase(final String id) {
|
||||
ExplorerEntityRequest request = ExplorerEntityRequest.builder()
|
||||
.attribute("PurchaseId")
|
||||
|
@ -40,6 +42,7 @@ public class DFPExplorerService {
|
|||
return explore(request);
|
||||
}
|
||||
|
||||
@Cacheable(value = "traversal-pi", unless = "#result.isEmpty()")
|
||||
public ExplorerEntity explorePaymentInstrument(final String id) {
|
||||
ExplorerEntityRequest request = ExplorerEntityRequest.builder()
|
||||
.attribute("PaymentInstrumentId")
|
||||
|
@ -49,6 +52,7 @@ public class DFPExplorerService {
|
|||
return explore(request);
|
||||
}
|
||||
|
||||
@Cacheable(value = "traversal-user", unless = "#result.isEmpty()")
|
||||
public ExplorerEntity exploreUser(final String id) {
|
||||
ExplorerEntityRequest request = ExplorerEntityRequest.builder()
|
||||
.attribute("UserId")
|
||||
|
@ -59,12 +63,17 @@ public class DFPExplorerService {
|
|||
}
|
||||
|
||||
private ExplorerEntity explore(final ExplorerEntityRequest request) {
|
||||
return dfpClient
|
||||
log.info("Start exploration of [{}] [{}]", request.getAttribute(), request.getValue());
|
||||
ExplorerEntity result = dfpClient
|
||||
.post()
|
||||
.uri(dfpExplorerUrl)
|
||||
.body(Mono.just(request), ExplorerEntityRequest.class)
|
||||
.retrieve()
|
||||
.bodyToMono(ExplorerEntity.class)
|
||||
.block();
|
||||
log.info("Exploration of [{}] [{}] has finished successfully", request.getAttribute(), request.getValue());
|
||||
result.setRequestAttributeName(request.getAttribute());
|
||||
result.setRequestAttributeValue(request.getValue());
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -159,7 +159,7 @@ public class DataSecurityService {
|
|||
@NonNull final Queue queue,
|
||||
@NonNull final String actor) {
|
||||
return SetUtils.union(
|
||||
Objects.requireNonNullElse(queue.getReviewers(), Collections.emptySet()),
|
||||
Objects.requireNonNullElse(queue.getSupervisors(), Collections.emptySet()),
|
||||
Objects.requireNonNullElse(queue.getReviewers(), Collections.emptySet()))
|
||||
.contains(actor);
|
||||
}
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче