Merge branch 'develop' into main
This commit is contained in:
commit
912ea52351
File diff suppressed because it is too large
Load Diff
@ -63,7 +63,7 @@
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.DBforMySQL/flexibleServers', parameters('flexibleServers_mysql_odms_db_dev_name'))]"
|
||||
],
|
||||
"name": "[concat(parameters('flexibleServers_mysql_odms_db_dev_name'), '/daily-20231026t072100-6cc69487-0eb7-4530-8f35-d1ce130a7df7')]",
|
||||
"name": "[concat(parameters('flexibleServers_mysql_odms_db_dev_name'), '/daily-20231108t072100-6cc69487-0eb7-4530-8f35-d1ce130a7df7')]",
|
||||
"type": "Microsoft.DBforMySQL/flexibleServers/backups"
|
||||
},
|
||||
{
|
||||
@ -71,7 +71,7 @@
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.DBforMySQL/flexibleServers', parameters('flexibleServers_mysql_odms_db_dev_name'))]"
|
||||
],
|
||||
"name": "[concat(parameters('flexibleServers_mysql_odms_db_dev_name'), '/daily-20231027t072100-6cc69487-0eb7-4530-8f35-d1ce130a7df7')]",
|
||||
"name": "[concat(parameters('flexibleServers_mysql_odms_db_dev_name'), '/daily-20231109t072100-6cc69487-0eb7-4530-8f35-d1ce130a7df7')]",
|
||||
"type": "Microsoft.DBforMySQL/flexibleServers/backups"
|
||||
},
|
||||
{
|
||||
@ -79,7 +79,7 @@
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.DBforMySQL/flexibleServers', parameters('flexibleServers_mysql_odms_db_dev_name'))]"
|
||||
],
|
||||
"name": "[concat(parameters('flexibleServers_mysql_odms_db_dev_name'), '/daily-20231028t072100-6cc69487-0eb7-4530-8f35-d1ce130a7df7')]",
|
||||
"name": "[concat(parameters('flexibleServers_mysql_odms_db_dev_name'), '/daily-20231110t072100-6cc69487-0eb7-4530-8f35-d1ce130a7df7')]",
|
||||
"type": "Microsoft.DBforMySQL/flexibleServers/backups"
|
||||
},
|
||||
{
|
||||
@ -87,7 +87,7 @@
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.DBforMySQL/flexibleServers', parameters('flexibleServers_mysql_odms_db_dev_name'))]"
|
||||
],
|
||||
"name": "[concat(parameters('flexibleServers_mysql_odms_db_dev_name'), '/daily-20231029t072100-6cc69487-0eb7-4530-8f35-d1ce130a7df7')]",
|
||||
"name": "[concat(parameters('flexibleServers_mysql_odms_db_dev_name'), '/daily-20231111t072100-6cc69487-0eb7-4530-8f35-d1ce130a7df7')]",
|
||||
"type": "Microsoft.DBforMySQL/flexibleServers/backups"
|
||||
},
|
||||
{
|
||||
@ -95,7 +95,7 @@
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.DBforMySQL/flexibleServers', parameters('flexibleServers_mysql_odms_db_dev_name'))]"
|
||||
],
|
||||
"name": "[concat(parameters('flexibleServers_mysql_odms_db_dev_name'), '/daily-20231030t072100-6cc69487-0eb7-4530-8f35-d1ce130a7df7')]",
|
||||
"name": "[concat(parameters('flexibleServers_mysql_odms_db_dev_name'), '/daily-20231112t072100-6cc69487-0eb7-4530-8f35-d1ce130a7df7')]",
|
||||
"type": "Microsoft.DBforMySQL/flexibleServers/backups"
|
||||
},
|
||||
{
|
||||
@ -103,7 +103,7 @@
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.DBforMySQL/flexibleServers', parameters('flexibleServers_mysql_odms_db_dev_name'))]"
|
||||
],
|
||||
"name": "[concat(parameters('flexibleServers_mysql_odms_db_dev_name'), '/daily-20231031t072100-6cc69487-0eb7-4530-8f35-d1ce130a7df7')]",
|
||||
"name": "[concat(parameters('flexibleServers_mysql_odms_db_dev_name'), '/daily-20231113t072100-6cc69487-0eb7-4530-8f35-d1ce130a7df7')]",
|
||||
"type": "Microsoft.DBforMySQL/flexibleServers/backups"
|
||||
},
|
||||
{
|
||||
@ -111,7 +111,7 @@
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.DBforMySQL/flexibleServers', parameters('flexibleServers_mysql_odms_db_dev_name'))]"
|
||||
],
|
||||
"name": "[concat(parameters('flexibleServers_mysql_odms_db_dev_name'), '/daily-20231101t072100-6cc69487-0eb7-4530-8f35-d1ce130a7df7')]",
|
||||
"name": "[concat(parameters('flexibleServers_mysql_odms_db_dev_name'), '/daily-20231114t072100-6cc69487-0eb7-4530-8f35-d1ce130a7df7')]",
|
||||
"type": "Microsoft.DBforMySQL/flexibleServers/backups"
|
||||
},
|
||||
{
|
||||
@ -5332,9 +5332,9 @@
|
||||
],
|
||||
"name": "[concat(parameters('flexibleServers_mysql_odms_db_dev_name'), '/slow_query_log_file')]",
|
||||
"properties": {
|
||||
"currentValue": "/app/serverlogs/slowlogs/mysql-slow-mysql-odms-db-dev-2023110109.log",
|
||||
"currentValue": "/app/serverlogs/slowlogs/mysql-slow-mysql-odms-db-dev-2023111409.log",
|
||||
"source": "user-override",
|
||||
"value": "/app/serverlogs/slowlogs/mysql-slow-mysql-odms-db-dev-2023110109.log"
|
||||
"value": "/app/serverlogs/slowlogs/mysql-slow-mysql-odms-db-dev-2023111409.log"
|
||||
},
|
||||
"type": "Microsoft.DBforMySQL/flexibleServers/configurations"
|
||||
},
|
||||
|
||||
@ -8,6 +8,9 @@
|
||||
"applicationGateways_agw_odms_webapp_dev_name": {
|
||||
"type": "String"
|
||||
},
|
||||
"networkSecurityGroups_nsg_odms_gateway_dev_name": {
|
||||
"type": "String"
|
||||
},
|
||||
"networkSecurityGroups_nsg_odms_private_dev_name": {
|
||||
"type": "String"
|
||||
},
|
||||
@ -1591,6 +1594,78 @@
|
||||
},
|
||||
"type": "Microsoft.Network/ApplicationGatewayWebApplicationFirewallPolicies"
|
||||
},
|
||||
{
|
||||
"apiVersion": "2023-05-01",
|
||||
"location": "japaneast",
|
||||
"name": "[parameters('networkSecurityGroups_nsg_odms_gateway_dev_name')]",
|
||||
"properties": {
|
||||
"securityRules": [
|
||||
{
|
||||
"id": "[resourceId('Microsoft.Network/networkSecurityGroups/securityRules', parameters('networkSecurityGroups_nsg_odms_gateway_dev_name'), 'AllowTagCustom65200-65535Inbound')]",
|
||||
"name": "AllowTagCustom65200-65535Inbound",
|
||||
"properties": {
|
||||
"access": "Allow",
|
||||
"destinationAddressPrefix": "*",
|
||||
"destinationAddressPrefixes": [],
|
||||
"destinationPortRange": "65200-65535",
|
||||
"destinationPortRanges": [],
|
||||
"direction": "Inbound",
|
||||
"priority": 100,
|
||||
"protocol": "TCP",
|
||||
"sourceAddressPrefix": "GatewayManager",
|
||||
"sourceAddressPrefixes": [],
|
||||
"sourcePortRange": "*",
|
||||
"sourcePortRanges": []
|
||||
},
|
||||
"type": "Microsoft.Network/networkSecurityGroups/securityRules"
|
||||
},
|
||||
{
|
||||
"id": "[resourceId('Microsoft.Network/networkSecurityGroups/securityRules', parameters('networkSecurityGroups_nsg_odms_gateway_dev_name'), 'DenyAnyHTTPSInbound')]",
|
||||
"name": "DenyAnyHTTPSInbound",
|
||||
"properties": {
|
||||
"access": "Deny",
|
||||
"destinationAddressPrefix": "*",
|
||||
"destinationAddressPrefixes": [],
|
||||
"destinationPortRange": "443",
|
||||
"destinationPortRanges": [],
|
||||
"direction": "Inbound",
|
||||
"priority": 1000,
|
||||
"protocol": "TCP",
|
||||
"sourceAddressPrefix": "*",
|
||||
"sourceAddressPrefixes": [],
|
||||
"sourcePortRange": "*",
|
||||
"sourcePortRanges": []
|
||||
},
|
||||
"type": "Microsoft.Network/networkSecurityGroups/securityRules"
|
||||
},
|
||||
{
|
||||
"id": "[resourceId('Microsoft.Network/networkSecurityGroups/securityRules', parameters('networkSecurityGroups_nsg_odms_gateway_dev_name'), 'AllowDeveloperInboundYumoto')]",
|
||||
"name": "AllowDeveloperInboundYumoto",
|
||||
"properties": {
|
||||
"access": "Allow",
|
||||
"description": "開発チーム NDS 湯本の動作確認用",
|
||||
"destinationAddressPrefix": "*",
|
||||
"destinationAddressPrefixes": [],
|
||||
"destinationPortRange": "443",
|
||||
"destinationPortRanges": [],
|
||||
"direction": "Inbound",
|
||||
"priority": 101,
|
||||
"protocol": "TCP",
|
||||
"sourceAddressPrefix": "180.39.76.100",
|
||||
"sourceAddressPrefixes": [],
|
||||
"sourcePortRange": "*",
|
||||
"sourcePortRanges": []
|
||||
},
|
||||
"type": "Microsoft.Network/networkSecurityGroups/securityRules"
|
||||
}
|
||||
]
|
||||
},
|
||||
"tags": {
|
||||
"Environment": "develop",
|
||||
"Project": "ODMS"
|
||||
},
|
||||
"type": "Microsoft.Network/networkSecurityGroups"
|
||||
},
|
||||
{
|
||||
"apiVersion": "2023-05-01",
|
||||
"location": "japaneast",
|
||||
@ -1725,7 +1800,7 @@
|
||||
"maxNumberOfVirtualNetworkLinks": 1000,
|
||||
"maxNumberOfVirtualNetworkLinksWithRegistration": 100,
|
||||
"numberOfRecordSets": 3,
|
||||
"numberOfVirtualNetworkLinks": 0,
|
||||
"numberOfVirtualNetworkLinks": 2,
|
||||
"numberOfVirtualNetworkLinksWithRegistration": 0,
|
||||
"provisioningState": "Succeeded"
|
||||
},
|
||||
@ -1740,7 +1815,7 @@
|
||||
"maxNumberOfVirtualNetworkLinks": 1000,
|
||||
"maxNumberOfVirtualNetworkLinksWithRegistration": 100,
|
||||
"numberOfRecordSets": 2,
|
||||
"numberOfVirtualNetworkLinks": 0,
|
||||
"numberOfVirtualNetworkLinks": 1,
|
||||
"numberOfVirtualNetworkLinksWithRegistration": 0,
|
||||
"provisioningState": "Succeeded"
|
||||
},
|
||||
@ -1755,7 +1830,7 @@
|
||||
"maxNumberOfVirtualNetworkLinks": 1000,
|
||||
"maxNumberOfVirtualNetworkLinksWithRegistration": 100,
|
||||
"numberOfRecordSets": 3,
|
||||
"numberOfVirtualNetworkLinks": 0,
|
||||
"numberOfVirtualNetworkLinks": 2,
|
||||
"numberOfVirtualNetworkLinksWithRegistration": 0,
|
||||
"provisioningState": "Succeeded"
|
||||
},
|
||||
@ -1770,7 +1845,7 @@
|
||||
"maxNumberOfVirtualNetworkLinks": 1000,
|
||||
"maxNumberOfVirtualNetworkLinksWithRegistration": 100,
|
||||
"numberOfRecordSets": 2,
|
||||
"numberOfVirtualNetworkLinks": 0,
|
||||
"numberOfVirtualNetworkLinks": 1,
|
||||
"numberOfVirtualNetworkLinksWithRegistration": 0,
|
||||
"provisioningState": "Succeeded"
|
||||
},
|
||||
@ -1885,6 +1960,51 @@
|
||||
},
|
||||
"type": "Microsoft.Network/networkSecurityGroups/securityRules"
|
||||
},
|
||||
{
|
||||
"apiVersion": "2023-05-01",
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.Network/networkSecurityGroups', parameters('networkSecurityGroups_nsg_odms_gateway_dev_name'))]"
|
||||
],
|
||||
"name": "[concat(parameters('networkSecurityGroups_nsg_odms_gateway_dev_name'), '/AllowDeveloperInboundYumoto')]",
|
||||
"properties": {
|
||||
"access": "Allow",
|
||||
"description": "開発チーム NDS 湯本の動作確認用",
|
||||
"destinationAddressPrefix": "*",
|
||||
"destinationAddressPrefixes": [],
|
||||
"destinationPortRange": "443",
|
||||
"destinationPortRanges": [],
|
||||
"direction": "Inbound",
|
||||
"priority": 101,
|
||||
"protocol": "TCP",
|
||||
"sourceAddressPrefix": "180.39.76.100",
|
||||
"sourceAddressPrefixes": [],
|
||||
"sourcePortRange": "*",
|
||||
"sourcePortRanges": []
|
||||
},
|
||||
"type": "Microsoft.Network/networkSecurityGroups/securityRules"
|
||||
},
|
||||
{
|
||||
"apiVersion": "2023-05-01",
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.Network/networkSecurityGroups', parameters('networkSecurityGroups_nsg_odms_gateway_dev_name'))]"
|
||||
],
|
||||
"name": "[concat(parameters('networkSecurityGroups_nsg_odms_gateway_dev_name'), '/AllowTagCustom65200-65535Inbound')]",
|
||||
"properties": {
|
||||
"access": "Allow",
|
||||
"destinationAddressPrefix": "*",
|
||||
"destinationAddressPrefixes": [],
|
||||
"destinationPortRange": "65200-65535",
|
||||
"destinationPortRanges": [],
|
||||
"direction": "Inbound",
|
||||
"priority": 100,
|
||||
"protocol": "TCP",
|
||||
"sourceAddressPrefix": "GatewayManager",
|
||||
"sourceAddressPrefixes": [],
|
||||
"sourcePortRange": "*",
|
||||
"sourcePortRanges": []
|
||||
},
|
||||
"type": "Microsoft.Network/networkSecurityGroups/securityRules"
|
||||
},
|
||||
{
|
||||
"apiVersion": "2023-05-01",
|
||||
"dependsOn": [
|
||||
@ -1929,6 +2049,28 @@
|
||||
},
|
||||
"type": "Microsoft.Network/networkSecurityGroups/securityRules"
|
||||
},
|
||||
{
|
||||
"apiVersion": "2023-05-01",
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.Network/networkSecurityGroups', parameters('networkSecurityGroups_nsg_odms_gateway_dev_name'))]"
|
||||
],
|
||||
"name": "[concat(parameters('networkSecurityGroups_nsg_odms_gateway_dev_name'), '/DenyAnyHTTPSInbound')]",
|
||||
"properties": {
|
||||
"access": "Deny",
|
||||
"destinationAddressPrefix": "*",
|
||||
"destinationAddressPrefixes": [],
|
||||
"destinationPortRange": "443",
|
||||
"destinationPortRanges": [],
|
||||
"direction": "Inbound",
|
||||
"priority": 1000,
|
||||
"protocol": "TCP",
|
||||
"sourceAddressPrefix": "*",
|
||||
"sourceAddressPrefixes": [],
|
||||
"sourcePortRange": "*",
|
||||
"sourcePortRanges": []
|
||||
},
|
||||
"type": "Microsoft.Network/networkSecurityGroups/securityRules"
|
||||
},
|
||||
{
|
||||
"apiVersion": "2018-09-01",
|
||||
"dependsOn": [
|
||||
@ -8500,6 +8642,22 @@
|
||||
},
|
||||
"type": "Microsoft.OperationalInsights/workspaces/tables"
|
||||
},
|
||||
{
|
||||
"apiVersion": "2021-12-01-preview",
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspaces_log_odms_agw_dev_name'))]"
|
||||
],
|
||||
"name": "[concat(parameters('workspaces_log_odms_agw_dev_name'), '/LASummaryLogs')]",
|
||||
"properties": {
|
||||
"plan": "Analytics",
|
||||
"retentionInDays": 30,
|
||||
"schema": {
|
||||
"name": "LASummaryLogs"
|
||||
},
|
||||
"totalRetentionInDays": 30
|
||||
},
|
||||
"type": "Microsoft.OperationalInsights/workspaces/tables"
|
||||
},
|
||||
{
|
||||
"apiVersion": "2021-12-01-preview",
|
||||
"dependsOn": [
|
||||
@ -10810,40 +10968,6 @@
|
||||
},
|
||||
"type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups"
|
||||
},
|
||||
{
|
||||
"apiVersion": "2023-05-01",
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.Network/virtualNetworks', parameters('virtualNetworks_vnet_odms_network_dev_name'))]",
|
||||
"[resourceId('Microsoft.Network/applicationGateways', parameters('applicationGateways_agw_odms_webapp_dev_name'))]"
|
||||
],
|
||||
"name": "[concat(parameters('virtualNetworks_vnet_odms_network_dev_name'), '/snet-odms-gateway-dev')]",
|
||||
"properties": {
|
||||
"addressPrefix": "10.1.0.0/24",
|
||||
"applicationGatewayIPConfigurations": [
|
||||
{
|
||||
"id": "[concat(resourceId('Microsoft.Network/applicationGateways', parameters('applicationGateways_agw_odms_webapp_dev_name')), '/gatewayIPConfigurations/appGatewayIpConfig')]"
|
||||
}
|
||||
],
|
||||
"delegations": [],
|
||||
"privateEndpointNetworkPolicies": "Disabled",
|
||||
"privateLinkServiceNetworkPolicies": "Enabled",
|
||||
"serviceEndpoints": [
|
||||
{
|
||||
"locations": [
|
||||
"*"
|
||||
],
|
||||
"service": "Microsoft.KeyVault"
|
||||
},
|
||||
{
|
||||
"locations": [
|
||||
"*"
|
||||
],
|
||||
"service": "Microsoft.Web"
|
||||
}
|
||||
]
|
||||
},
|
||||
"type": "Microsoft.Network/virtualNetworks/subnets"
|
||||
},
|
||||
{
|
||||
"apiVersion": "2023-05-01",
|
||||
"dependsOn": [
|
||||
@ -11185,12 +11309,51 @@
|
||||
},
|
||||
"type": "Microsoft.Network/applicationGateways"
|
||||
},
|
||||
{
|
||||
"apiVersion": "2023-05-01",
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.Network/virtualNetworks', parameters('virtualNetworks_vnet_odms_network_dev_name'))]",
|
||||
"[resourceId('Microsoft.Network/networkSecurityGroups', parameters('networkSecurityGroups_nsg_odms_gateway_dev_name'))]",
|
||||
"[resourceId('Microsoft.Network/applicationGateways', parameters('applicationGateways_agw_odms_webapp_dev_name'))]"
|
||||
],
|
||||
"name": "[concat(parameters('virtualNetworks_vnet_odms_network_dev_name'), '/snet-odms-gateway-dev')]",
|
||||
"properties": {
|
||||
"addressPrefix": "10.1.0.0/24",
|
||||
"applicationGatewayIPConfigurations": [
|
||||
{
|
||||
"id": "[concat(resourceId('Microsoft.Network/applicationGateways', parameters('applicationGateways_agw_odms_webapp_dev_name')), '/gatewayIPConfigurations/appGatewayIpConfig')]"
|
||||
}
|
||||
],
|
||||
"delegations": [],
|
||||
"networkSecurityGroup": {
|
||||
"id": "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('networkSecurityGroups_nsg_odms_gateway_dev_name'))]"
|
||||
},
|
||||
"privateEndpointNetworkPolicies": "Disabled",
|
||||
"privateLinkServiceNetworkPolicies": "Enabled",
|
||||
"serviceEndpoints": [
|
||||
{
|
||||
"locations": [
|
||||
"*"
|
||||
],
|
||||
"service": "Microsoft.KeyVault"
|
||||
},
|
||||
{
|
||||
"locations": [
|
||||
"*"
|
||||
],
|
||||
"service": "Microsoft.Web"
|
||||
}
|
||||
]
|
||||
},
|
||||
"type": "Microsoft.Network/virtualNetworks/subnets"
|
||||
},
|
||||
{
|
||||
"apiVersion": "2023-05-01",
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.Network/networkSecurityGroups', parameters('networkSecurityGroups_nsg_odms_public_dev_name'))]",
|
||||
"[resourceId('Microsoft.Network/applicationGateways', parameters('applicationGateways_agw_odms_webapp_dev_name'))]",
|
||||
"[resourceId('Microsoft.Network/networkSecurityGroups', parameters('networkSecurityGroups_nsg_odms_private_dev_name'))]"
|
||||
"[resourceId('Microsoft.Network/networkSecurityGroups', parameters('networkSecurityGroups_nsg_odms_private_dev_name'))]",
|
||||
"[resourceId('Microsoft.Network/networkSecurityGroups', parameters('networkSecurityGroups_nsg_odms_gateway_dev_name'))]",
|
||||
"[resourceId('Microsoft.Network/applicationGateways', parameters('applicationGateways_agw_odms_webapp_dev_name'))]"
|
||||
],
|
||||
"location": "japaneast",
|
||||
"name": "[parameters('virtualNetworks_vnet_odms_network_dev_name')]",
|
||||
@ -11243,36 +11406,6 @@
|
||||
},
|
||||
"type": "Microsoft.Network/virtualNetworks/subnets"
|
||||
},
|
||||
{
|
||||
"id": "[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworks_vnet_odms_network_dev_name'), 'snet-odms-gateway-dev')]",
|
||||
"name": "snet-odms-gateway-dev",
|
||||
"properties": {
|
||||
"addressPrefix": "10.1.0.0/24",
|
||||
"applicationGatewayIPConfigurations": [
|
||||
{
|
||||
"id": "[concat(resourceId('Microsoft.Network/applicationGateways', parameters('applicationGateways_agw_odms_webapp_dev_name')), '/gatewayIPConfigurations/appGatewayIpConfig')]"
|
||||
}
|
||||
],
|
||||
"delegations": [],
|
||||
"privateEndpointNetworkPolicies": "Disabled",
|
||||
"privateLinkServiceNetworkPolicies": "Enabled",
|
||||
"serviceEndpoints": [
|
||||
{
|
||||
"locations": [
|
||||
"*"
|
||||
],
|
||||
"service": "Microsoft.KeyVault"
|
||||
},
|
||||
{
|
||||
"locations": [
|
||||
"*"
|
||||
],
|
||||
"service": "Microsoft.Web"
|
||||
}
|
||||
]
|
||||
},
|
||||
"type": "Microsoft.Network/virtualNetworks/subnets"
|
||||
},
|
||||
{
|
||||
"id": "[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworks_vnet_odms_network_dev_name'), 'snet-odms-private-dev')]",
|
||||
"name": "snet-odms-private-dev",
|
||||
@ -11341,6 +11474,39 @@
|
||||
]
|
||||
},
|
||||
"type": "Microsoft.Network/virtualNetworks/subnets"
|
||||
},
|
||||
{
|
||||
"id": "[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworks_vnet_odms_network_dev_name'), 'snet-odms-gateway-dev')]",
|
||||
"name": "snet-odms-gateway-dev",
|
||||
"properties": {
|
||||
"addressPrefix": "10.1.0.0/24",
|
||||
"applicationGatewayIPConfigurations": [
|
||||
{
|
||||
"id": "[concat(resourceId('Microsoft.Network/applicationGateways', parameters('applicationGateways_agw_odms_webapp_dev_name')), '/gatewayIPConfigurations/appGatewayIpConfig')]"
|
||||
}
|
||||
],
|
||||
"delegations": [],
|
||||
"networkSecurityGroup": {
|
||||
"id": "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('networkSecurityGroups_nsg_odms_gateway_dev_name'))]"
|
||||
},
|
||||
"privateEndpointNetworkPolicies": "Disabled",
|
||||
"privateLinkServiceNetworkPolicies": "Enabled",
|
||||
"serviceEndpoints": [
|
||||
{
|
||||
"locations": [
|
||||
"*"
|
||||
],
|
||||
"service": "Microsoft.KeyVault"
|
||||
},
|
||||
{
|
||||
"locations": [
|
||||
"*"
|
||||
],
|
||||
"service": "Microsoft.Web"
|
||||
}
|
||||
]
|
||||
},
|
||||
"type": "Microsoft.Network/virtualNetworks/subnets"
|
||||
}
|
||||
],
|
||||
"virtualNetworkPeerings": [
|
||||
|
||||
@ -564,6 +564,23 @@
|
||||
},
|
||||
"type": "Microsoft.Storage/storageAccounts/blobServices/containers"
|
||||
},
|
||||
{
|
||||
"apiVersion": "2023-01-01",
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.Storage/storageAccounts/blobServices', parameters('storageAccounts_saodmsaudev_name'), 'default')]",
|
||||
"[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccounts_saodmsaudev_name'))]"
|
||||
],
|
||||
"name": "[concat(parameters('storageAccounts_saodmsaudev_name'), '/default/account-10')]",
|
||||
"properties": {
|
||||
"defaultEncryptionScope": "$account-encryption-key",
|
||||
"denyEncryptionScopeOverride": false,
|
||||
"immutableStorageWithVersioning": {
|
||||
"enabled": false
|
||||
},
|
||||
"publicAccess": "None"
|
||||
},
|
||||
"type": "Microsoft.Storage/storageAccounts/blobServices/containers"
|
||||
},
|
||||
{
|
||||
"apiVersion": "2023-01-01",
|
||||
"dependsOn": [
|
||||
@ -1210,23 +1227,6 @@
|
||||
},
|
||||
"type": "Microsoft.Storage/storageAccounts/blobServices/containers"
|
||||
},
|
||||
{
|
||||
"apiVersion": "2023-01-01",
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.Storage/storageAccounts/blobServices', parameters('storageAccounts_saodmseudev_name'), 'default')]",
|
||||
"[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccounts_saodmseudev_name'))]"
|
||||
],
|
||||
"name": "[concat(parameters('storageAccounts_saodmseudev_name'), '/default/account-63')]",
|
||||
"properties": {
|
||||
"defaultEncryptionScope": "$account-encryption-key",
|
||||
"denyEncryptionScopeOverride": false,
|
||||
"immutableStorageWithVersioning": {
|
||||
"enabled": false
|
||||
},
|
||||
"publicAccess": "None"
|
||||
},
|
||||
"type": "Microsoft.Storage/storageAccounts/blobServices/containers"
|
||||
},
|
||||
{
|
||||
"apiVersion": "2023-01-01",
|
||||
"dependsOn": [
|
||||
@ -1787,6 +1787,57 @@
|
||||
"publicAccess": "None"
|
||||
},
|
||||
"type": "Microsoft.Storage/storageAccounts/blobServices/containers"
|
||||
},
|
||||
{
|
||||
"apiVersion": "2023-01-01",
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.Storage/storageAccounts/blobServices', parameters('storageAccounts_saodmseudev_name'), 'default')]",
|
||||
"[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccounts_saodmseudev_name'))]"
|
||||
],
|
||||
"name": "[concat(parameters('storageAccounts_saodmseudev_name'), '/default/account-92')]",
|
||||
"properties": {
|
||||
"defaultEncryptionScope": "$account-encryption-key",
|
||||
"denyEncryptionScopeOverride": false,
|
||||
"immutableStorageWithVersioning": {
|
||||
"enabled": false
|
||||
},
|
||||
"publicAccess": "None"
|
||||
},
|
||||
"type": "Microsoft.Storage/storageAccounts/blobServices/containers"
|
||||
},
|
||||
{
|
||||
"apiVersion": "2023-01-01",
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.Storage/storageAccounts/blobServices', parameters('storageAccounts_saodmsusdev_name'), 'default')]",
|
||||
"[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccounts_saodmsusdev_name'))]"
|
||||
],
|
||||
"name": "[concat(parameters('storageAccounts_saodmsusdev_name'), '/default/account-93')]",
|
||||
"properties": {
|
||||
"defaultEncryptionScope": "$account-encryption-key",
|
||||
"denyEncryptionScopeOverride": false,
|
||||
"immutableStorageWithVersioning": {
|
||||
"enabled": false
|
||||
},
|
||||
"publicAccess": "None"
|
||||
},
|
||||
"type": "Microsoft.Storage/storageAccounts/blobServices/containers"
|
||||
},
|
||||
{
|
||||
"apiVersion": "2023-01-01",
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.Storage/storageAccounts/blobServices', parameters('storageAccounts_saodmseudev_name'), 'default')]",
|
||||
"[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccounts_saodmseudev_name'))]"
|
||||
],
|
||||
"name": "[concat(parameters('storageAccounts_saodmseudev_name'), '/default/account-94')]",
|
||||
"properties": {
|
||||
"defaultEncryptionScope": "$account-encryption-key",
|
||||
"denyEncryptionScopeOverride": false,
|
||||
"immutableStorageWithVersioning": {
|
||||
"enabled": false
|
||||
},
|
||||
"publicAccess": "None"
|
||||
},
|
||||
"type": "Microsoft.Storage/storageAccounts/blobServices/containers"
|
||||
}
|
||||
],
|
||||
"variables": {}
|
||||
|
||||
@ -11,6 +11,9 @@
|
||||
"networkInterfaces_vm_odms_maintenance600_name": {
|
||||
"type": "String"
|
||||
},
|
||||
"networkInterfaces_vm_odms_prod_maintenance7_name": {
|
||||
"type": "String"
|
||||
},
|
||||
"networkInterfaces_vm_odms_staging_maintenance158_name": {
|
||||
"type": "String"
|
||||
},
|
||||
@ -26,6 +29,12 @@
|
||||
"privateDnsZones_privatelink_azurecr_io_name": {
|
||||
"type": "String"
|
||||
},
|
||||
"privateDnsZones_privatelink_blob_core_windows_net_name": {
|
||||
"type": "String"
|
||||
},
|
||||
"privateEndpoints_pep_odms_bastion_maintenance_name": {
|
||||
"type": "String"
|
||||
},
|
||||
"privateEndpoints_pep_odms_registry_maintenance_name": {
|
||||
"type": "String"
|
||||
},
|
||||
@ -41,6 +50,9 @@
|
||||
"schedules_shutdown_computevm_vm_odms_maintenance_name": {
|
||||
"type": "String"
|
||||
},
|
||||
"schedules_shutdown_computevm_vm_odms_prod_maintenance_name": {
|
||||
"type": "String"
|
||||
},
|
||||
"schedules_shutdown_computevm_vm_odms_staging_maintenance_name": {
|
||||
"type": "String"
|
||||
},
|
||||
@ -50,6 +62,9 @@
|
||||
"storageAccounts_saodmscloudshell_name": {
|
||||
"type": "String"
|
||||
},
|
||||
"storageAccounts_saomdsbastion_name": {
|
||||
"type": "String"
|
||||
},
|
||||
"storageAccounts_saomdspipeline_name": {
|
||||
"type": "String"
|
||||
},
|
||||
@ -62,6 +77,9 @@
|
||||
"virtualMachines_vm_odms_maintenance_name": {
|
||||
"type": "String"
|
||||
},
|
||||
"virtualMachines_vm_odms_prod_maintenance_name": {
|
||||
"type": "String"
|
||||
},
|
||||
"virtualMachines_vm_odms_staging_maintenance_name": {
|
||||
"type": "String"
|
||||
},
|
||||
@ -359,7 +377,7 @@
|
||||
"direction": "Inbound",
|
||||
"priority": 130,
|
||||
"protocol": "TCP",
|
||||
"sourceAddressPrefix": "220.215.171.117",
|
||||
"sourceAddressPrefix": "220.215.248.23",
|
||||
"sourceAddressPrefixes": [],
|
||||
"sourcePortRange": "*",
|
||||
"sourcePortRanges": []
|
||||
@ -821,6 +839,124 @@
|
||||
"sourcePortRanges": []
|
||||
},
|
||||
"type": "Microsoft.Network/networkSecurityGroups/securityRules"
|
||||
},
|
||||
{
|
||||
"id": "[resourceId('Microsoft.Network/networkSecurityGroups/securityRules', parameters('networkSecurityGroups_nsg_odms_vm_maintenance_name'), 'AllowToolInstallerStorageOutbound')]",
|
||||
"name": "AllowToolInstallerStorageOutbound",
|
||||
"properties": {
|
||||
"access": "Allow",
|
||||
"destinationAddressPrefix": "10.0.2.7",
|
||||
"destinationAddressPrefixes": [],
|
||||
"destinationPortRange": "443",
|
||||
"destinationPortRanges": [],
|
||||
"direction": "Outbound",
|
||||
"priority": 1001,
|
||||
"protocol": "TCP",
|
||||
"sourceAddressPrefix": "10.0.2.0/24",
|
||||
"sourceAddressPrefixes": [],
|
||||
"sourcePortRange": "*",
|
||||
"sourcePortRanges": []
|
||||
},
|
||||
"type": "Microsoft.Network/networkSecurityGroups/securityRules"
|
||||
},
|
||||
{
|
||||
"id": "[resourceId('Microsoft.Network/networkSecurityGroups/securityRules', parameters('networkSecurityGroups_nsg_odms_vm_maintenance_name'), 'AllowProdBastionToRedisOutbound')]",
|
||||
"name": "AllowProdBastionToRedisOutbound",
|
||||
"properties": {
|
||||
"access": "Allow",
|
||||
"description": "本番環境踏み台PCから本番環境Redisへのoutbound",
|
||||
"destinationAddressPrefix": "10.3.1.4",
|
||||
"destinationAddressPrefixes": [],
|
||||
"destinationPortRange": "6380",
|
||||
"destinationPortRanges": [],
|
||||
"direction": "Outbound",
|
||||
"priority": 122,
|
||||
"protocol": "TCP",
|
||||
"sourceAddressPrefix": "10.0.2.6",
|
||||
"sourceAddressPrefixes": [],
|
||||
"sourcePortRange": "*",
|
||||
"sourcePortRanges": []
|
||||
},
|
||||
"type": "Microsoft.Network/networkSecurityGroups/securityRules"
|
||||
},
|
||||
{
|
||||
"id": "[resourceId('Microsoft.Network/networkSecurityGroups/securityRules', parameters('networkSecurityGroups_nsg_odms_vm_maintenance_name'), 'AllowDevBastionToRedisOutbound')]",
|
||||
"name": "AllowDevBastionToRedisOutbound",
|
||||
"properties": {
|
||||
"access": "Allow",
|
||||
"description": "DEV環境踏み台PCからDEV環境Redisへのoutbound",
|
||||
"destinationAddressPrefix": "10.1.1.7",
|
||||
"destinationAddressPrefixes": [],
|
||||
"destinationPortRange": "6380",
|
||||
"destinationPortRanges": [],
|
||||
"direction": "Outbound",
|
||||
"priority": 120,
|
||||
"protocol": "TCP",
|
||||
"sourceAddressPrefix": "10.0.2.4",
|
||||
"sourceAddressPrefixes": [],
|
||||
"sourcePortRange": "*",
|
||||
"sourcePortRanges": []
|
||||
},
|
||||
"type": "Microsoft.Network/networkSecurityGroups/securityRules"
|
||||
},
|
||||
{
|
||||
"id": "[resourceId('Microsoft.Network/networkSecurityGroups/securityRules', parameters('networkSecurityGroups_nsg_odms_vm_maintenance_name'), 'AllowStgBastionToRedisOutbound')]",
|
||||
"name": "AllowStgBastionToRedisOutbound",
|
||||
"properties": {
|
||||
"access": "Allow",
|
||||
"description": "STG環境踏み台PCからSTG環境Redisへのoutbound",
|
||||
"destinationAddressPrefix": "10.2.1.7",
|
||||
"destinationAddressPrefixes": [],
|
||||
"destinationPortRange": "6380",
|
||||
"destinationPortRanges": [],
|
||||
"direction": "Outbound",
|
||||
"priority": 121,
|
||||
"protocol": "TCP",
|
||||
"sourceAddressPrefix": "10.0.2.5",
|
||||
"sourceAddressPrefixes": [],
|
||||
"sourcePortRange": "*",
|
||||
"sourcePortRanges": []
|
||||
},
|
||||
"type": "Microsoft.Network/networkSecurityGroups/securityRules"
|
||||
},
|
||||
{
|
||||
"id": "[resourceId('Microsoft.Network/networkSecurityGroups/securityRules', parameters('networkSecurityGroups_nsg_odms_vm_maintenance_name'), 'AllowProdHTTPSOutbound')]",
|
||||
"name": "AllowProdHTTPSOutbound",
|
||||
"properties": {
|
||||
"access": "Allow",
|
||||
"destinationAddressPrefix": "AzureActiveDirectory",
|
||||
"destinationAddressPrefixes": [],
|
||||
"destinationPortRange": "443",
|
||||
"destinationPortRanges": [],
|
||||
"direction": "Outbound",
|
||||
"priority": 112,
|
||||
"protocol": "TCP",
|
||||
"sourceAddressPrefix": "10.0.2.6",
|
||||
"sourceAddressPrefixes": [],
|
||||
"sourcePortRange": "*",
|
||||
"sourcePortRanges": []
|
||||
},
|
||||
"type": "Microsoft.Network/networkSecurityGroups/securityRules"
|
||||
},
|
||||
{
|
||||
"id": "[resourceId('Microsoft.Network/networkSecurityGroups/securityRules', parameters('networkSecurityGroups_nsg_odms_vm_maintenance_name'), 'AllowProdAppOutbound')]",
|
||||
"name": "AllowProdAppOutbound",
|
||||
"properties": {
|
||||
"access": "Allow",
|
||||
"description": "PROD踏み台からPROD環境へのアクセスを許可",
|
||||
"destinationAddressPrefix": "10.3.0.10",
|
||||
"destinationAddressPrefixes": [],
|
||||
"destinationPortRange": "4443",
|
||||
"destinationPortRanges": [],
|
||||
"direction": "Outbound",
|
||||
"priority": 113,
|
||||
"protocol": "TCP",
|
||||
"sourceAddressPrefix": "10.0.2.6",
|
||||
"sourceAddressPrefixes": [],
|
||||
"sourcePortRange": "*",
|
||||
"sourcePortRanges": []
|
||||
},
|
||||
"type": "Microsoft.Network/networkSecurityGroups/securityRules"
|
||||
}
|
||||
]
|
||||
},
|
||||
@ -849,6 +985,21 @@
|
||||
},
|
||||
"type": "Microsoft.Network/privateDnsZones"
|
||||
},
|
||||
{
|
||||
"apiVersion": "2018-09-01",
|
||||
"location": "global",
|
||||
"name": "[parameters('privateDnsZones_privatelink_blob_core_windows_net_name')]",
|
||||
"properties": {
|
||||
"maxNumberOfRecordSets": 25000,
|
||||
"maxNumberOfVirtualNetworkLinks": 1000,
|
||||
"maxNumberOfVirtualNetworkLinksWithRegistration": 100,
|
||||
"numberOfRecordSets": 2,
|
||||
"numberOfVirtualNetworkLinks": 1,
|
||||
"numberOfVirtualNetworkLinksWithRegistration": 0,
|
||||
"provisioningState": "Succeeded"
|
||||
},
|
||||
"type": "Microsoft.Network/privateDnsZones"
|
||||
},
|
||||
{
|
||||
"apiVersion": "2023-05-01",
|
||||
"location": "japaneast",
|
||||
@ -930,6 +1081,58 @@
|
||||
},
|
||||
"type": "Microsoft.Storage/storageAccounts"
|
||||
},
|
||||
{
|
||||
"apiVersion": "2023-01-01",
|
||||
"kind": "StorageV2",
|
||||
"location": "japaneast",
|
||||
"name": "[parameters('storageAccounts_saomdsbastion_name')]",
|
||||
"properties": {
|
||||
"accessTier": "Hot",
|
||||
"allowBlobPublicAccess": false,
|
||||
"allowCrossTenantReplication": false,
|
||||
"allowSharedKeyAccess": true,
|
||||
"defaultToOAuthAuthentication": false,
|
||||
"dnsEndpointType": "Standard",
|
||||
"encryption": {
|
||||
"keySource": "Microsoft.Storage",
|
||||
"requireInfrastructureEncryption": true,
|
||||
"services": {
|
||||
"blob": {
|
||||
"enabled": true,
|
||||
"keyType": "Account"
|
||||
},
|
||||
"file": {
|
||||
"enabled": true,
|
||||
"keyType": "Account"
|
||||
}
|
||||
}
|
||||
},
|
||||
"minimumTlsVersion": "TLS1_2",
|
||||
"networkAcls": {
|
||||
"bypass": "AzureServices",
|
||||
"defaultAction": "Deny",
|
||||
"ipRules": [
|
||||
{
|
||||
"action": "Allow",
|
||||
"value": "180.39.76.100"
|
||||
}
|
||||
],
|
||||
"resourceAccessRules": [],
|
||||
"virtualNetworkRules": []
|
||||
},
|
||||
"publicNetworkAccess": "Enabled",
|
||||
"supportsHttpsTrafficOnly": true
|
||||
},
|
||||
"sku": {
|
||||
"name": "Standard_LRS",
|
||||
"tier": "Standard"
|
||||
},
|
||||
"tags": {
|
||||
"Environment": "maintenance",
|
||||
"Project": "ODMS"
|
||||
},
|
||||
"type": "Microsoft.Storage/storageAccounts"
|
||||
},
|
||||
{
|
||||
"apiVersion": "2023-01-01",
|
||||
"kind": "StorageV2",
|
||||
@ -1136,6 +1339,80 @@
|
||||
},
|
||||
"type": "Microsoft.Compute/virtualMachines"
|
||||
},
|
||||
{
|
||||
"apiVersion": "2023-03-01",
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.Network/networkInterfaces', parameters('networkInterfaces_vm_odms_prod_maintenance7_name'))]"
|
||||
],
|
||||
"location": "japaneast",
|
||||
"name": "[parameters('virtualMachines_vm_odms_prod_maintenance_name')]",
|
||||
"properties": {
|
||||
"diagnosticsProfile": {
|
||||
"bootDiagnostics": {
|
||||
"enabled": true
|
||||
}
|
||||
},
|
||||
"hardwareProfile": {
|
||||
"vmSize": "Standard_B2s"
|
||||
},
|
||||
"networkProfile": {
|
||||
"networkInterfaces": [
|
||||
{
|
||||
"id": "[resourceId('Microsoft.Network/networkInterfaces', parameters('networkInterfaces_vm_odms_prod_maintenance7_name'))]"
|
||||
}
|
||||
]
|
||||
},
|
||||
"osProfile": {
|
||||
"adminUsername": "odmsAdmin",
|
||||
"allowExtensionOperations": true,
|
||||
"computerName": "vm-odms-prod-ma",
|
||||
"requireGuestProvisionSignal": true,
|
||||
"secrets": [],
|
||||
"windowsConfiguration": {
|
||||
"enableAutomaticUpdates": true,
|
||||
"enableVMAgentPlatformUpdates": false,
|
||||
"patchSettings": {
|
||||
"assessmentMode": "ImageDefault",
|
||||
"enableHotpatching": false,
|
||||
"patchMode": "AutomaticByOS"
|
||||
},
|
||||
"provisionVMAgent": true
|
||||
}
|
||||
},
|
||||
"securityProfile": {
|
||||
"securityType": "TrustedLaunch",
|
||||
"uefiSettings": {
|
||||
"secureBootEnabled": true,
|
||||
"vTpmEnabled": true
|
||||
}
|
||||
},
|
||||
"storageProfile": {
|
||||
"dataDisks": [],
|
||||
"diskControllerType": "SCSI",
|
||||
"imageReference": {
|
||||
"offer": "WindowsServer",
|
||||
"publisher": "MicrosoftWindowsServer",
|
||||
"sku": "2022-datacenter-azure-edition",
|
||||
"version": "latest"
|
||||
},
|
||||
"osDisk": {
|
||||
"caching": "ReadWrite",
|
||||
"createOption": "FromImage",
|
||||
"deleteOption": "Delete",
|
||||
"managedDisk": {
|
||||
"id": "[resourceId('Microsoft.Compute/disks', concat(parameters('virtualMachines_vm_odms_prod_maintenance_name'), '_OsDisk_1_89b0ffad76d44d57a136152577e01483'))]"
|
||||
},
|
||||
"name": "[concat(parameters('virtualMachines_vm_odms_prod_maintenance_name'), '_OsDisk_1_89b0ffad76d44d57a136152577e01483')]",
|
||||
"osType": "Windows"
|
||||
}
|
||||
}
|
||||
},
|
||||
"tags": {
|
||||
"Environment": "production",
|
||||
"Project": "ODMS"
|
||||
},
|
||||
"type": "Microsoft.Compute/virtualMachines"
|
||||
},
|
||||
{
|
||||
"apiVersion": "2023-03-01",
|
||||
"dependsOn": [
|
||||
@ -1199,10 +1476,8 @@
|
||||
"caching": "ReadWrite",
|
||||
"createOption": "FromImage",
|
||||
"deleteOption": "Delete",
|
||||
"diskSizeGB": 127,
|
||||
"managedDisk": {
|
||||
"id": "[resourceId('Microsoft.Compute/disks', concat(parameters('virtualMachines_vm_odms_staging_maintenance_name'), '_OsDisk_1_903a7540b5a64475b512aedc10487661'))]",
|
||||
"storageAccountType": "Premium_LRS"
|
||||
"id": "[resourceId('Microsoft.Compute/disks', concat(parameters('virtualMachines_vm_odms_staging_maintenance_name'), '_OsDisk_1_903a7540b5a64475b512aedc10487661'))]"
|
||||
},
|
||||
"name": "[concat(parameters('virtualMachines_vm_odms_staging_maintenance_name'), '_OsDisk_1_903a7540b5a64475b512aedc10487661')]",
|
||||
"osType": "Windows"
|
||||
@ -1402,6 +1677,33 @@
|
||||
},
|
||||
"type": "microsoft.devtestlab/schedules"
|
||||
},
|
||||
{
|
||||
"apiVersion": "2018-09-15",
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.Compute/virtualMachines', parameters('virtualMachines_vm_odms_prod_maintenance_name'))]"
|
||||
],
|
||||
"location": "japaneast",
|
||||
"name": "[parameters('schedules_shutdown_computevm_vm_odms_prod_maintenance_name')]",
|
||||
"properties": {
|
||||
"dailyRecurrence": {
|
||||
"time": "1900"
|
||||
},
|
||||
"notificationSettings": {
|
||||
"notificationLocale": "ja",
|
||||
"status": "Disabled",
|
||||
"timeInMinutes": 30
|
||||
},
|
||||
"status": "Enabled",
|
||||
"targetResourceId": "[resourceId('Microsoft.Compute/virtualMachines', parameters('virtualMachines_vm_odms_prod_maintenance_name'))]",
|
||||
"taskType": "ComputeVmShutdownTask",
|
||||
"timeZoneId": "Tokyo Standard Time"
|
||||
},
|
||||
"tags": {
|
||||
"Environment": "production",
|
||||
"Project": "ODMS"
|
||||
},
|
||||
"type": "microsoft.devtestlab/schedules"
|
||||
},
|
||||
{
|
||||
"apiVersion": "2018-09-15",
|
||||
"dependsOn": [
|
||||
@ -1507,7 +1809,7 @@
|
||||
"enableIPForwarding": false,
|
||||
"ipConfigurations": [
|
||||
{
|
||||
"etag": "W/\"0f027839-4941-4a48-a05c-b0f240513f07\"",
|
||||
"etag": "W/\"7a9501b8-2c41-4e35-8622-46c24a6baa0d\"",
|
||||
"id": "[concat(resourceId('Microsoft.Network/networkInterfaces', parameters('networkInterfaces_vm_odms_maintenance600_name')), '/ipConfigurations/ipconfig1')]",
|
||||
"name": "ipconfig1",
|
||||
"properties": {
|
||||
@ -1531,6 +1833,49 @@
|
||||
},
|
||||
"type": "Microsoft.Network/networkInterfaces"
|
||||
},
|
||||
{
|
||||
"apiVersion": "2023-05-01",
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworks_vnet_odms_network_maintenance_name'), 'snet-odms-vm-maintenance')]"
|
||||
],
|
||||
"kind": "Regular",
|
||||
"location": "japaneast",
|
||||
"name": "[parameters('networkInterfaces_vm_odms_prod_maintenance7_name')]",
|
||||
"properties": {
|
||||
"auxiliaryMode": "None",
|
||||
"auxiliarySku": "None",
|
||||
"disableTcpStateTracking": false,
|
||||
"dnsSettings": {
|
||||
"dnsServers": []
|
||||
},
|
||||
"enableAcceleratedNetworking": false,
|
||||
"enableIPForwarding": false,
|
||||
"ipConfigurations": [
|
||||
{
|
||||
"etag": "W/\"2e09acfb-738c-4282-80b6-c0d107ba3ac3\"",
|
||||
"id": "[concat(resourceId('Microsoft.Network/networkInterfaces', parameters('networkInterfaces_vm_odms_prod_maintenance7_name')), '/ipConfigurations/ipconfig1')]",
|
||||
"name": "ipconfig1",
|
||||
"properties": {
|
||||
"primary": true,
|
||||
"privateIPAddress": "10.0.2.6",
|
||||
"privateIPAddressVersion": "IPv4",
|
||||
"privateIPAllocationMethod": "Dynamic",
|
||||
"provisioningState": "Succeeded",
|
||||
"subnet": {
|
||||
"id": "[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworks_vnet_odms_network_maintenance_name'), 'snet-odms-vm-maintenance')]"
|
||||
}
|
||||
},
|
||||
"type": "Microsoft.Network/networkInterfaces/ipConfigurations"
|
||||
}
|
||||
],
|
||||
"nicType": "Standard"
|
||||
},
|
||||
"tags": {
|
||||
"Environment": "production",
|
||||
"Project": "ODMS"
|
||||
},
|
||||
"type": "Microsoft.Network/networkInterfaces"
|
||||
},
|
||||
{
|
||||
"apiVersion": "2023-05-01",
|
||||
"dependsOn": [
|
||||
@ -1550,7 +1895,7 @@
|
||||
"enableIPForwarding": false,
|
||||
"ipConfigurations": [
|
||||
{
|
||||
"etag": "W/\"94c366ab-a94a-4393-b858-aefb939b6fc9\"",
|
||||
"etag": "W/\"d3adbed2-54d6-431d-b056-a9393f6021c3\"",
|
||||
"id": "[concat(resourceId('Microsoft.Network/networkInterfaces', parameters('networkInterfaces_vm_odms_staging_maintenance158_name')), '/ipConfigurations/ipconfig1')]",
|
||||
"name": "ipconfig1",
|
||||
"properties": {
|
||||
@ -1733,6 +2078,29 @@
|
||||
},
|
||||
"type": "Microsoft.Network/networkSecurityGroups/securityRules"
|
||||
},
|
||||
{
|
||||
"apiVersion": "2023-05-01",
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.Network/networkSecurityGroups', parameters('networkSecurityGroups_nsg_odms_vm_maintenance_name'))]"
|
||||
],
|
||||
"name": "[concat(parameters('networkSecurityGroups_nsg_odms_vm_maintenance_name'), '/AllowDevBastionToRedisOutbound')]",
|
||||
"properties": {
|
||||
"access": "Allow",
|
||||
"description": "DEV環境踏み台PCからDEV環境Redisへのoutbound",
|
||||
"destinationAddressPrefix": "10.1.1.7",
|
||||
"destinationAddressPrefixes": [],
|
||||
"destinationPortRange": "6380",
|
||||
"destinationPortRanges": [],
|
||||
"direction": "Outbound",
|
||||
"priority": 120,
|
||||
"protocol": "TCP",
|
||||
"sourceAddressPrefix": "10.0.2.4",
|
||||
"sourceAddressPrefixes": [],
|
||||
"sourcePortRange": "*",
|
||||
"sourcePortRanges": []
|
||||
},
|
||||
"type": "Microsoft.Network/networkSecurityGroups/securityRules"
|
||||
},
|
||||
{
|
||||
"apiVersion": "2023-05-01",
|
||||
"dependsOn": [
|
||||
@ -1948,7 +2316,7 @@
|
||||
"direction": "Inbound",
|
||||
"priority": 130,
|
||||
"protocol": "TCP",
|
||||
"sourceAddressPrefix": "220.215.171.117",
|
||||
"sourceAddressPrefix": "220.215.248.23",
|
||||
"sourceAddressPrefixes": [],
|
||||
"sourcePortRange": "*",
|
||||
"sourcePortRanges": []
|
||||
@ -1977,6 +2345,74 @@
|
||||
},
|
||||
"type": "Microsoft.Network/networkSecurityGroups/securityRules"
|
||||
},
|
||||
{
|
||||
"apiVersion": "2023-05-01",
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.Network/networkSecurityGroups', parameters('networkSecurityGroups_nsg_odms_vm_maintenance_name'))]"
|
||||
],
|
||||
"name": "[concat(parameters('networkSecurityGroups_nsg_odms_vm_maintenance_name'), '/AllowProdAppOutbound')]",
|
||||
"properties": {
|
||||
"access": "Allow",
|
||||
"description": "PROD踏み台からPROD環境へのアクセスを許可",
|
||||
"destinationAddressPrefix": "10.3.0.10",
|
||||
"destinationAddressPrefixes": [],
|
||||
"destinationPortRange": "4443",
|
||||
"destinationPortRanges": [],
|
||||
"direction": "Outbound",
|
||||
"priority": 113,
|
||||
"protocol": "TCP",
|
||||
"sourceAddressPrefix": "10.0.2.6",
|
||||
"sourceAddressPrefixes": [],
|
||||
"sourcePortRange": "*",
|
||||
"sourcePortRanges": []
|
||||
},
|
||||
"type": "Microsoft.Network/networkSecurityGroups/securityRules"
|
||||
},
|
||||
{
|
||||
"apiVersion": "2023-05-01",
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.Network/networkSecurityGroups', parameters('networkSecurityGroups_nsg_odms_vm_maintenance_name'))]"
|
||||
],
|
||||
"name": "[concat(parameters('networkSecurityGroups_nsg_odms_vm_maintenance_name'), '/AllowProdBastionToRedisOutbound')]",
|
||||
"properties": {
|
||||
"access": "Allow",
|
||||
"description": "本番環境踏み台PCから本番環境Redisへのoutbound",
|
||||
"destinationAddressPrefix": "10.3.1.4",
|
||||
"destinationAddressPrefixes": [],
|
||||
"destinationPortRange": "6380",
|
||||
"destinationPortRanges": [],
|
||||
"direction": "Outbound",
|
||||
"priority": 122,
|
||||
"protocol": "TCP",
|
||||
"sourceAddressPrefix": "10.0.2.6",
|
||||
"sourceAddressPrefixes": [],
|
||||
"sourcePortRange": "*",
|
||||
"sourcePortRanges": []
|
||||
},
|
||||
"type": "Microsoft.Network/networkSecurityGroups/securityRules"
|
||||
},
|
||||
{
|
||||
"apiVersion": "2023-05-01",
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.Network/networkSecurityGroups', parameters('networkSecurityGroups_nsg_odms_vm_maintenance_name'))]"
|
||||
],
|
||||
"name": "[concat(parameters('networkSecurityGroups_nsg_odms_vm_maintenance_name'), '/AllowProdHTTPSOutbound')]",
|
||||
"properties": {
|
||||
"access": "Allow",
|
||||
"destinationAddressPrefix": "AzureActiveDirectory",
|
||||
"destinationAddressPrefixes": [],
|
||||
"destinationPortRange": "443",
|
||||
"destinationPortRanges": [],
|
||||
"direction": "Outbound",
|
||||
"priority": 112,
|
||||
"protocol": "TCP",
|
||||
"sourceAddressPrefix": "10.0.2.6",
|
||||
"sourceAddressPrefixes": [],
|
||||
"sourcePortRange": "*",
|
||||
"sourcePortRanges": []
|
||||
},
|
||||
"type": "Microsoft.Network/networkSecurityGroups/securityRules"
|
||||
},
|
||||
{
|
||||
"apiVersion": "2023-05-01",
|
||||
"dependsOn": [
|
||||
@ -2046,6 +2482,29 @@
|
||||
},
|
||||
"type": "Microsoft.Network/networkSecurityGroups/securityRules"
|
||||
},
|
||||
{
|
||||
"apiVersion": "2023-05-01",
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.Network/networkSecurityGroups', parameters('networkSecurityGroups_nsg_odms_vm_maintenance_name'))]"
|
||||
],
|
||||
"name": "[concat(parameters('networkSecurityGroups_nsg_odms_vm_maintenance_name'), '/AllowStgBastionToRedisOutbound')]",
|
||||
"properties": {
|
||||
"access": "Allow",
|
||||
"description": "STG環境踏み台PCからSTG環境Redisへのoutbound",
|
||||
"destinationAddressPrefix": "10.2.1.7",
|
||||
"destinationAddressPrefixes": [],
|
||||
"destinationPortRange": "6380",
|
||||
"destinationPortRanges": [],
|
||||
"direction": "Outbound",
|
||||
"priority": 121,
|
||||
"protocol": "TCP",
|
||||
"sourceAddressPrefix": "10.0.2.5",
|
||||
"sourceAddressPrefixes": [],
|
||||
"sourcePortRange": "*",
|
||||
"sourcePortRanges": []
|
||||
},
|
||||
"type": "Microsoft.Network/networkSecurityGroups/securityRules"
|
||||
},
|
||||
{
|
||||
"apiVersion": "2023-05-01",
|
||||
"dependsOn": [
|
||||
@ -2137,6 +2596,28 @@
|
||||
},
|
||||
"type": "Microsoft.Network/networkSecurityGroups/securityRules"
|
||||
},
|
||||
{
|
||||
"apiVersion": "2023-05-01",
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.Network/networkSecurityGroups', parameters('networkSecurityGroups_nsg_odms_vm_maintenance_name'))]"
|
||||
],
|
||||
"name": "[concat(parameters('networkSecurityGroups_nsg_odms_vm_maintenance_name'), '/AllowToolInstallerStorageOutbound')]",
|
||||
"properties": {
|
||||
"access": "Allow",
|
||||
"destinationAddressPrefix": "10.0.2.7",
|
||||
"destinationAddressPrefixes": [],
|
||||
"destinationPortRange": "443",
|
||||
"destinationPortRanges": [],
|
||||
"direction": "Outbound",
|
||||
"priority": 1001,
|
||||
"protocol": "TCP",
|
||||
"sourceAddressPrefix": "10.0.2.0/24",
|
||||
"sourceAddressPrefixes": [],
|
||||
"sourcePortRange": "*",
|
||||
"sourcePortRanges": []
|
||||
},
|
||||
"type": "Microsoft.Network/networkSecurityGroups/securityRules"
|
||||
},
|
||||
{
|
||||
"apiVersion": "2023-05-01",
|
||||
"dependsOn": [
|
||||
@ -2309,6 +2790,22 @@
|
||||
},
|
||||
"type": "Microsoft.Network/privateDnsZones/A"
|
||||
},
|
||||
{
|
||||
"apiVersion": "2018-09-01",
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.Network/privateDnsZones', parameters('privateDnsZones_privatelink_blob_core_windows_net_name'))]"
|
||||
],
|
||||
"name": "[concat(parameters('privateDnsZones_privatelink_blob_core_windows_net_name'), '/saomdsbastion')]",
|
||||
"properties": {
|
||||
"aRecords": [
|
||||
{
|
||||
"ipv4Address": "10.0.2.7"
|
||||
}
|
||||
],
|
||||
"ttl": 3600
|
||||
},
|
||||
"type": "Microsoft.Network/privateDnsZones/A"
|
||||
},
|
||||
{
|
||||
"apiVersion": "2018-09-01",
|
||||
"dependsOn": [
|
||||
@ -2329,6 +2826,26 @@
|
||||
},
|
||||
"type": "Microsoft.Network/privateDnsZones/SOA"
|
||||
},
|
||||
{
|
||||
"apiVersion": "2018-09-01",
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.Network/privateDnsZones', parameters('privateDnsZones_privatelink_blob_core_windows_net_name'))]"
|
||||
],
|
||||
"name": "[concat(parameters('privateDnsZones_privatelink_blob_core_windows_net_name'), '/@')]",
|
||||
"properties": {
|
||||
"soaRecord": {
|
||||
"email": "azureprivatedns-host.microsoft.com",
|
||||
"expireTime": 2419200,
|
||||
"host": "azureprivatedns.net",
|
||||
"minimumTtl": 10,
|
||||
"refreshTime": 3600,
|
||||
"retryTime": 300,
|
||||
"serialNumber": 1
|
||||
},
|
||||
"ttl": 3600
|
||||
},
|
||||
"type": "Microsoft.Network/privateDnsZones/SOA"
|
||||
},
|
||||
{
|
||||
"apiVersion": "2018-09-01",
|
||||
"dependsOn": [
|
||||
@ -2507,6 +3024,39 @@
|
||||
},
|
||||
"type": "Microsoft.Storage/storageAccounts/blobServices"
|
||||
},
|
||||
{
|
||||
"apiVersion": "2023-01-01",
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccounts_saomdsbastion_name'))]"
|
||||
],
|
||||
"name": "[concat(parameters('storageAccounts_saomdsbastion_name'), '/default')]",
|
||||
"properties": {
|
||||
"changeFeed": {
|
||||
"enabled": false
|
||||
},
|
||||
"containerDeleteRetentionPolicy": {
|
||||
"days": 7,
|
||||
"enabled": true
|
||||
},
|
||||
"cors": {
|
||||
"corsRules": []
|
||||
},
|
||||
"deleteRetentionPolicy": {
|
||||
"allowPermanentDelete": false,
|
||||
"days": 7,
|
||||
"enabled": true
|
||||
},
|
||||
"isVersioningEnabled": true,
|
||||
"restorePolicy": {
|
||||
"enabled": false
|
||||
}
|
||||
},
|
||||
"sku": {
|
||||
"name": "Standard_LRS",
|
||||
"tier": "Standard"
|
||||
},
|
||||
"type": "Microsoft.Storage/storageAccounts/blobServices"
|
||||
},
|
||||
{
|
||||
"apiVersion": "2023-01-01",
|
||||
"dependsOn": [
|
||||
@ -2564,6 +3114,30 @@
|
||||
},
|
||||
"type": "Microsoft.Storage/storageAccounts/fileServices"
|
||||
},
|
||||
{
|
||||
"apiVersion": "2023-01-01",
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccounts_saomdsbastion_name'))]"
|
||||
],
|
||||
"name": "[concat(parameters('storageAccounts_saomdsbastion_name'), '/default')]",
|
||||
"properties": {
|
||||
"cors": {
|
||||
"corsRules": []
|
||||
},
|
||||
"protocolSettings": {
|
||||
"smb": {}
|
||||
},
|
||||
"shareDeleteRetentionPolicy": {
|
||||
"days": 7,
|
||||
"enabled": true
|
||||
}
|
||||
},
|
||||
"sku": {
|
||||
"name": "Standard_LRS",
|
||||
"tier": "Standard"
|
||||
},
|
||||
"type": "Microsoft.Storage/storageAccounts/fileServices"
|
||||
},
|
||||
{
|
||||
"apiVersion": "2023-01-01",
|
||||
"dependsOn": [
|
||||
@ -2588,6 +3162,23 @@
|
||||
},
|
||||
"type": "Microsoft.Storage/storageAccounts/fileServices"
|
||||
},
|
||||
{
|
||||
"apiVersion": "2023-01-01",
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccounts_saomdsbastion_name'))]"
|
||||
],
|
||||
"name": "[concat(parameters('storageAccounts_saomdsbastion_name'), '/', parameters('storageAccounts_saomdsbastion_name'), '.9d0044b4-3ec4-4ef1-9c5f-dee9d7e813fb')]",
|
||||
"properties": {
|
||||
"privateEndpoint": {},
|
||||
"privateLinkServiceConnectionState": {
|
||||
"actionRequired": "None",
|
||||
"description": "Auto-Approved",
|
||||
"status": "Approved"
|
||||
},
|
||||
"provisioningState": "Succeeded"
|
||||
},
|
||||
"type": "Microsoft.Storage/storageAccounts/privateEndpointConnections"
|
||||
},
|
||||
{
|
||||
"apiVersion": "2023-01-01",
|
||||
"dependsOn": [
|
||||
@ -2601,6 +3192,19 @@
|
||||
},
|
||||
"type": "Microsoft.Storage/storageAccounts/queueServices"
|
||||
},
|
||||
{
|
||||
"apiVersion": "2023-01-01",
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccounts_saomdsbastion_name'))]"
|
||||
],
|
||||
"name": "[concat(parameters('storageAccounts_saomdsbastion_name'), '/default')]",
|
||||
"properties": {
|
||||
"cors": {
|
||||
"corsRules": []
|
||||
}
|
||||
},
|
||||
"type": "Microsoft.Storage/storageAccounts/queueServices"
|
||||
},
|
||||
{
|
||||
"apiVersion": "2023-01-01",
|
||||
"dependsOn": [
|
||||
@ -2627,6 +3231,19 @@
|
||||
},
|
||||
"type": "Microsoft.Storage/storageAccounts/tableServices"
|
||||
},
|
||||
{
|
||||
"apiVersion": "2023-01-01",
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccounts_saomdsbastion_name'))]"
|
||||
],
|
||||
"name": "[concat(parameters('storageAccounts_saomdsbastion_name'), '/default')]",
|
||||
"properties": {
|
||||
"cors": {
|
||||
"corsRules": []
|
||||
}
|
||||
},
|
||||
"type": "Microsoft.Storage/storageAccounts/tableServices"
|
||||
},
|
||||
{
|
||||
"apiVersion": "2023-01-01",
|
||||
"dependsOn": [
|
||||
@ -2715,6 +3332,68 @@
|
||||
},
|
||||
"type": "Microsoft.Network/privateDnsZones/virtualNetworkLinks"
|
||||
},
|
||||
{
|
||||
"apiVersion": "2018-09-01",
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.Network/privateDnsZones', parameters('privateDnsZones_privatelink_blob_core_windows_net_name'))]",
|
||||
"[resourceId('Microsoft.Network/virtualNetworks', parameters('virtualNetworks_vnet_odms_network_maintenance_name'))]"
|
||||
],
|
||||
"location": "global",
|
||||
"name": "[concat(parameters('privateDnsZones_privatelink_blob_core_windows_net_name'), '/e3fkm7ajqovu6')]",
|
||||
"properties": {
|
||||
"registrationEnabled": false,
|
||||
"virtualNetwork": {
|
||||
"id": "[resourceId('Microsoft.Network/virtualNetworks', parameters('virtualNetworks_vnet_odms_network_maintenance_name'))]"
|
||||
}
|
||||
},
|
||||
"type": "Microsoft.Network/privateDnsZones/virtualNetworkLinks"
|
||||
},
|
||||
{
|
||||
"apiVersion": "2023-05-01",
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccounts_saomdsbastion_name'))]",
|
||||
"[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworks_vnet_odms_network_maintenance_name'), 'snet-odms-vm-maintenance')]"
|
||||
],
|
||||
"location": "japaneast",
|
||||
"name": "[parameters('privateEndpoints_pep_odms_bastion_maintenance_name')]",
|
||||
"properties": {
|
||||
"customDnsConfigs": [
|
||||
{
|
||||
"fqdn": "saomdsbastion.blob.core.windows.net",
|
||||
"ipAddresses": [
|
||||
"10.0.2.7"
|
||||
]
|
||||
}
|
||||
],
|
||||
"ipConfigurations": [],
|
||||
"manualPrivateLinkServiceConnections": [],
|
||||
"privateLinkServiceConnections": [
|
||||
{
|
||||
"id": "[concat(resourceId('Microsoft.Network/privateEndpoints', parameters('privateEndpoints_pep_odms_bastion_maintenance_name')), concat('/privateLinkServiceConnections/', parameters('privateEndpoints_pep_odms_bastion_maintenance_name'), '_ac9d69cb-cf72-4b78-8163-0d902150b027'))]",
|
||||
"name": "[concat(parameters('privateEndpoints_pep_odms_bastion_maintenance_name'), '_ac9d69cb-cf72-4b78-8163-0d902150b027')]",
|
||||
"properties": {
|
||||
"groupIds": [
|
||||
"blob"
|
||||
],
|
||||
"privateLinkServiceConnectionState": {
|
||||
"actionsRequired": "None",
|
||||
"description": "Auto-Approved",
|
||||
"status": "Approved"
|
||||
},
|
||||
"privateLinkServiceId": "[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccounts_saomdsbastion_name'))]"
|
||||
}
|
||||
}
|
||||
],
|
||||
"subnet": {
|
||||
"id": "[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworks_vnet_odms_network_maintenance_name'), 'snet-odms-vm-maintenance')]"
|
||||
}
|
||||
},
|
||||
"tags": {
|
||||
"Environment": "maintenance",
|
||||
"Project": "ODMS"
|
||||
},
|
||||
"type": "Microsoft.Network/privateEndpoints"
|
||||
},
|
||||
{
|
||||
"apiVersion": "2023-05-01",
|
||||
"dependsOn": [
|
||||
@ -2838,6 +3517,40 @@
|
||||
},
|
||||
"type": "Microsoft.Network/virtualNetworks/subnets"
|
||||
},
|
||||
{
|
||||
"apiVersion": "2023-01-01",
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.Storage/storageAccounts/blobServices', parameters('storageAccounts_saomdsbastion_name'), 'default')]",
|
||||
"[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccounts_saomdsbastion_name'))]"
|
||||
],
|
||||
"name": "[concat(parameters('storageAccounts_saomdsbastion_name'), '/default/develop')]",
|
||||
"properties": {
|
||||
"defaultEncryptionScope": "$account-encryption-key",
|
||||
"denyEncryptionScopeOverride": false,
|
||||
"immutableStorageWithVersioning": {
|
||||
"enabled": false
|
||||
},
|
||||
"publicAccess": "None"
|
||||
},
|
||||
"type": "Microsoft.Storage/storageAccounts/blobServices/containers"
|
||||
},
|
||||
{
|
||||
"apiVersion": "2023-01-01",
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.Storage/storageAccounts/blobServices', parameters('storageAccounts_saomdsbastion_name'), 'default')]",
|
||||
"[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccounts_saomdsbastion_name'))]"
|
||||
],
|
||||
"name": "[concat(parameters('storageAccounts_saomdsbastion_name'), '/default/prod')]",
|
||||
"properties": {
|
||||
"defaultEncryptionScope": "$account-encryption-key",
|
||||
"denyEncryptionScopeOverride": false,
|
||||
"immutableStorageWithVersioning": {
|
||||
"enabled": false
|
||||
},
|
||||
"publicAccess": "None"
|
||||
},
|
||||
"type": "Microsoft.Storage/storageAccounts/blobServices/containers"
|
||||
},
|
||||
{
|
||||
"apiVersion": "2023-01-01",
|
||||
"dependsOn": [
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -49,8 +49,8 @@
|
||||
"version": "8.0.21"
|
||||
},
|
||||
"sku": {
|
||||
"name": "Standard_B1s",
|
||||
"tier": "Burstable"
|
||||
"name": "Standard_D2ads_v5",
|
||||
"tier": "GeneralPurpose"
|
||||
},
|
||||
"tags": {
|
||||
"Environment": "staging",
|
||||
@ -63,7 +63,7 @@
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.DBforMySQL/flexibleServers', parameters('flexibleServers_mysql_odms_db_stg_name'))]"
|
||||
],
|
||||
"name": "[concat(parameters('flexibleServers_mysql_odms_db_stg_name'), '/daily-20231026t173100-c3fd140d-3620-488c-9516-d0c0fb44c636')]",
|
||||
"name": "[concat(parameters('flexibleServers_mysql_odms_db_stg_name'), '/daily-20231107t173100-c3fd140d-3620-488c-9516-d0c0fb44c636')]",
|
||||
"type": "Microsoft.DBforMySQL/flexibleServers/backups"
|
||||
},
|
||||
{
|
||||
@ -71,7 +71,7 @@
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.DBforMySQL/flexibleServers', parameters('flexibleServers_mysql_odms_db_stg_name'))]"
|
||||
],
|
||||
"name": "[concat(parameters('flexibleServers_mysql_odms_db_stg_name'), '/daily-20231027t173100-c3fd140d-3620-488c-9516-d0c0fb44c636')]",
|
||||
"name": "[concat(parameters('flexibleServers_mysql_odms_db_stg_name'), '/daily-20231108t173100-c3fd140d-3620-488c-9516-d0c0fb44c636')]",
|
||||
"type": "Microsoft.DBforMySQL/flexibleServers/backups"
|
||||
},
|
||||
{
|
||||
@ -79,7 +79,7 @@
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.DBforMySQL/flexibleServers', parameters('flexibleServers_mysql_odms_db_stg_name'))]"
|
||||
],
|
||||
"name": "[concat(parameters('flexibleServers_mysql_odms_db_stg_name'), '/daily-20231028t173100-c3fd140d-3620-488c-9516-d0c0fb44c636')]",
|
||||
"name": "[concat(parameters('flexibleServers_mysql_odms_db_stg_name'), '/daily-20231109t173100-c3fd140d-3620-488c-9516-d0c0fb44c636')]",
|
||||
"type": "Microsoft.DBforMySQL/flexibleServers/backups"
|
||||
},
|
||||
{
|
||||
@ -87,7 +87,7 @@
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.DBforMySQL/flexibleServers', parameters('flexibleServers_mysql_odms_db_stg_name'))]"
|
||||
],
|
||||
"name": "[concat(parameters('flexibleServers_mysql_odms_db_stg_name'), '/daily-20231029t173100-c3fd140d-3620-488c-9516-d0c0fb44c636')]",
|
||||
"name": "[concat(parameters('flexibleServers_mysql_odms_db_stg_name'), '/daily-20231110t173100-c3fd140d-3620-488c-9516-d0c0fb44c636')]",
|
||||
"type": "Microsoft.DBforMySQL/flexibleServers/backups"
|
||||
},
|
||||
{
|
||||
@ -95,7 +95,7 @@
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.DBforMySQL/flexibleServers', parameters('flexibleServers_mysql_odms_db_stg_name'))]"
|
||||
],
|
||||
"name": "[concat(parameters('flexibleServers_mysql_odms_db_stg_name'), '/daily-20231030t173100-c3fd140d-3620-488c-9516-d0c0fb44c636')]",
|
||||
"name": "[concat(parameters('flexibleServers_mysql_odms_db_stg_name'), '/daily-20231111t173100-c3fd140d-3620-488c-9516-d0c0fb44c636')]",
|
||||
"type": "Microsoft.DBforMySQL/flexibleServers/backups"
|
||||
},
|
||||
{
|
||||
@ -103,7 +103,7 @@
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.DBforMySQL/flexibleServers', parameters('flexibleServers_mysql_odms_db_stg_name'))]"
|
||||
],
|
||||
"name": "[concat(parameters('flexibleServers_mysql_odms_db_stg_name'), '/daily-20231031t173100-c3fd140d-3620-488c-9516-d0c0fb44c636')]",
|
||||
"name": "[concat(parameters('flexibleServers_mysql_odms_db_stg_name'), '/daily-20231112t173100-c3fd140d-3620-488c-9516-d0c0fb44c636')]",
|
||||
"type": "Microsoft.DBforMySQL/flexibleServers/backups"
|
||||
},
|
||||
{
|
||||
@ -111,7 +111,7 @@
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.DBforMySQL/flexibleServers', parameters('flexibleServers_mysql_odms_db_stg_name'))]"
|
||||
],
|
||||
"name": "[concat(parameters('flexibleServers_mysql_odms_db_stg_name'), '/daily-20231101t173100-c3fd140d-3620-488c-9516-d0c0fb44c636')]",
|
||||
"name": "[concat(parameters('flexibleServers_mysql_odms_db_stg_name'), '/daily-20231113t173100-c3fd140d-3620-488c-9516-d0c0fb44c636')]",
|
||||
"type": "Microsoft.DBforMySQL/flexibleServers/backups"
|
||||
},
|
||||
{
|
||||
@ -443,9 +443,9 @@
|
||||
],
|
||||
"name": "[concat(parameters('flexibleServers_mysql_odms_db_stg_name'), '/back_log')]",
|
||||
"properties": {
|
||||
"currentValue": "185",
|
||||
"currentValue": "783",
|
||||
"source": "system-default",
|
||||
"value": "185"
|
||||
"value": "783"
|
||||
},
|
||||
"type": "Microsoft.DBforMySQL/flexibleServers/configurations"
|
||||
},
|
||||
@ -469,9 +469,9 @@
|
||||
],
|
||||
"name": "[concat(parameters('flexibleServers_mysql_odms_db_stg_name'), '/binlog_cache_size')]",
|
||||
"properties": {
|
||||
"currentValue": "131072",
|
||||
"currentValue": "8388608",
|
||||
"source": "system-default",
|
||||
"value": "131072"
|
||||
"value": "8388608"
|
||||
},
|
||||
"type": "Microsoft.DBforMySQL/flexibleServers/configurations"
|
||||
},
|
||||
@ -701,9 +701,9 @@
|
||||
],
|
||||
"name": "[concat(parameters('flexibleServers_mysql_odms_db_stg_name'), '/binlog_transaction_dependency_history_size')]",
|
||||
"properties": {
|
||||
"currentValue": "1000",
|
||||
"currentValue": "8000",
|
||||
"source": "system-default",
|
||||
"value": "1000"
|
||||
"value": "8000"
|
||||
},
|
||||
"type": "Microsoft.DBforMySQL/flexibleServers/configurations"
|
||||
},
|
||||
@ -1479,9 +1479,9 @@
|
||||
],
|
||||
"name": "[concat(parameters('flexibleServers_mysql_odms_db_stg_name'), '/innodb_buffer_pool_chunk_size')]",
|
||||
"properties": {
|
||||
"currentValue": "33554432",
|
||||
"currentValue": "134217728",
|
||||
"source": "system-default",
|
||||
"value": "33554432"
|
||||
"value": "134217728"
|
||||
},
|
||||
"type": "Microsoft.DBforMySQL/flexibleServers/configurations"
|
||||
},
|
||||
@ -1557,9 +1557,9 @@
|
||||
],
|
||||
"name": "[concat(parameters('flexibleServers_mysql_odms_db_stg_name'), '/innodb_buffer_pool_instances')]",
|
||||
"properties": {
|
||||
"currentValue": "1",
|
||||
"currentValue": "8",
|
||||
"source": "system-default",
|
||||
"value": "1"
|
||||
"value": "8"
|
||||
},
|
||||
"type": "Microsoft.DBforMySQL/flexibleServers/configurations"
|
||||
},
|
||||
@ -1609,9 +1609,9 @@
|
||||
],
|
||||
"name": "[concat(parameters('flexibleServers_mysql_odms_db_stg_name'), '/innodb_buffer_pool_size')]",
|
||||
"properties": {
|
||||
"currentValue": "134217728",
|
||||
"currentValue": "4294967296",
|
||||
"source": "system-default",
|
||||
"value": "134217728"
|
||||
"value": "4294967296"
|
||||
},
|
||||
"type": "Microsoft.DBforMySQL/flexibleServers/configurations"
|
||||
},
|
||||
@ -1902,9 +1902,9 @@
|
||||
],
|
||||
"name": "[concat(parameters('flexibleServers_mysql_odms_db_stg_name'), '/innodb_fatal_semaphore_wait_threshold')]",
|
||||
"properties": {
|
||||
"currentValue": "7201",
|
||||
"currentValue": "600",
|
||||
"source": "system-default",
|
||||
"value": "7201"
|
||||
"value": "600"
|
||||
},
|
||||
"type": "Microsoft.DBforMySQL/flexibleServers/configurations"
|
||||
},
|
||||
@ -2993,9 +2993,9 @@
|
||||
],
|
||||
"name": "[concat(parameters('flexibleServers_mysql_odms_db_stg_name'), '/innodb_temp_tablespaces_dir')]",
|
||||
"properties": {
|
||||
"currentValue": "/app/work/temp",
|
||||
"currentValue": "/mnt/temp",
|
||||
"source": "system-default",
|
||||
"value": "/app/work/temp"
|
||||
"value": "/mnt/temp"
|
||||
},
|
||||
"type": "Microsoft.DBforMySQL/flexibleServers/configurations"
|
||||
},
|
||||
@ -3032,9 +3032,9 @@
|
||||
],
|
||||
"name": "[concat(parameters('flexibleServers_mysql_odms_db_stg_name'), '/innodb_tmpdir')]",
|
||||
"properties": {
|
||||
"currentValue": "/app/work/temp",
|
||||
"currentValue": "/mnt/temp",
|
||||
"source": "system-default",
|
||||
"value": "/app/work/temp"
|
||||
"value": "/mnt/temp"
|
||||
},
|
||||
"type": "Microsoft.DBforMySQL/flexibleServers/configurations"
|
||||
},
|
||||
@ -3559,9 +3559,9 @@
|
||||
],
|
||||
"name": "[concat(parameters('flexibleServers_mysql_odms_db_stg_name'), '/max_allowed_packet')]",
|
||||
"properties": {
|
||||
"currentValue": "16777216",
|
||||
"currentValue": "536870912",
|
||||
"source": "system-default",
|
||||
"value": "16777216"
|
||||
"value": "536870912"
|
||||
},
|
||||
"type": "Microsoft.DBforMySQL/flexibleServers/configurations"
|
||||
},
|
||||
@ -3624,9 +3624,9 @@
|
||||
],
|
||||
"name": "[concat(parameters('flexibleServers_mysql_odms_db_stg_name'), '/max_connections')]",
|
||||
"properties": {
|
||||
"currentValue": "85",
|
||||
"currentValue": "683",
|
||||
"source": "system-default",
|
||||
"value": "85"
|
||||
"value": "683"
|
||||
},
|
||||
"type": "Microsoft.DBforMySQL/flexibleServers/configurations"
|
||||
},
|
||||
@ -4736,9 +4736,9 @@
|
||||
],
|
||||
"name": "[concat(parameters('flexibleServers_mysql_odms_db_stg_name'), '/relay_log')]",
|
||||
"properties": {
|
||||
"currentValue": "/app/work/relaylogs/relay_bin",
|
||||
"currentValue": "/mnt/relaylogs/relay_bin",
|
||||
"source": "system-default",
|
||||
"value": "/app/work/relaylogs/relay_bin"
|
||||
"value": "/mnt/relaylogs/relay_bin"
|
||||
},
|
||||
"type": "Microsoft.DBforMySQL/flexibleServers/configurations"
|
||||
},
|
||||
@ -4749,9 +4749,9 @@
|
||||
],
|
||||
"name": "[concat(parameters('flexibleServers_mysql_odms_db_stg_name'), '/relay_log_index')]",
|
||||
"properties": {
|
||||
"currentValue": "/app/work/relaylogs/relay_bin.index",
|
||||
"currentValue": "/mnt/relaylogs/relay_bin.index",
|
||||
"source": "system-default",
|
||||
"value": "/app/work/relaylogs/relay_bin.index"
|
||||
"value": "/mnt/relaylogs/relay_bin.index"
|
||||
},
|
||||
"type": "Microsoft.DBforMySQL/flexibleServers/configurations"
|
||||
},
|
||||
@ -4801,9 +4801,9 @@
|
||||
],
|
||||
"name": "[concat(parameters('flexibleServers_mysql_odms_db_stg_name'), '/relay_log_space_limit')]",
|
||||
"properties": {
|
||||
"currentValue": "1073741824",
|
||||
"currentValue": "4294967296",
|
||||
"source": "system-default",
|
||||
"value": "1073741824"
|
||||
"value": "4294967296"
|
||||
},
|
||||
"type": "Microsoft.DBforMySQL/flexibleServers/configurations"
|
||||
},
|
||||
@ -5152,9 +5152,9 @@
|
||||
],
|
||||
"name": "[concat(parameters('flexibleServers_mysql_odms_db_stg_name'), '/slave_load_tmpdir')]",
|
||||
"properties": {
|
||||
"currentValue": "/app/work/temp",
|
||||
"currentValue": "/mnt/temp",
|
||||
"source": "system-default",
|
||||
"value": "/app/work/temp"
|
||||
"value": "/mnt/temp"
|
||||
},
|
||||
"type": "Microsoft.DBforMySQL/flexibleServers/configurations"
|
||||
},
|
||||
@ -5204,9 +5204,9 @@
|
||||
],
|
||||
"name": "[concat(parameters('flexibleServers_mysql_odms_db_stg_name'), '/slave_parallel_workers')]",
|
||||
"properties": {
|
||||
"currentValue": "0",
|
||||
"currentValue": "8",
|
||||
"source": "system-default",
|
||||
"value": "0"
|
||||
"value": "8"
|
||||
},
|
||||
"type": "Microsoft.DBforMySQL/flexibleServers/configurations"
|
||||
},
|
||||
@ -5217,9 +5217,9 @@
|
||||
],
|
||||
"name": "[concat(parameters('flexibleServers_mysql_odms_db_stg_name'), '/slave_pending_jobs_size_max')]",
|
||||
"properties": {
|
||||
"currentValue": "16777216",
|
||||
"currentValue": "67108864",
|
||||
"source": "system-default",
|
||||
"value": "16777216"
|
||||
"value": "67108864"
|
||||
},
|
||||
"type": "Microsoft.DBforMySQL/flexibleServers/configurations"
|
||||
},
|
||||
@ -5332,9 +5332,9 @@
|
||||
],
|
||||
"name": "[concat(parameters('flexibleServers_mysql_odms_db_stg_name'), '/slow_query_log_file')]",
|
||||
"properties": {
|
||||
"currentValue": "/app/serverlogs/slowlogs/mysql-slow-mysql-odms-db-stg-2023110201.log",
|
||||
"currentValue": "/app/serverlogs/slowlogs/mysql-slow-mysql-odms-db-stg-2023111401.log",
|
||||
"source": "user-override",
|
||||
"value": "/app/serverlogs/slowlogs/mysql-slow-mysql-odms-db-stg-2023110201.log"
|
||||
"value": "/app/serverlogs/slowlogs/mysql-slow-mysql-odms-db-stg-2023111401.log"
|
||||
},
|
||||
"type": "Microsoft.DBforMySQL/flexibleServers/configurations"
|
||||
},
|
||||
@ -5345,9 +5345,9 @@
|
||||
],
|
||||
"name": "[concat(parameters('flexibleServers_mysql_odms_db_stg_name'), '/sort_buffer_size')]",
|
||||
"properties": {
|
||||
"currentValue": "262144",
|
||||
"currentValue": "524288",
|
||||
"source": "system-default",
|
||||
"value": "262144"
|
||||
"value": "524288"
|
||||
},
|
||||
"type": "Microsoft.DBforMySQL/flexibleServers/configurations"
|
||||
},
|
||||
@ -5501,9 +5501,9 @@
|
||||
],
|
||||
"name": "[concat(parameters('flexibleServers_mysql_odms_db_stg_name'), '/table_definition_cache')]",
|
||||
"properties": {
|
||||
"currentValue": "300",
|
||||
"currentValue": "2400",
|
||||
"source": "system-default",
|
||||
"value": "300"
|
||||
"value": "2400"
|
||||
},
|
||||
"type": "Microsoft.DBforMySQL/flexibleServers/configurations"
|
||||
},
|
||||
@ -5527,9 +5527,9 @@
|
||||
],
|
||||
"name": "[concat(parameters('flexibleServers_mysql_odms_db_stg_name'), '/table_open_cache')]",
|
||||
"properties": {
|
||||
"currentValue": "300",
|
||||
"currentValue": "2400",
|
||||
"source": "system-default",
|
||||
"value": "300"
|
||||
"value": "2400"
|
||||
},
|
||||
"type": "Microsoft.DBforMySQL/flexibleServers/configurations"
|
||||
},
|
||||
@ -5592,9 +5592,9 @@
|
||||
],
|
||||
"name": "[concat(parameters('flexibleServers_mysql_odms_db_stg_name'), '/thread_cache_size')]",
|
||||
"properties": {
|
||||
"currentValue": "8",
|
||||
"currentValue": "14",
|
||||
"source": "system-default",
|
||||
"value": "8"
|
||||
"value": "14"
|
||||
},
|
||||
"type": "Microsoft.DBforMySQL/flexibleServers/configurations"
|
||||
},
|
||||
@ -5670,9 +5670,9 @@
|
||||
],
|
||||
"name": "[concat(parameters('flexibleServers_mysql_odms_db_stg_name'), '/thread_pool_size')]",
|
||||
"properties": {
|
||||
"currentValue": "1",
|
||||
"currentValue": "2",
|
||||
"source": "system-default",
|
||||
"value": "1"
|
||||
"value": "2"
|
||||
},
|
||||
"type": "Microsoft.DBforMySQL/flexibleServers/configurations"
|
||||
},
|
||||
@ -5761,9 +5761,9 @@
|
||||
],
|
||||
"name": "[concat(parameters('flexibleServers_mysql_odms_db_stg_name'), '/tmpdir')]",
|
||||
"properties": {
|
||||
"currentValue": "/app/work/temp",
|
||||
"currentValue": "/mnt/temp",
|
||||
"source": "system-default",
|
||||
"value": "/app/work/temp"
|
||||
"value": "/mnt/temp"
|
||||
},
|
||||
"type": "Microsoft.DBforMySQL/flexibleServers/configurations"
|
||||
},
|
||||
|
||||
@ -32,6 +32,9 @@
|
||||
"privateDnsZones_privatelink_redis_cache_windows_net_name": {
|
||||
"type": "String"
|
||||
},
|
||||
"privateEndpoints_pep_odms_app_staging_stg_name": {
|
||||
"type": "String"
|
||||
},
|
||||
"privateEndpoints_pep_odms_app_stg_name": {
|
||||
"type": "String"
|
||||
},
|
||||
@ -1387,7 +1390,7 @@
|
||||
"maxNumberOfVirtualNetworkLinks": 1000,
|
||||
"maxNumberOfVirtualNetworkLinksWithRegistration": 100,
|
||||
"numberOfRecordSets": 3,
|
||||
"numberOfVirtualNetworkLinks": 0,
|
||||
"numberOfVirtualNetworkLinks": 2,
|
||||
"numberOfVirtualNetworkLinksWithRegistration": 0,
|
||||
"provisioningState": "Succeeded"
|
||||
},
|
||||
@ -1402,7 +1405,7 @@
|
||||
"maxNumberOfVirtualNetworkLinks": 1000,
|
||||
"maxNumberOfVirtualNetworkLinksWithRegistration": 100,
|
||||
"numberOfRecordSets": 3,
|
||||
"numberOfVirtualNetworkLinks": 0,
|
||||
"numberOfVirtualNetworkLinks": 2,
|
||||
"numberOfVirtualNetworkLinksWithRegistration": 0,
|
||||
"provisioningState": "Succeeded"
|
||||
},
|
||||
@ -1421,7 +1424,7 @@
|
||||
"maxNumberOfVirtualNetworkLinks": 1000,
|
||||
"maxNumberOfVirtualNetworkLinksWithRegistration": 100,
|
||||
"numberOfRecordSets": 2,
|
||||
"numberOfVirtualNetworkLinks": 0,
|
||||
"numberOfVirtualNetworkLinks": 1,
|
||||
"numberOfVirtualNetworkLinksWithRegistration": 0,
|
||||
"provisioningState": "Succeeded"
|
||||
},
|
||||
@ -1435,8 +1438,8 @@
|
||||
"maxNumberOfRecordSets": 25000,
|
||||
"maxNumberOfVirtualNetworkLinks": 1000,
|
||||
"maxNumberOfVirtualNetworkLinksWithRegistration": 100,
|
||||
"numberOfRecordSets": 3,
|
||||
"numberOfVirtualNetworkLinks": 0,
|
||||
"numberOfRecordSets": 5,
|
||||
"numberOfVirtualNetworkLinks": 1,
|
||||
"numberOfVirtualNetworkLinksWithRegistration": 0,
|
||||
"provisioningState": "Succeeded"
|
||||
},
|
||||
@ -1454,7 +1457,7 @@
|
||||
"maxNumberOfVirtualNetworkLinks": 1000,
|
||||
"maxNumberOfVirtualNetworkLinksWithRegistration": 100,
|
||||
"numberOfRecordSets": 2,
|
||||
"numberOfVirtualNetworkLinks": 0,
|
||||
"numberOfVirtualNetworkLinks": 1,
|
||||
"numberOfVirtualNetworkLinksWithRegistration": 0,
|
||||
"provisioningState": "Succeeded"
|
||||
},
|
||||
@ -2411,6 +2414,44 @@
|
||||
},
|
||||
"type": "Microsoft.Network/privateDnsZones/A"
|
||||
},
|
||||
{
|
||||
"apiVersion": "2018-09-01",
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.Network/privateDnsZones', parameters('privateDnsZones_privatelink_azurewebsites_net_name'))]"
|
||||
],
|
||||
"name": "[concat(parameters('privateDnsZones_privatelink_azurewebsites_net_name'), '/app-odms-dictation-stg-staging')]",
|
||||
"properties": {
|
||||
"aRecords": [
|
||||
{
|
||||
"ipv4Address": "10.2.1.8"
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"creator": "created by private endpoint pep-odms-app-staging-stg with resource guid 8d258be6-1804-4cc3-8172-46075366effa"
|
||||
},
|
||||
"ttl": 10
|
||||
},
|
||||
"type": "Microsoft.Network/privateDnsZones/A"
|
||||
},
|
||||
{
|
||||
"apiVersion": "2018-09-01",
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.Network/privateDnsZones', parameters('privateDnsZones_privatelink_azurewebsites_net_name'))]"
|
||||
],
|
||||
"name": "[concat(parameters('privateDnsZones_privatelink_azurewebsites_net_name'), '/app-odms-dictation-stg-staging.scm')]",
|
||||
"properties": {
|
||||
"aRecords": [
|
||||
{
|
||||
"ipv4Address": "10.2.1.8"
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"creator": "created by private endpoint pep-odms-app-staging-stg with resource guid 8d258be6-1804-4cc3-8172-46075366effa"
|
||||
},
|
||||
"ttl": 10
|
||||
},
|
||||
"type": "Microsoft.Network/privateDnsZones/A"
|
||||
},
|
||||
{
|
||||
"apiVersion": "2018-09-01",
|
||||
"dependsOn": [
|
||||
@ -2611,6 +2652,39 @@
|
||||
},
|
||||
"type": "Microsoft.Network/privateDnsZones/virtualNetworkLinks"
|
||||
},
|
||||
{
|
||||
"apiVersion": "2023-05-01",
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworks_vnet_odms_network_stg_name'), 'snet-odms-public-stg')]"
|
||||
],
|
||||
"location": "japaneast",
|
||||
"name": "[parameters('privateEndpoints_pep_odms_app_staging_stg_name')]",
|
||||
"properties": {
|
||||
"customDnsConfigs": [],
|
||||
"ipConfigurations": [],
|
||||
"manualPrivateLinkServiceConnections": [],
|
||||
"privateLinkServiceConnections": [
|
||||
{
|
||||
"id": "[concat(resourceId('Microsoft.Network/privateEndpoints', parameters('privateEndpoints_pep_odms_app_staging_stg_name')), concat('/privateLinkServiceConnections/', parameters('privateEndpoints_pep_odms_app_staging_stg_name'), '-9794'))]",
|
||||
"name": "[concat(parameters('privateEndpoints_pep_odms_app_staging_stg_name'), '-9794')]",
|
||||
"properties": {
|
||||
"groupIds": [
|
||||
"sites-staging"
|
||||
],
|
||||
"privateLinkServiceConnectionState": {
|
||||
"actionsRequired": "None",
|
||||
"status": "Approved"
|
||||
},
|
||||
"privateLinkServiceId": "[parameters('sites_app_odms_dictation_stg_externalid')]"
|
||||
}
|
||||
}
|
||||
],
|
||||
"subnet": {
|
||||
"id": "[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworks_vnet_odms_network_stg_name'), 'snet-odms-public-stg')]"
|
||||
}
|
||||
},
|
||||
"type": "Microsoft.Network/privateEndpoints"
|
||||
},
|
||||
{
|
||||
"apiVersion": "2023-05-01",
|
||||
"dependsOn": [
|
||||
@ -8969,6 +9043,22 @@
|
||||
},
|
||||
"type": "Microsoft.OperationalInsights/workspaces/tables"
|
||||
},
|
||||
{
|
||||
"apiVersion": "2021-12-01-preview",
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspaces_log_odms_agw_stg_name'))]"
|
||||
],
|
||||
"name": "[concat(parameters('workspaces_log_odms_agw_stg_name'), '/LASummaryLogs')]",
|
||||
"properties": {
|
||||
"plan": "Analytics",
|
||||
"retentionInDays": 30,
|
||||
"schema": {
|
||||
"name": "LASummaryLogs"
|
||||
},
|
||||
"totalRetentionInDays": 30
|
||||
},
|
||||
"type": "Microsoft.OperationalInsights/workspaces/tables"
|
||||
},
|
||||
{
|
||||
"apiVersion": "2021-12-01-preview",
|
||||
"dependsOn": [
|
||||
@ -11257,6 +11347,25 @@
|
||||
},
|
||||
"type": "Microsoft.Network/privateDnsZones/virtualNetworkLinks"
|
||||
},
|
||||
{
|
||||
"apiVersion": "2023-05-01",
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.Network/privateEndpoints', parameters('privateEndpoints_pep_odms_app_staging_stg_name'))]",
|
||||
"[resourceId('Microsoft.Network/privateDnsZones', parameters('privateDnsZones_privatelink_azurewebsites_net_name'))]"
|
||||
],
|
||||
"name": "[concat(parameters('privateEndpoints_pep_odms_app_staging_stg_name'), '/default')]",
|
||||
"properties": {
|
||||
"privateDnsZoneConfigs": [
|
||||
{
|
||||
"name": "privatelink-azurewebsites-net",
|
||||
"properties": {
|
||||
"privateDnsZoneId": "[resourceId('Microsoft.Network/privateDnsZones', parameters('privateDnsZones_privatelink_azurewebsites_net_name'))]"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups"
|
||||
},
|
||||
{
|
||||
"apiVersion": "2023-05-01",
|
||||
"dependsOn": [
|
||||
|
||||
@ -2066,6 +2066,23 @@
|
||||
},
|
||||
"type": "Microsoft.Storage/storageAccounts/blobServices/containers"
|
||||
},
|
||||
{
|
||||
"apiVersion": "2023-01-01",
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.Storage/storageAccounts/blobServices', parameters('storageAccounts_saodmsusstg_name'), 'default')]",
|
||||
"[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccounts_saodmsusstg_name'))]"
|
||||
],
|
||||
"name": "[concat(parameters('storageAccounts_saodmsusstg_name'), '/default/account-189')]",
|
||||
"properties": {
|
||||
"defaultEncryptionScope": "$account-encryption-key",
|
||||
"denyEncryptionScopeOverride": false,
|
||||
"immutableStorageWithVersioning": {
|
||||
"enabled": false
|
||||
},
|
||||
"publicAccess": "None"
|
||||
},
|
||||
"type": "Microsoft.Storage/storageAccounts/blobServices/containers"
|
||||
},
|
||||
{
|
||||
"apiVersion": "2023-01-01",
|
||||
"dependsOn": [
|
||||
@ -2083,6 +2100,40 @@
|
||||
},
|
||||
"type": "Microsoft.Storage/storageAccounts/blobServices/containers"
|
||||
},
|
||||
{
|
||||
"apiVersion": "2023-01-01",
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.Storage/storageAccounts/blobServices', parameters('storageAccounts_saodmsusstg_name'), 'default')]",
|
||||
"[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccounts_saodmsusstg_name'))]"
|
||||
],
|
||||
"name": "[concat(parameters('storageAccounts_saodmsusstg_name'), '/default/account-191')]",
|
||||
"properties": {
|
||||
"defaultEncryptionScope": "$account-encryption-key",
|
||||
"denyEncryptionScopeOverride": false,
|
||||
"immutableStorageWithVersioning": {
|
||||
"enabled": false
|
||||
},
|
||||
"publicAccess": "None"
|
||||
},
|
||||
"type": "Microsoft.Storage/storageAccounts/blobServices/containers"
|
||||
},
|
||||
{
|
||||
"apiVersion": "2023-01-01",
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.Storage/storageAccounts/blobServices', parameters('storageAccounts_saodmsaustg_name'), 'default')]",
|
||||
"[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccounts_saodmsaustg_name'))]"
|
||||
],
|
||||
"name": "[concat(parameters('storageAccounts_saodmsaustg_name'), '/default/account-192')]",
|
||||
"properties": {
|
||||
"defaultEncryptionScope": "$account-encryption-key",
|
||||
"denyEncryptionScopeOverride": false,
|
||||
"immutableStorageWithVersioning": {
|
||||
"enabled": false
|
||||
},
|
||||
"publicAccess": "None"
|
||||
},
|
||||
"type": "Microsoft.Storage/storageAccounts/blobServices/containers"
|
||||
},
|
||||
{
|
||||
"apiVersion": "2023-01-01",
|
||||
"dependsOn": [
|
||||
|
||||
12
dictation_function/Dockerfile
Normal file
12
dictation_function/Dockerfile
Normal file
@ -0,0 +1,12 @@
|
||||
# To enable ssh & remote debugging on app service change the base image to the one below
|
||||
# FROM mcr.microsoft.com/azure-functions/node:4-node18-appservice
|
||||
FROM mcr.microsoft.com/azure-functions/node:4-node18
|
||||
|
||||
ENV AzureWebJobsScriptRoot=/home/site/wwwroot \
|
||||
AzureFunctionsJobHost__Logging__Console__IsEnabled=true
|
||||
|
||||
COPY . /home/site/wwwroot
|
||||
|
||||
RUN cd /home/site/wwwroot && \
|
||||
npm install && \
|
||||
npm run build
|
||||
71
dictation_function/package-lock.json
generated
71
dictation_function/package-lock.json
generated
@ -6663,6 +6663,77 @@
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/slash/node_modules/ansi-styles": {
|
||||
"version": "3.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
|
||||
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"color-convert": "^1.9.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/slash/node_modules/chalk": {
|
||||
"version": "2.4.2",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
|
||||
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"ansi-styles": "^3.2.1",
|
||||
"escape-string-regexp": "^1.0.5",
|
||||
"supports-color": "^5.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/slash/node_modules/color-convert": {
|
||||
"version": "1.9.3",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
|
||||
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"color-name": "1.1.3"
|
||||
}
|
||||
},
|
||||
"node_modules/slash/node_modules/color-name": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
|
||||
"integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/slash/node_modules/escape-string-regexp": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
|
||||
"integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/slash/node_modules/has-flag": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
|
||||
"integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/slash/node_modules/supports-color": {
|
||||
"version": "5.5.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
|
||||
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"has-flag": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/smart-buffer": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz",
|
||||
|
||||
@ -14,9 +14,11 @@ import {
|
||||
DateWithZeroTime,
|
||||
ExpirationThresholdDate,
|
||||
} from "../common/types/types";
|
||||
import { getMailFrom } from "../common/getEnv/getEnv";
|
||||
import { createMailContentOfLicenseShortage } from "../sendgrid/mailContents/U103ShortageAlert";
|
||||
import { createMailContentOfLicenseExpiringSoon } from "../sendgrid/mailContents/U104ExpiringSoonAlert";
|
||||
import { AdB2cService } from "../adb2c/adb2c.service";
|
||||
import { SendGridService } from "../sendgrid/sendgrid.service";
|
||||
import { getMailFrom } from "../common/getEnv/getEnv";
|
||||
|
||||
export async function licenseAlertProcessing(
|
||||
context: InvocationContext,
|
||||
@ -194,7 +196,11 @@ export async function licenseAlertProcessing(
|
||||
// ライセンス不足メール
|
||||
if (targetAccount.shortage !== 0) {
|
||||
const { subject, text, html } =
|
||||
await sendgrid.createMailContentOfLicenseShortage();
|
||||
await createMailContentOfLicenseShortage(
|
||||
targetAccount.companyName,
|
||||
targetAccount.shortage,
|
||||
targetAccount.parentCompanyName
|
||||
);
|
||||
// メールを送信
|
||||
try {
|
||||
await sendgrid.sendMail(
|
||||
@ -218,7 +224,11 @@ export async function licenseAlertProcessing(
|
||||
// ライセンス不足メール
|
||||
if (targetAccount.shortage !== 0) {
|
||||
const { subject, text, html } =
|
||||
await sendgrid.createMailContentOfLicenseShortage();
|
||||
await createMailContentOfLicenseShortage(
|
||||
targetAccount.companyName,
|
||||
targetAccount.shortage,
|
||||
targetAccount.parentCompanyName
|
||||
);
|
||||
// メールを送信
|
||||
try {
|
||||
await sendgrid.sendMail(
|
||||
@ -243,7 +253,11 @@ export async function licenseAlertProcessing(
|
||||
// ライセンス失効警告メール
|
||||
if (targetAccount.userCountOfLicenseExpiringSoon !== 0) {
|
||||
const { subject, text, html } =
|
||||
await sendgrid.createMailContentOfLicenseExpiringSoon();
|
||||
await createMailContentOfLicenseExpiringSoon(
|
||||
targetAccount.companyName,
|
||||
targetAccount.userCountOfLicenseExpiringSoon,
|
||||
targetAccount.parentCompanyName
|
||||
);
|
||||
// メールを送信
|
||||
try {
|
||||
await sendgrid.sendMail(
|
||||
@ -267,7 +281,11 @@ export async function licenseAlertProcessing(
|
||||
// ライセンス不足メール
|
||||
if (targetAccount.shortage !== 0) {
|
||||
const { subject, text, html } =
|
||||
await sendgrid.createMailContentOfLicenseExpiringSoon();
|
||||
await createMailContentOfLicenseExpiringSoon(
|
||||
targetAccount.companyName,
|
||||
targetAccount.userCountOfLicenseExpiringSoon,
|
||||
targetAccount.parentCompanyName
|
||||
);
|
||||
// メールを送信
|
||||
try {
|
||||
await sendgrid.sendMail(
|
||||
@ -330,7 +348,7 @@ export async function licenseAlert(
|
||||
}
|
||||
|
||||
app.timer("licenseAlert", {
|
||||
schedule: "0 */1 * * * *",
|
||||
schedule: "0 0 1 * * *",
|
||||
handler: licenseAlert,
|
||||
});
|
||||
|
||||
|
||||
@ -0,0 +1,179 @@
|
||||
/**
|
||||
* メールコンテンツを作成する(ライセンス在庫不足)
|
||||
* @param companyName
|
||||
* @param shortage
|
||||
* @param dealer
|
||||
* @returns メールのサブジェクトとコンテンツ
|
||||
*/
|
||||
export async function createMailContentOfLicenseShortage(
|
||||
companyName: string,
|
||||
shortage: number,
|
||||
dealer: string | undefined
|
||||
): Promise<{
|
||||
subject: string;
|
||||
text: string;
|
||||
html: string;
|
||||
}> {
|
||||
return {
|
||||
// subject ////////////////////////////////////////////////////////////////////
|
||||
subject: "License Shortage Notification [U-103]",
|
||||
// text ////////////////////////////////////////////////////////////////////
|
||||
text: `<English>
|
||||
Dear ${companyName},
|
||||
|
||||
One or more of your assigned ODMS Cloud licenses will expire within 14 days. There is insufficient amount of unassigned licenses in your inventory to issue to users with expiring licenses.
|
||||
|
||||
Insufficient license count: ${shortage}
|
||||
|
||||
Please order additional annual licenses from ${dealer} to ensure you have sufficient inventory.
|
||||
|
||||
You can either automatically or manually assign licenses to users. Users with the Auto-assign option enabled (default) will have their license automatically assigned from your license inventory on the expiration date. If you disable the Auto-assign option, you must manually assign licenses.
|
||||
|
||||
Please log in to ODMS Cloud to configure your user setting and verify the license expiration date.
|
||||
URL: https://odmscloud.omsystem.com/
|
||||
|
||||
If you need support regarding ODMS Cloud, please contact ${dealer}.
|
||||
|
||||
If you have received this e-mail in error, please delete this e-mail from your system.
|
||||
This is an automatically generated e-mail and this mailbox is not monitored. Please do not reply.
|
||||
|
||||
|
||||
<Deutsch>
|
||||
Sehr geehrte(r) ${companyName},
|
||||
|
||||
Eine oder mehrere Ihrer zugewiesenen ODMS Cloud-Lizenzen laufen innerhalb von 14 Tagen ab. In Ihrem Bestand ist nicht genügend Anzahl nicht zugewiesener Lizenzen Inventar, um diese an Benutzer mit ablaufenden Lizenzen auszugeben.
|
||||
|
||||
Unzureichende Lizenzanzahl: ${shortage}
|
||||
|
||||
Bitte bestellen Sie zusätzliche Jahreslizenzen bei Ihrem ${dealer} um sicherzustellen, dass Sie über ausreichend Lagerbestände Inventar.
|
||||
|
||||
Sie können Benutzern entweder automatisch oder manuell Lizenzen zuweisen. Benutzern mit aktivierter Option „Automatische Zuweisung“ (Standard) wird die Lizenz am Ablaufdatum automatisch aus Ihrem Lizenzbestand zugewiesen. Wenn Sie die Option „Automatisch zuweisen“ deaktivieren, müssen Sie Lizenzen manuell zuweisen.
|
||||
|
||||
Bitte melden Sie sich bei ODMS Cloud an, um Ihre Benutzereinstellungen zu konfigurieren und das Ablaufdatum der Lizenz zu überprüfen.
|
||||
URL: https://odmscloud.omsystem.com/
|
||||
|
||||
Wenn Sie Unterstützung bezüglich ODMS benötigen, wenden Sie sich bitte an ${dealer}.
|
||||
|
||||
Wenn Sie diese E-Mail fälschlicherweise erhalten haben, löschen Sie diese E-Mail bitte aus Ihrem System.
|
||||
Dies ist eine automatisch generierte E-Mail und dieses Postfach wird nicht überwacht. Bitte nicht antworten.
|
||||
|
||||
|
||||
<Español>
|
||||
Estimado(a) ${companyName},
|
||||
|
||||
Una o más de sus licencias de ODMS Cloud asignadas caducarán en un plazo de 14 días. No hay una cantidad suficiente de licencias no asignadas en su inventario para emitirlas a usuarios con licencias vencidas.
|
||||
|
||||
Recuento de licencias insuficiente: ${shortage}
|
||||
|
||||
Solicite licencias anuales adicionales a su ${dealer} para asegurarse de tener suficiente inventario.
|
||||
|
||||
Puede asignar licencias a los usuarios de forma automática o manual. A los usuarios con la opción Asignación automática habilitada (predeterminada) se les asignará su licencia automáticamente desde su inventario de licencias en la fecha de vencimiento. Si desactiva la opción Asignar automáticamente, deberá asignar licencias manualmente.
|
||||
|
||||
Inicie sesión en ODMS Cloud para configurar su configuración de usuario y verificar la fecha de vencimiento de la licencia.
|
||||
URL: https://odmscloud.omsystem.com/
|
||||
|
||||
Si necesita ayuda con respecto a ODMS Cloud, comuníquese con ${dealer}.
|
||||
|
||||
Si recibió este correo electrónico por error, elimínelo de su sistema.
|
||||
Este es un correo electrónico generado automáticamente y este buzón no está monitoreado. Por favor, no responda.
|
||||
|
||||
|
||||
<Français>
|
||||
Chère/Cher ${companyName},
|
||||
|
||||
Une ou plusieurs de vos licences ODMS Cloud attribuées expireront dans les 14 jours. Le nombre de licences non attribuées dans votre inventaire est insuffisant pour être délivré aux utilisateurs dont les licences arrivent à expiration.
|
||||
|
||||
Nombre de licences insuffisant: ${shortage}
|
||||
|
||||
Veuillez commander des licences annuelles supplémentaires auprès de votre ${dealer} pour vous assurer que vous disposez d'un inventaire suffisant.
|
||||
|
||||
Vous pouvez attribuer automatiquement ou manuellement des licences aux utilisateurs. Les utilisateurs dont l'option d'attribution automatique est activée (par défaut) verront leur licence automatiquement attribuée à partir de votre inventaire de licences à la date d'expiration. Si vous désactivez l'option Attribution automatique, vous devez attribuer manuellement des licences.
|
||||
|
||||
Veuillez vous connecter à ODMS Cloud pour configurer vos paramètres utilisateur et vérifier la date d'expiration de la licence.
|
||||
URL: https://odmscloud.omsystem.com/
|
||||
|
||||
Si vous avez besoin d'assistance concernant ODMS Cloud, veuillez contacter ${dealer}.
|
||||
|
||||
Si vous avez reçu cet e-mail par erreur, veuillez supprimer cet e-mail de votre système.
|
||||
Il s'agit d'un e-mail généré automatiquement et cette boîte aux lettres n'est pas surveillée. Merci de ne pas répondre.`,
|
||||
// html ////////////////////////////////////////////////////////////////////
|
||||
html: `<h3><English></h3>
|
||||
<p>Dear ${companyName},<p>
|
||||
|
||||
<p>One or more of your assigned ODMS Cloud licenses will expire within 14 days. There is insufficient amount of unassigned licenses in your inventory to issue to users with expiring licenses.</p>
|
||||
|
||||
<p>Insufficient license count: ${shortage}</p>
|
||||
|
||||
<p>Please order additional annual licenses from ${dealer} to ensure you have sufficient inventory. </p>
|
||||
|
||||
<p>You can either automatically or manually assign licenses to users. Users with the Auto-assign option enabled (default) will have their license automatically assigned from your license inventory on the expiration date. If you disable the Auto-assign option, you must manually assign licenses.</p>
|
||||
|
||||
<p>Please log in to ODMS Cloud to configure your user setting and verify the license expiration date.<br>
|
||||
URL: <a href="https://odmscloud.omsystem.com/">https://odmscloud.omsystem.com/</a></p>
|
||||
|
||||
<p>If you need support regarding ODMS Cloud, please contact ${dealer}.</p>
|
||||
|
||||
<p>If you have received this e-mail in error, please delete this e-mail from your system.<br>
|
||||
This is an automatically generated e-mail and this mailbox is not monitored. Please do not reply.</p>
|
||||
|
||||
|
||||
<h3><Deutsch></h3>
|
||||
<p>Sehr geehrte(r) ${companyName},</p>
|
||||
|
||||
<p>Eine oder mehrere Ihrer zugewiesenen ODMS Cloud-Lizenzen laufen innerhalb von 14 Tagen ab. In Ihrem Bestand ist nicht genügend Anzahl nicht zugewiesener Lizenzen Inventar, um diese an Benutzer mit ablaufenden Lizenzen auszugeben.</p>
|
||||
|
||||
<p>Unzureichende Lizenzanzahl: ${shortage}</p>
|
||||
|
||||
<p>Bitte bestellen Sie zusätzliche Jahreslizenzen bei Ihrem ${dealer} um sicherzustellen, dass Sie über ausreichend Lagerbestände Inventar.</p>
|
||||
|
||||
<p>Sie können Benutzern entweder automatisch oder manuell Lizenzen zuweisen. Benutzern mit aktivierter Option „Automatische Zuweisung“ (Standard) wird die Lizenz am Ablaufdatum automatisch aus Ihrem Lizenzbestand zugewiesen. Wenn Sie die Option „Automatisch zuweisen“ deaktivieren, müssen Sie Lizenzen manuell zuweisen.</p>
|
||||
|
||||
<p>Bitte melden Sie sich bei ODMS Cloud an, um Ihre Benutzereinstellungen zu konfigurieren und das Ablaufdatum der Lizenz zu überprüfen.<br>
|
||||
URL: <a href="https://odmscloud.omsystem.com/">https://odmscloud.omsystem.com/</a></p>
|
||||
|
||||
<p>Wenn Sie Unterstützung bezüglich ODMS benötigen, wenden Sie sich bitte an ${dealer}.</p>
|
||||
|
||||
<p>Wenn Sie diese E-Mail fälschlicherweise erhalten haben, löschen Sie diese E-Mail bitte aus Ihrem System.<br>
|
||||
Dies ist eine automatisch generierte E-Mail und dieses Postfach wird nicht überwacht. Bitte nicht antworten.</p>
|
||||
|
||||
|
||||
<h3><Español></h3>
|
||||
<p>Estimado(a) ${companyName},</p>
|
||||
|
||||
<p>Una o más de sus licencias de ODMS Cloud asignadas caducarán en un plazo de 14 días. No hay una cantidad suficiente de licencias no asignadas en su inventario para emitirlas a usuarios con licencias vencidas.</p>
|
||||
|
||||
<p>Recuento de licencias insuficiente: ${shortage}</p>
|
||||
|
||||
<p>Solicite licencias anuales adicionales a su ${dealer} para asegurarse de tener suficiente inventario.</p>
|
||||
|
||||
<p>Puede asignar licencias a los usuarios de forma automática o manual. A los usuarios con la opción Asignación automática habilitada (predeterminada) se les asignará su licencia automáticamente desde su inventario de licencias en la fecha de vencimiento. Si desactiva la opción Asignar automáticamente, deberá asignar licencias manualmente.</p>
|
||||
|
||||
<p>Inicie sesión en ODMS Cloud para configurar su configuración de usuario y verificar la fecha de vencimiento de la licencia.<br>
|
||||
URL: <a href="https://odmscloud.omsystem.com/">https://odmscloud.omsystem.com/</a></p>
|
||||
|
||||
<p>Si necesita ayuda con respecto a ODMS Cloud, comuníquese con ${dealer}.</p>
|
||||
|
||||
<p>Si recibió este correo electrónico por error, elimínelo de su sistema.<br>
|
||||
Este es un correo electrónico generado automáticamente y este buzón no está monitoreado. Por favor, no responda.</p>
|
||||
|
||||
|
||||
<h3><Français></h3>
|
||||
<p>Chère/Cher ${companyName},</p>
|
||||
|
||||
<p>Une ou plusieurs de vos licences ODMS Cloud attribuées expireront dans les 14 jours. Le nombre de licences non attribuées dans votre inventaire est insuffisant pour être délivré aux utilisateurs dont les licences arrivent à expiration.</p>
|
||||
|
||||
<p>Nombre de licences insuffisant: ${shortage}</p>
|
||||
|
||||
<p>Veuillez commander des licences annuelles supplémentaires auprès de votre ${dealer} pour vous assurer que vous disposez d'un inventaire suffisant.</p>
|
||||
|
||||
<p>Vous pouvez attribuer automatiquement ou manuellement des licences aux utilisateurs. Les utilisateurs dont l'option d'attribution automatique est activée (par défaut) verront leur licence automatiquement attribuée à partir de votre inventaire de licences à la date d'expiration. Si vous désactivez l'option Attribution automatique, vous devez attribuer manuellement des licences.</p>
|
||||
|
||||
<p>Veuillez vous connecter à ODMS Cloud pour configurer vos paramètres utilisateur et vérifier la date d'expiration de la licence.<br>
|
||||
URL: <a href="https://odmscloud.omsystem.com/">https://odmscloud.omsystem.com/</a></p>
|
||||
|
||||
<p>Si vous avez besoin d'assistance concernant ODMS Cloud, veuillez contacter ${dealer}.</p>
|
||||
|
||||
<p>Si vous avez reçu cet e-mail par erreur, veuillez supprimer cet e-mail de votre système.<br>
|
||||
Il s'agit d'un e-mail généré automatiquement et cette boîte aux lettres n'est pas surveillée. Merci de ne pas répondre.</p>`,
|
||||
};
|
||||
}
|
||||
@ -0,0 +1,156 @@
|
||||
/**
|
||||
* メールコンテンツを作成する(ライセンス失効警告)
|
||||
* @param companyName
|
||||
* @param ExpiringSoonUserCount
|
||||
* @param dealer
|
||||
* @returns メールのサブジェクトとコンテンツ
|
||||
*/
|
||||
export async function createMailContentOfLicenseExpiringSoon(
|
||||
companyName: string,
|
||||
ExpiringSoonUserCount: number,
|
||||
dealer: string | undefined
|
||||
): Promise<{
|
||||
subject: string;
|
||||
text: string;
|
||||
html: string;
|
||||
}> {
|
||||
return {
|
||||
// subject ////////////////////////////////////////////////////////////////////
|
||||
subject: "License Expiration Warning [U-104]",
|
||||
// text ////////////////////////////////////////////////////////////////////
|
||||
text: `<English>
|
||||
Dear ${companyName},
|
||||
|
||||
One or more of your assigned ODMS Cloud licenses will expire today.
|
||||
Number of licenses expiring: ${ExpiringSoonUserCount}
|
||||
|
||||
If you do not have a sufficient number of licenses, you will need to order annual licenses from your ${dealer} and assign them to your users whose licenses are expiring.
|
||||
|
||||
Please log in to ODMS Cloud to configure your user setting and verify the license expiration date.
|
||||
URL: https://odmscloud.omsystem.com/
|
||||
|
||||
If you need support regarding ODMS Cloud, please contact ${dealer}.
|
||||
|
||||
If you have received this e-mail in error, please delete this e-mail from your system.
|
||||
This is an automatically generated e-mail and this mailbox is not monitored. Please do not reply.
|
||||
|
||||
|
||||
<Deutsch>
|
||||
Sehr geehrte(r) ${companyName},
|
||||
|
||||
Eine oder mehrere Ihrer zugewiesenen ODMS Cloud-Lizenzen laufen heute ab.
|
||||
Anzahl der auslaufenden Lizenzen: ${ExpiringSoonUserCount}
|
||||
|
||||
Wenn Sie nicht über genügend Lizenzen verfügen, müssen Sie Jahreslizenzen bei Ihrem ${dealer} bestellen und diese Ihren Benutzern zuweisen, deren Lizenzen ablaufen.
|
||||
|
||||
Bitte melden Sie sich bei ODMS Cloud an, um Ihre Benutzereinstellungen zu konfigurieren und das Ablaufdatum der Lizenz zu überprüfen.
|
||||
URL: https://odmscloud.omsystem.com/
|
||||
|
||||
Wenn Sie Unterstützung bezüglich ODMS benötigen, wenden Sie sich bitte an ${dealer}.
|
||||
|
||||
Wenn Sie diese E-Mail fälschlicherweise erhalten haben, löschen Sie diese E-Mail bitte aus Ihrem System.
|
||||
Dies ist eine automatisch generierte E-Mail und dieses Postfach wird nicht überwacht. Bitte nicht antworten.
|
||||
|
||||
|
||||
<Español>
|
||||
Estimado(a) ${companyName},
|
||||
|
||||
Una o más de sus licencias de ODMS Cloud asignadas caducarán hoy.
|
||||
Número de licencias que vencen: ${ExpiringSoonUserCount}
|
||||
|
||||
Si no tiene una cantidad suficiente de licencias, deberá solicitar licencias anuales a su ${dealer} y asignarlas a los usuarios cuyas licencias están por vencer.
|
||||
|
||||
Inicie sesión en ODMS Cloud para configurar su configuración de usuario y verificar la fecha de vencimiento de la licencia.
|
||||
URL: https://odmscloud.omsystem.com/
|
||||
|
||||
Si necesita ayuda con respecto a ODMS Cloud, comuníquese con ${dealer}.
|
||||
|
||||
Si recibió este correo electrónico por error, elimínelo de su sistema.
|
||||
Este es un correo electrónico generado automáticamente y este buzón no está monitoreado. Por favor, no responda.
|
||||
|
||||
|
||||
<Français>
|
||||
Chère/Cher ${companyName},
|
||||
|
||||
Une ou plusieurs de vos licences ODMS Cloud attribuées expireront aujourd'hui.
|
||||
Nombre de licences arrivant à expiration: ${ExpiringSoonUserCount}
|
||||
|
||||
Si vous ne disposez pas d'un nombre suffisant de licences, vous devrez commander des licences annuelles auprès de votre ${dealer} et les attribuer à vos utilisateurs dont les licences arrivent à expiration.
|
||||
|
||||
Veuillez vous connecter à ODMS Cloud pour configurer vos paramètres utilisateur et vérifier la date d'expiration de la licence.
|
||||
URL: https://odmscloud.omsystem.com/
|
||||
|
||||
Si vous avez besoin d'assistance concernant ODMS Cloud, veuillez contacter ${dealer}.
|
||||
|
||||
Si vous avez reçu cet e-mail par erreur, veuillez supprimer cet e-mail de votre système.
|
||||
Il s'agit d'un e-mail généré automatiquement et cette boîte aux lettres n'est pas surveillée. Merci de ne pas répondre.`,
|
||||
// html ////////////////////////////////////////////////////////////////////
|
||||
html: `<h3><English></h3>
|
||||
<p>Dear ${companyName},</p>
|
||||
|
||||
<p>One or more of your assigned ODMS Cloud licenses will expire today.<br>
|
||||
Number of licenses expiring: ${ExpiringSoonUserCount}</p>
|
||||
|
||||
<p>If you do not have a sufficient number of licenses, you will need to order annual licenses from your ${dealer} and assign them to your users whose licenses are expiring.</p>
|
||||
|
||||
<p>Please log in to ODMS Cloud to configure your user setting and verify the license expiration date.<br>
|
||||
URL: <a href="https://odmscloud.omsystem.com/">https://odmscloud.omsystem.com/</a></p>
|
||||
|
||||
<p>If you need support regarding ODMS Cloud, please contact ${dealer}.</p>
|
||||
|
||||
<p>If you have received this e-mail in error, please delete this e-mail from your system.<br>
|
||||
This is an automatically generated e-mail and this mailbox is not monitored. Please do not reply.</p>
|
||||
|
||||
|
||||
<h3><Deutsch></h3>
|
||||
<p>Sehr geehrte(r) ${companyName},</p>
|
||||
|
||||
<p>Eine oder mehrere Ihrer zugewiesenen ODMS Cloud-Lizenzen laufen heute ab.<br>
|
||||
Anzahl der auslaufenden Lizenzen: ${ExpiringSoonUserCount}</p>
|
||||
|
||||
<p>Wenn Sie nicht über genügend Lizenzen verfügen, müssen Sie Jahreslizenzen bei Ihrem ${dealer} bestellen und diese Ihren Benutzern zuweisen, deren Lizenzen ablaufen.</p>
|
||||
|
||||
<p>Bitte melden Sie sich bei ODMS Cloud an, um Ihre Benutzereinstellungen zu konfigurieren und das Ablaufdatum der Lizenz zu überprüfen.<br>
|
||||
URL: <a href="https://odmscloud.omsystem.com/">https://odmscloud.omsystem.com/</a></p>
|
||||
|
||||
<p>Wenn Sie Unterstützung bezüglich ODMS benötigen, wenden Sie sich bitte an ${dealer}.</p>
|
||||
|
||||
<p>Wenn Sie diese E-Mail fälschlicherweise erhalten haben, löschen Sie diese E-Mail bitte aus Ihrem System.<br>
|
||||
Dies ist eine automatisch generierte E-Mail und dieses Postfach wird nicht überwacht. Bitte nicht antworten.</p>
|
||||
|
||||
|
||||
<h3><Español></h3>
|
||||
<p>Estimado(a) ${companyName},</p>
|
||||
|
||||
<p>Una o más de sus licencias de ODMS Cloud asignadas caducarán hoy.<br>
|
||||
Número de licencias que vencen: ${ExpiringSoonUserCount}</p>
|
||||
|
||||
<p>Si no tiene una cantidad suficiente de licencias, deberá solicitar licencias anuales a su ${dealer} y asignarlas a los usuarios cuyas licencias están por vencer.</p>
|
||||
|
||||
<p>Inicie sesión en ODMS Cloud para configurar su configuración de usuario y verificar la fecha de vencimiento de la licencia.<br>
|
||||
URL: <a href="https://odmscloud.omsystem.com/">https://odmscloud.omsystem.com/</a></p>
|
||||
|
||||
<p>Si necesita ayuda con respecto a ODMS Cloud, comuníquese con ${dealer}.</p>
|
||||
|
||||
<p>Si recibió este correo electrónico por error, elimínelo de su sistema.<br>
|
||||
Este es un correo electrónico generado automáticamente y este buzón no está monitoreado. Por favor, no responda.</p>
|
||||
|
||||
|
||||
<h3><Français></h3>
|
||||
<p>Chère/Cher ${companyName},</p>
|
||||
|
||||
<p>Une ou plusieurs de vos licences ODMS Cloud attribuées expireront aujourd'hui.<br>
|
||||
Nombre de licences arrivant à expiration: ${ExpiringSoonUserCount}</p>
|
||||
|
||||
<p>Si vous ne disposez pas d'un nombre suffisant de licences, vous devrez commander des licences annuelles auprès de votre ${dealer} et les attribuer à vos utilisateurs dont les licences arrivent à expiration.</p>
|
||||
|
||||
<p>Veuillez vous connecter à ODMS Cloud pour configurer vos paramètres utilisateur et vérifier la date d'expiration de la licence.<br>
|
||||
URL: <a href="https://odmscloud.omsystem.com/">https://odmscloud.omsystem.com/</a></p>
|
||||
|
||||
<p>Si vous avez besoin d'assistance concernant ODMS Cloud, veuillez contacter ${dealer}.</p>
|
||||
|
||||
<p>Si vous avez reçu cet e-mail par erreur, veuillez supprimer cet e-mail de votre système.<br>
|
||||
Il s'agit d'un e-mail généré automatiquement et cette boîte aux lettres n'est pas surveillée. Merci de ne pas répondre.</p>
|
||||
`,
|
||||
};
|
||||
}
|
||||
@ -8,43 +8,6 @@ export class SendGridService {
|
||||
}
|
||||
sendgrid.setApiKey(process.env.SENDGRID_API_KEY);
|
||||
}
|
||||
/**
|
||||
* メールコンテンツを作成する(ライセンス不足)
|
||||
* @param accountId 認証対象のユーザーが所属するアカウントのID
|
||||
* @param userId 認証対象のユーザーのID
|
||||
* @param email 認証対象のユーザーのメールアドレス
|
||||
* @returns メールのサブジェクトとコンテンツ
|
||||
*/
|
||||
async createMailContentOfLicenseShortage(): Promise<{
|
||||
subject: string;
|
||||
text: string;
|
||||
html: string;
|
||||
}> {
|
||||
return {
|
||||
subject: "ライセンス在庫不足通知",
|
||||
text: `ライセンス在庫不足通知:本文`,
|
||||
html: `<p>ライセンス在庫不足通知:本文</p>`,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* メールコンテンツを作成する(ライセンス不足)
|
||||
* @param accountId 認証対象のユーザーが所属するアカウントのID
|
||||
* @param userId 認証対象のユーザーのID
|
||||
* @param email 認証対象のユーザーのメールアドレス
|
||||
* @returns メールのサブジェクトとコンテンツ
|
||||
*/
|
||||
async createMailContentOfLicenseExpiringSoon(): Promise<{
|
||||
subject: string;
|
||||
text: string;
|
||||
html: string;
|
||||
}> {
|
||||
return {
|
||||
subject: "ライセンス失効警告 ",
|
||||
text: `ライセンス失効警告:本文`,
|
||||
html: `<p>ライセンス失効警告:本文</p>`,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* メールを送信する
|
||||
|
||||
@ -41,14 +41,6 @@ describe("licenseAlert", () => {
|
||||
const sendgridMock = new SendGridServiceMock() as SendGridService;
|
||||
const adb2cMock = new AdB2cServiceMock() as AdB2cService;
|
||||
// 呼び出し回数でテスト成否を判定
|
||||
const spyShortage = jest.spyOn(
|
||||
sendgridMock,
|
||||
"createMailContentOfLicenseShortage"
|
||||
);
|
||||
const spyExpirySoon = jest.spyOn(
|
||||
sendgridMock,
|
||||
"createMailContentOfLicenseExpiringSoon"
|
||||
);
|
||||
const spySend = jest.spyOn(sendgridMock, "sendMail");
|
||||
|
||||
const currentDate = new DateWithZeroTime();
|
||||
@ -72,8 +64,6 @@ describe("licenseAlert", () => {
|
||||
);
|
||||
|
||||
await licenseAlertProcessing(context, source, sendgridMock, adb2cMock);
|
||||
expect(spyShortage.mock.calls).toHaveLength(1);
|
||||
expect(spyExpirySoon.mock.calls).toHaveLength(0);
|
||||
expect(spySend.mock.calls).toHaveLength(1);
|
||||
});
|
||||
|
||||
@ -84,14 +74,6 @@ describe("licenseAlert", () => {
|
||||
const adb2cMock = new AdB2cServiceMock() as AdB2cService;
|
||||
|
||||
// 呼び出し回数でテスト成否を判定
|
||||
const spyShortage = jest.spyOn(
|
||||
sendgridMock,
|
||||
"createMailContentOfLicenseShortage"
|
||||
);
|
||||
const spyExpirySoon = jest.spyOn(
|
||||
sendgridMock,
|
||||
"createMailContentOfLicenseExpiringSoon"
|
||||
);
|
||||
const spySend = jest.spyOn(sendgridMock, "sendMail");
|
||||
|
||||
const currentDate = new DateWithZeroTime();
|
||||
@ -115,8 +97,6 @@ describe("licenseAlert", () => {
|
||||
);
|
||||
|
||||
await licenseAlertProcessing(context, source, sendgridMock, adb2cMock);
|
||||
expect(spyShortage.mock.calls).toHaveLength(1);
|
||||
expect(spyExpirySoon.mock.calls).toHaveLength(1);
|
||||
expect(spySend.mock.calls).toHaveLength(2);
|
||||
});
|
||||
|
||||
@ -127,14 +107,6 @@ describe("licenseAlert", () => {
|
||||
const adb2cMock = new AdB2cServiceMock() as AdB2cService;
|
||||
|
||||
// 呼び出し回数でテスト成否を判定
|
||||
const spyShortage = jest.spyOn(
|
||||
sendgridMock,
|
||||
"createMailContentOfLicenseShortage"
|
||||
);
|
||||
const spyExpirySoon = jest.spyOn(
|
||||
sendgridMock,
|
||||
"createMailContentOfLicenseExpiringSoon"
|
||||
);
|
||||
const spySend = jest.spyOn(sendgridMock, "sendMail");
|
||||
|
||||
const currentDate = new DateWithZeroTime();
|
||||
@ -171,8 +143,6 @@ describe("licenseAlert", () => {
|
||||
);
|
||||
|
||||
await licenseAlertProcessing(context, source, sendgridMock, adb2cMock);
|
||||
expect(spyShortage.mock.calls).toHaveLength(0);
|
||||
expect(spyExpirySoon.mock.calls).toHaveLength(0);
|
||||
expect(spySend.mock.calls).toHaveLength(0);
|
||||
});
|
||||
|
||||
@ -183,14 +153,6 @@ describe("licenseAlert", () => {
|
||||
const adb2cMock = new AdB2cServiceMock() as AdB2cService;
|
||||
|
||||
// 呼び出し回数でテスト成否を判定
|
||||
const spyShortage = jest.spyOn(
|
||||
sendgridMock,
|
||||
"createMailContentOfLicenseShortage"
|
||||
);
|
||||
const spyExpirySoon = jest.spyOn(
|
||||
sendgridMock,
|
||||
"createMailContentOfLicenseExpiringSoon"
|
||||
);
|
||||
const spySend = jest.spyOn(sendgridMock, "sendMail");
|
||||
|
||||
const currentDate = new DateWithZeroTime();
|
||||
@ -214,52 +176,12 @@ describe("licenseAlert", () => {
|
||||
);
|
||||
|
||||
await licenseAlertProcessing(context, source, sendgridMock, adb2cMock);
|
||||
expect(spyShortage.mock.calls).toHaveLength(1);
|
||||
expect(spyExpirySoon.mock.calls).toHaveLength(0);
|
||||
expect(spySend.mock.calls).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
|
||||
// テスト用sendgrid
|
||||
export class SendGridServiceMock {
|
||||
/**
|
||||
* メールコンテンツを作成する(ライセンス不足)
|
||||
* @param accountId 認証対象のユーザーが所属するアカウントのID
|
||||
* @param userId 認証対象のユーザーのID
|
||||
* @param email 認証対象のユーザーのメールアドレス
|
||||
* @returns メールのサブジェクトとコンテンツ
|
||||
*/
|
||||
async createMailContentOfLicenseShortage(): Promise<{
|
||||
subject: string;
|
||||
text: string;
|
||||
html: string;
|
||||
}> {
|
||||
return {
|
||||
subject: "ライセンス在庫不足通知",
|
||||
text: `ライセンス在庫不足通知:本文`,
|
||||
html: `<p>ライセンス在庫不足通知:本文</p>`,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* メールコンテンツを作成する(ライセンス不足)
|
||||
* @param accountId 認証対象のユーザーが所属するアカウントのID
|
||||
* @param userId 認証対象のユーザーのID
|
||||
* @param email 認証対象のユーザーのメールアドレス
|
||||
* @returns メールのサブジェクトとコンテンツ
|
||||
*/
|
||||
async createMailContentOfLicenseExpiringSoon(): Promise<{
|
||||
subject: string;
|
||||
text: string;
|
||||
html: string;
|
||||
}> {
|
||||
return {
|
||||
subject: "ライセンス失効警告",
|
||||
text: `ライセンス失効警告:本文`,
|
||||
html: `<p>ライセンス失効警告:本文</p>`,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* メールを送信する
|
||||
* @param to
|
||||
|
||||
107
dictation_server/package-lock.json
generated
107
dictation_server/package-lock.json
generated
@ -11,7 +11,7 @@
|
||||
"dependencies": {
|
||||
"@azure/identity": "^3.1.3",
|
||||
"@azure/keyvault-secrets": "^4.6.0",
|
||||
"@azure/notification-hubs": "^1.0.2",
|
||||
"@azure/notification-hubs": "^1.0.3",
|
||||
"@azure/storage-blob": "^12.14.0",
|
||||
"@microsoft/microsoft-graph-client": "^3.0.5",
|
||||
"@nestjs/axios": "^0.1.0",
|
||||
@ -341,6 +341,22 @@
|
||||
"openapi-types": ">=7"
|
||||
}
|
||||
},
|
||||
"node_modules/@azure-rest/core-client": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@azure-rest/core-client/-/core-client-1.1.4.tgz",
|
||||
"integrity": "sha512-RUIQOA8T0WcbNlddr8hjl2MuC5GVRqmMwPXqBVsgvdKesLy+eg3y/6nf3qe2fvcJMI1gF6VtgU5U4hRaR4w4ag==",
|
||||
"dependencies": {
|
||||
"@azure/abort-controller": "^1.1.0",
|
||||
"@azure/core-auth": "^1.3.0",
|
||||
"@azure/core-rest-pipeline": "^1.5.0",
|
||||
"@azure/core-tracing": "^1.0.1",
|
||||
"@azure/core-util": "^1.0.0",
|
||||
"tslib": "^2.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@azure/abort-controller": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-1.1.0.tgz",
|
||||
@ -353,15 +369,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@azure/core-auth": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@azure/core-auth/-/core-auth-1.4.0.tgz",
|
||||
"integrity": "sha512-HFrcTgmuSuukRf/EdPmqBrc5l6Q5Uu+2TbuhaKbgaCpP2TfAeiNaQPAadxO+CYBRHGUzIDteMAjFspFLDLnKVQ==",
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@azure/core-auth/-/core-auth-1.5.0.tgz",
|
||||
"integrity": "sha512-udzoBuYG1VBoHVohDTrvKjyzel34zt77Bhp7dQntVGGD0ehVq48owENbBG8fIgkHRNUBQH5k1r0hpoMu5L8+kw==",
|
||||
"dependencies": {
|
||||
"@azure/abort-controller": "^1.0.0",
|
||||
"@azure/core-util": "^1.1.0",
|
||||
"tslib": "^2.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.0.0"
|
||||
"node": ">=14.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@azure/core-client": {
|
||||
@ -443,11 +460,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@azure/core-lro": {
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@azure/core-lro/-/core-lro-2.5.1.tgz",
|
||||
"integrity": "sha512-JHQy/bA3NOz2WuzOi5zEk6n/TJdAropupxUT521JIJvW7EXV2YN2SFYZrf/2RHeD28QAClGdynYadZsbmP+nyQ==",
|
||||
"version": "2.5.4",
|
||||
"resolved": "https://registry.npmjs.org/@azure/core-lro/-/core-lro-2.5.4.tgz",
|
||||
"integrity": "sha512-3GJiMVH7/10bulzOKGrrLeG/uCBH/9VtxqaMcB9lIqAeamI/xYQSHJL/KcsLDuH+yTjYpro/u6D/MuRe4dN70Q==",
|
||||
"dependencies": {
|
||||
"@azure/abort-controller": "^1.0.0",
|
||||
"@azure/core-util": "^1.2.0",
|
||||
"@azure/logger": "^1.0.0",
|
||||
"tslib": "^2.2.0"
|
||||
},
|
||||
@ -467,23 +485,22 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@azure/core-rest-pipeline": {
|
||||
"version": "1.10.2",
|
||||
"resolved": "https://registry.npmjs.org/@azure/core-rest-pipeline/-/core-rest-pipeline-1.10.2.tgz",
|
||||
"integrity": "sha512-e3WzAsRKLor5EgK2bQqR1OY5D7VBqzORHtlqtygZZQGCYOIBsynqrZBa8MFD1Ue9r8TPtofOLditalnlQHS45Q==",
|
||||
"version": "1.12.2",
|
||||
"resolved": "https://registry.npmjs.org/@azure/core-rest-pipeline/-/core-rest-pipeline-1.12.2.tgz",
|
||||
"integrity": "sha512-wLLJQdL4v1yoqYtEtjKNjf8pJ/G/BqVomAWxcKOR1KbZJyCEnCv04yks7Y1NhJ3JzxbDs307W67uX0JzklFdCg==",
|
||||
"dependencies": {
|
||||
"@azure/abort-controller": "^1.0.0",
|
||||
"@azure/core-auth": "^1.4.0",
|
||||
"@azure/core-tracing": "^1.0.1",
|
||||
"@azure/core-util": "^1.0.0",
|
||||
"@azure/core-util": "^1.3.0",
|
||||
"@azure/logger": "^1.0.0",
|
||||
"form-data": "^4.0.0",
|
||||
"http-proxy-agent": "^5.0.0",
|
||||
"https-proxy-agent": "^5.0.0",
|
||||
"tslib": "^2.2.0",
|
||||
"uuid": "^8.3.0"
|
||||
"tslib": "^2.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
"node": ">=16.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@azure/core-tracing": {
|
||||
@ -498,23 +515,23 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@azure/core-util": {
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@azure/core-util/-/core-util-1.3.2.tgz",
|
||||
"integrity": "sha512-2bECOUh88RvL1pMZTcc6OzfobBeWDBf5oBbhjIhT1MV9otMVWCzpOJkkiKtrnO88y5GGBelgY8At73KGAdbkeQ==",
|
||||
"version": "1.6.1",
|
||||
"resolved": "https://registry.npmjs.org/@azure/core-util/-/core-util-1.6.1.tgz",
|
||||
"integrity": "sha512-h5taHeySlsV9qxuK64KZxy4iln1BtMYlNt5jbuEFN3UFSAd1EwKg/Gjl5a6tZ/W8t6li3xPnutOx7zbDyXnPmQ==",
|
||||
"dependencies": {
|
||||
"@azure/abort-controller": "^1.0.0",
|
||||
"tslib": "^2.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
"node": ">=16.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@azure/core-xml": {
|
||||
"version": "1.3.3",
|
||||
"resolved": "https://registry.npmjs.org/@azure/core-xml/-/core-xml-1.3.3.tgz",
|
||||
"integrity": "sha512-Go/xGz7nGqVINsD9O7gOfe8uiR1S+IFcw9WTUPJHSzoFT6F5ZWjXIIlSikLZm77TtmxzXGnQYjjiZIoIZ4x14A==",
|
||||
"version": "1.3.4",
|
||||
"resolved": "https://registry.npmjs.org/@azure/core-xml/-/core-xml-1.3.4.tgz",
|
||||
"integrity": "sha512-B1xI79Ur/u+KR69fGTcsMNj8KDjBSqAy0Ys6Byy4Qm1CqoUy7gCT5A7Pej0EBWRskuH6bpCwrAnosfmQEalkcg==",
|
||||
"dependencies": {
|
||||
"fast-xml-parser": "^4.0.8",
|
||||
"fast-xml-parser": "^4.2.4",
|
||||
"tslib": "^2.2.0"
|
||||
},
|
||||
"engines": {
|
||||
@ -628,25 +645,31 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@azure/notification-hubs": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@azure/notification-hubs/-/notification-hubs-1.0.2.tgz",
|
||||
"integrity": "sha512-INtgq8uFQpncwbKm4It8M0GkKIePNDNybhuXs4cQPf5H0i9CbfFEt2c6LtT1AdEzbWfUhjsmU5y0p3YDmecwwg==",
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@azure/notification-hubs/-/notification-hubs-1.0.3.tgz",
|
||||
"integrity": "sha512-IWzIO2nKwM+9CWgnTsMyZhXxR7q3n3/aXpJiqUn1U3xHXTtHVE+joZ/AL9fCZTEBVB1PQvbrjp8VZvwEptqJ/Q==",
|
||||
"dependencies": {
|
||||
"@azure-rest/core-client": "^1.1.4",
|
||||
"@azure/abort-controller": "^1.1.0",
|
||||
"@azure/core-client": "^1.6.1",
|
||||
"@azure/core-lro": "^2.4.0",
|
||||
"@azure/core-paging": "^1.3.0",
|
||||
"@azure/core-rest-pipeline": "^1.8.1",
|
||||
"@azure/core-auth": "^1.5.0",
|
||||
"@azure/core-lro": "^2.5.4",
|
||||
"@azure/core-paging": "^1.5.0",
|
||||
"@azure/core-rest-pipeline": "^1.12.2",
|
||||
"@azure/core-tracing": "^1.0.1",
|
||||
"@azure/core-util": "^1.3.0",
|
||||
"@azure/core-xml": "^1.3.1",
|
||||
"@azure/logger": "^1.0.3",
|
||||
"tslib": "^2.4.0"
|
||||
"@azure/core-util": "^1.6.1",
|
||||
"@azure/core-xml": "^1.3.4",
|
||||
"@azure/logger": "^1.0.4",
|
||||
"tslib": "^2.6.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
"node": ">=18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@azure/notification-hubs/node_modules/tslib": {
|
||||
"version": "2.6.2",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",
|
||||
"integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q=="
|
||||
},
|
||||
"node_modules/@azure/storage-blob": {
|
||||
"version": "12.14.0",
|
||||
"resolved": "https://registry.npmjs.org/@azure/storage-blob/-/storage-blob-12.14.0.tgz",
|
||||
@ -5899,17 +5922,17 @@
|
||||
"integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA=="
|
||||
},
|
||||
"node_modules/fast-xml-parser": {
|
||||
"version": "4.2.6",
|
||||
"resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.2.6.tgz",
|
||||
"integrity": "sha512-Xo1qV++h/Y3Ng8dphjahnYe+rGHaaNdsYOBWL9Y9GCPKpNKilJtilvWkLcI9f9X2DoKTLsZsGYAls5+JL5jfLA==",
|
||||
"version": "4.3.2",
|
||||
"resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.3.2.tgz",
|
||||
"integrity": "sha512-rmrXUXwbJedoXkStenj1kkljNF7ugn5ZjR9FJcwmCfcCbtOMDghPajbc+Tck6vE6F5XsDmx+Pr2le9fw8+pXBg==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "paypal",
|
||||
"url": "https://paypal.me/naturalintelligence"
|
||||
},
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/NaturalIntelligence"
|
||||
},
|
||||
{
|
||||
"type": "paypal",
|
||||
"url": "https://paypal.me/naturalintelligence"
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
|
||||
@ -31,7 +31,7 @@
|
||||
"dependencies": {
|
||||
"@azure/identity": "^3.1.3",
|
||||
"@azure/keyvault-secrets": "^4.6.0",
|
||||
"@azure/notification-hubs": "^1.0.2",
|
||||
"@azure/notification-hubs": "^1.0.3",
|
||||
"@azure/storage-blob": "^12.14.0",
|
||||
"@microsoft/microsoft-graph-client": "^3.0.5",
|
||||
"@nestjs/axios": "^0.1.0",
|
||||
|
||||
@ -2077,6 +2077,14 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "不正なパラメータ",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": { "$ref": "#/components/schemas/ErrorResponse" }
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "認証エラー",
|
||||
"content": {
|
||||
@ -4180,7 +4188,7 @@
|
||||
"properties": {
|
||||
"authorId": {
|
||||
"type": "string",
|
||||
"description": "ログインしたユーザーのAuthorID(Authorでない場合は空文字)"
|
||||
"description": "ログインしたユーザーのAuthorID(Authorでない場合はundefined)"
|
||||
},
|
||||
"authorIdList": {
|
||||
"description": "属しているアカウントのAuthorID List(全て)",
|
||||
@ -4215,7 +4223,6 @@
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"authorId",
|
||||
"authorIdList",
|
||||
"workTypeList",
|
||||
"isEncrypted",
|
||||
|
||||
@ -39,6 +39,7 @@ export const ErrorCodes = [
|
||||
'E010501', // アカウント不在エラー
|
||||
'E010502', // アカウント情報変更不可エラー
|
||||
'E010503', // 代行操作不許可エラー
|
||||
'E010504', // アカウントロックエラー
|
||||
'E010601', // タスク変更不可エラー(タスクが変更できる状態でない、またはタスクが存在しない)
|
||||
'E010602', // タスク変更権限不足エラー
|
||||
'E010603', // タスク不在エラー
|
||||
@ -54,6 +55,7 @@ export const ErrorCodes = [
|
||||
'E010809', // ライセンス発行キャンセル不可エラー(ステータスが変えられている場合)
|
||||
'E010810', // ライセンス発行キャンセル不可エラー(発行から一定期間経過した場合)
|
||||
'E010811', // ライセンス発行キャンセル不可エラー(発行したライセンスが割り当てされている場合)
|
||||
'E010812', // ライセンス未割当エラー
|
||||
'E010908', // タイピストグループ不在エラー
|
||||
'E011001', // ワークタイプ重複エラー
|
||||
'E011002', // ワークタイプ登録上限超過エラー
|
||||
|
||||
@ -28,6 +28,7 @@ export const errors: Errors = {
|
||||
E010501: 'Account not Found Error.',
|
||||
E010502: 'Account information cannot be changed Error.',
|
||||
E010503: 'Delegation not allowed Error.',
|
||||
E010504: 'Account is locked Error.',
|
||||
E010601: 'Task is not Editable Error',
|
||||
E010602: 'No task edit permissions Error',
|
||||
E010603: 'Task not found Error.',
|
||||
@ -43,6 +44,7 @@ export const errors: Errors = {
|
||||
E010809: 'Already license order status changed Error',
|
||||
E010810: 'Cancellation period expired error',
|
||||
E010811: 'Already license allocated Error',
|
||||
E010812: 'License not allocated Error',
|
||||
E010908: 'Typist Group not exist Error',
|
||||
E011001: 'This WorkTypeID already used Error',
|
||||
E011002: 'WorkTypeID create limit exceeded Error',
|
||||
|
||||
@ -4,8 +4,5 @@ export const makeContext = (
|
||||
externalId: string,
|
||||
delegationId?: string,
|
||||
): Context => {
|
||||
return {
|
||||
trackingId: externalId,
|
||||
delegationId: delegationId,
|
||||
};
|
||||
return new Context(externalId, delegationId);
|
||||
};
|
||||
|
||||
@ -7,4 +7,19 @@ export class Context {
|
||||
* APIの代行操作ユーザーを追跡するためのID
|
||||
*/
|
||||
delegationId?: string | undefined;
|
||||
|
||||
constructor(externalId: string, delegationId?: string) {
|
||||
this.trackingId = externalId;
|
||||
this.delegationId = delegationId;
|
||||
}
|
||||
/**
|
||||
* ログにユーザーを特定する情報を出力する
|
||||
*/
|
||||
getTrackingId(): string {
|
||||
if (this.delegationId) {
|
||||
return `${this.trackingId} by ${this.delegationId}`;
|
||||
} else {
|
||||
return this.trackingId;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,13 +0,0 @@
|
||||
/*
|
||||
通知メッセージコード作成方針
|
||||
M+6桁(数字)で構成する。
|
||||
- 1~2桁目の値は種類(正常系、以上系...)
|
||||
- 3~4桁目の値は関連機能(タスク、ユーザー、ファイル...)
|
||||
- 5~6桁目の値は任意の重複しない値
|
||||
ex)
|
||||
E00XXXX : 正常系メッセージ
|
||||
E01XXXX : 以上系メッセージ
|
||||
EXX00XX : 全般
|
||||
EXX01XX : タスク関連
|
||||
*/
|
||||
export const NotifyMessageCodes = ['M000101'] as const;
|
||||
@ -1,7 +0,0 @@
|
||||
import { notifyMessages } from './message';
|
||||
import { NotifyMessageCodeType } from './types/types';
|
||||
|
||||
export const makeNotifyMessage = (code: NotifyMessageCodeType): string => {
|
||||
const msg = notifyMessages[code];
|
||||
return msg;
|
||||
};
|
||||
@ -1,6 +0,0 @@
|
||||
import { NotifyMessages } from './types/types';
|
||||
|
||||
// エラーコードとメッセージ対応表
|
||||
export const notifyMessages: NotifyMessages = {
|
||||
M000101: 'You are assigned to Typist.',
|
||||
};
|
||||
@ -1,7 +1,6 @@
|
||||
import { NotifyMessageCodes } from '../code';
|
||||
|
||||
export type NotifyMessageCodeType = (typeof NotifyMessageCodes)[number];
|
||||
|
||||
export type NotifyMessages = {
|
||||
[P in NotifyMessageCodeType]: string;
|
||||
export type NotificationBody = {
|
||||
filename: string;
|
||||
authorId: string;
|
||||
priority: string;
|
||||
uploadedAt: string;
|
||||
};
|
||||
|
||||
@ -185,6 +185,11 @@ export const overrideBlobstorageService = <TService>(
|
||||
accountId: number,
|
||||
country: string,
|
||||
) => Promise<boolean>;
|
||||
publishUploadSas?: (
|
||||
context: Context,
|
||||
accountId: number,
|
||||
country: string,
|
||||
) => Promise<string>;
|
||||
publishTemplateUploadSas?: (
|
||||
context: Context,
|
||||
accountId: number,
|
||||
@ -212,6 +217,12 @@ export const overrideBlobstorageService = <TService>(
|
||||
writable: true,
|
||||
});
|
||||
}
|
||||
if (overrides.publishUploadSas) {
|
||||
Object.defineProperty(obj, obj.publishUploadSas.name, {
|
||||
value: overrides.publishUploadSas,
|
||||
writable: true,
|
||||
});
|
||||
}
|
||||
if (overrides.publishTemplateUploadSas) {
|
||||
Object.defineProperty(obj, obj.publishTemplateUploadSas.name, {
|
||||
value: overrides.publishTemplateUploadSas,
|
||||
|
||||
@ -239,6 +239,27 @@ export const OPTION_ITEM_VALUE_TYPE = {
|
||||
LAST_INPUT: 'LastInput',
|
||||
} as const;
|
||||
|
||||
/**
|
||||
* オプションアイテムのタイプ文字列と数値の対応
|
||||
**/
|
||||
export const OPTION_ITEM_VALUE_TYPE_NUMBER: {
|
||||
type: string;
|
||||
value: number;
|
||||
}[] = [
|
||||
{
|
||||
type: OPTION_ITEM_VALUE_TYPE.BLANK,
|
||||
value: 1,
|
||||
},
|
||||
{
|
||||
type: OPTION_ITEM_VALUE_TYPE.DEFAULT,
|
||||
value: 2,
|
||||
},
|
||||
{
|
||||
type: OPTION_ITEM_VALUE_TYPE.LAST_INPUT,
|
||||
value: 3,
|
||||
},
|
||||
];
|
||||
|
||||
/**
|
||||
* ADB2Cユーザのidentity.signInType
|
||||
* @const {string[]}
|
||||
@ -261,3 +282,9 @@ export const TERM_TYPE = {
|
||||
EULA: 'EULA',
|
||||
DPA: 'DPA',
|
||||
} as const;
|
||||
|
||||
/**
|
||||
* 音声ファイルのフォーマット
|
||||
* @const {string}
|
||||
*/
|
||||
export const USER_AUDIO_FORMAT = 'DS2(QP)';
|
||||
|
||||
@ -76,9 +76,9 @@ import { retrieveAuthorizationToken } from '../../common/http/helper';
|
||||
import { AccessToken } from '../../common/token';
|
||||
import jwt from 'jsonwebtoken';
|
||||
import { makeContext } from '../../common/log';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import { AuthService } from '../auth/auth.service';
|
||||
import { makeErrorResponse } from '../../common/error/makeErrorResponse';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
|
||||
@ApiTags('accounts')
|
||||
@Controller('accounts')
|
||||
@ -167,7 +167,24 @@ export class AccountsController {
|
||||
@Req() req: Request,
|
||||
@Body() body: GetLicenseSummaryRequest,
|
||||
): Promise<GetLicenseSummaryResponse> {
|
||||
const accessToken = retrieveAuthorizationToken(req);
|
||||
if (!accessToken) {
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E000107'),
|
||||
HttpStatus.UNAUTHORIZED,
|
||||
);
|
||||
}
|
||||
const decodedAccessToken = jwt.decode(accessToken, { json: true });
|
||||
if (!decodedAccessToken) {
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E000101'),
|
||||
HttpStatus.UNAUTHORIZED,
|
||||
);
|
||||
}
|
||||
const { userId } = decodedAccessToken as AccessToken;
|
||||
const context = makeContext(userId);
|
||||
const response = await this.accountService.getLicenseSummary(
|
||||
context,
|
||||
body.accountId,
|
||||
);
|
||||
return response;
|
||||
@ -317,8 +334,9 @@ export class AccountsController {
|
||||
);
|
||||
}
|
||||
const { userId } = decodedAccessToken as AccessToken;
|
||||
const context = makeContext(userId);
|
||||
|
||||
const typists = await this.accountService.getTypists(userId);
|
||||
const typists = await this.accountService.getTypists(context, userId);
|
||||
|
||||
return { typists };
|
||||
}
|
||||
@ -363,8 +381,12 @@ export class AccountsController {
|
||||
);
|
||||
}
|
||||
const { userId } = decodedAccessToken as AccessToken;
|
||||
const context = makeContext(userId);
|
||||
|
||||
const typistGroups = await this.accountService.getTypistGroups(userId);
|
||||
const typistGroups = await this.accountService.getTypistGroups(
|
||||
context,
|
||||
userId,
|
||||
);
|
||||
|
||||
return { typistGroups };
|
||||
}
|
||||
@ -666,8 +688,31 @@ export class AccountsController {
|
||||
): Promise<GetPartnerLicensesResponse> {
|
||||
const { limit, offset, accountId } = body;
|
||||
|
||||
const accessToken = retrieveAuthorizationToken(req);
|
||||
if (!accessToken) {
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E000107'),
|
||||
HttpStatus.UNAUTHORIZED,
|
||||
);
|
||||
}
|
||||
const decodedAccessToken = jwt.decode(accessToken, { json: true });
|
||||
if (!decodedAccessToken) {
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E000101'),
|
||||
HttpStatus.UNAUTHORIZED,
|
||||
);
|
||||
}
|
||||
const { userId } = decodedAccessToken as AccessToken;
|
||||
|
||||
const context = makeContext(userId);
|
||||
|
||||
const getPartnerLicensesResponse =
|
||||
await this.accountService.getPartnerLicenses(limit, offset, accountId);
|
||||
await this.accountService.getPartnerLicenses(
|
||||
context,
|
||||
limit,
|
||||
offset,
|
||||
accountId,
|
||||
);
|
||||
|
||||
return getPartnerLicensesResponse;
|
||||
}
|
||||
@ -703,8 +748,31 @@ export class AccountsController {
|
||||
): Promise<GetOrderHistoriesResponse> {
|
||||
const { limit, offset, accountId } = body;
|
||||
|
||||
const accessToken = retrieveAuthorizationToken(req);
|
||||
if (!accessToken) {
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E000107'),
|
||||
HttpStatus.UNAUTHORIZED,
|
||||
);
|
||||
}
|
||||
const decodedAccessToken = jwt.decode(accessToken, { json: true });
|
||||
if (!decodedAccessToken) {
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E000101'),
|
||||
HttpStatus.UNAUTHORIZED,
|
||||
);
|
||||
}
|
||||
const { userId } = decodedAccessToken as AccessToken;
|
||||
|
||||
const context = makeContext(userId);
|
||||
|
||||
const getOrderHistoriesResponse =
|
||||
await this.accountService.getOrderHistories(limit, offset, accountId);
|
||||
await this.accountService.getOrderHistories(
|
||||
context,
|
||||
limit,
|
||||
offset,
|
||||
accountId,
|
||||
);
|
||||
|
||||
return getOrderHistoriesResponse;
|
||||
}
|
||||
@ -786,7 +854,8 @@ export class AccountsController {
|
||||
})
|
||||
@ApiOperation({ operationId: 'getDealers' })
|
||||
async getDealers(): Promise<GetDealersResponse> {
|
||||
return await this.accountService.getDealers();
|
||||
const context = makeContext(uuidv4());
|
||||
return await this.accountService.getDealers(context);
|
||||
}
|
||||
|
||||
@Post('/issue/cancel')
|
||||
@ -1460,9 +1529,14 @@ export class AccountsController {
|
||||
async getAccountInfoMinimalAccess(
|
||||
@Body() body: GetAccountInfoMinimalAccessRequest,
|
||||
): Promise<GetAccountInfoMinimalAccessResponse> {
|
||||
const context = makeContext(uuidv4());
|
||||
|
||||
// IDトークンの検証
|
||||
const idToken = await this.authService.getVerifiedIdToken(body.idToken);
|
||||
const isVerified = await this.authService.isVerifiedUser(idToken);
|
||||
const idToken = await this.authService.getVerifiedIdToken(
|
||||
context,
|
||||
body.idToken,
|
||||
);
|
||||
const isVerified = await this.authService.isVerifiedUser(context, idToken);
|
||||
if (!isVerified) {
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E010201'),
|
||||
@ -1470,8 +1544,6 @@ export class AccountsController {
|
||||
);
|
||||
}
|
||||
|
||||
const context = makeContext(idToken.sub);
|
||||
|
||||
const tier = await this.accountService.getAccountInfoMinimalAccess(
|
||||
context,
|
||||
idToken.sub,
|
||||
|
||||
@ -1587,7 +1587,8 @@ describe('AccountsService', () => {
|
||||
licensesRepositoryMockValue,
|
||||
worktypesRepositoryMockValue,
|
||||
);
|
||||
expect(await service.getLicenseSummary(accountId)).toEqual(
|
||||
const context = makeContext(`uuidv4`);
|
||||
expect(await service.getLicenseSummary(context, accountId)).toEqual(
|
||||
expectedAccountLisenceCounts,
|
||||
);
|
||||
});
|
||||
@ -1619,7 +1620,8 @@ describe('AccountsService', () => {
|
||||
licensesRepositoryMockValue,
|
||||
worktypesRepositoryMockValue,
|
||||
);
|
||||
await expect(service.getLicenseSummary(accountId)).rejects.toEqual(
|
||||
const context = makeContext(`uuidv4`);
|
||||
await expect(service.getLicenseSummary(context, accountId)).rejects.toEqual(
|
||||
new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
@ -1653,7 +1655,8 @@ describe('AccountsService', () => {
|
||||
licensesRepositoryMockValue,
|
||||
worktypesRepositoryMockValue,
|
||||
);
|
||||
expect(await service.getTypists(externalId)).toEqual([
|
||||
const context = makeContext(`uuidv4`);
|
||||
expect(await service.getTypists(context, externalId)).toEqual([
|
||||
{ id: 1, name: 'Typist1' },
|
||||
{ id: 2, name: 'Typist2' },
|
||||
{ id: 3, name: 'Typist3' },
|
||||
@ -1686,7 +1689,8 @@ describe('AccountsService', () => {
|
||||
licensesRepositoryMockValue,
|
||||
worktypesRepositoryMockValue,
|
||||
);
|
||||
await expect(service.getTypists(externalId)).rejects.toEqual(
|
||||
const context = makeContext(`uuidv4`);
|
||||
await expect(service.getTypists(context, externalId)).rejects.toEqual(
|
||||
new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
@ -1720,7 +1724,8 @@ describe('AccountsService', () => {
|
||||
licensesRepositoryMockValue,
|
||||
worktypesRepositoryMockValue,
|
||||
);
|
||||
await expect(service.getTypists(externalId)).rejects.toEqual(
|
||||
const context = makeContext(`uuidv4`);
|
||||
await expect(service.getTypists(context, externalId)).rejects.toEqual(
|
||||
new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
@ -1755,7 +1760,8 @@ describe('AccountsService', () => {
|
||||
worktypesRepositoryMockValue,
|
||||
);
|
||||
|
||||
expect(await service.getTypistGroups(externalId)).toEqual([
|
||||
const context = makeContext(`uuidv4`);
|
||||
expect(await service.getTypistGroups(context, externalId)).toEqual([
|
||||
{ id: 1, name: 'GroupA' },
|
||||
{ id: 2, name: 'GroupB' },
|
||||
]);
|
||||
@ -1788,7 +1794,8 @@ describe('AccountsService', () => {
|
||||
worktypesRepositoryMockValue,
|
||||
);
|
||||
|
||||
await expect(service.getTypistGroups(externalId)).rejects.toEqual(
|
||||
const context = makeContext(`uuidv4`);
|
||||
await expect(service.getTypistGroups(context, externalId)).rejects.toEqual(
|
||||
new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
@ -1823,7 +1830,8 @@ describe('AccountsService', () => {
|
||||
worktypesRepositoryMockValue,
|
||||
);
|
||||
|
||||
await expect(service.getTypistGroups(externalId)).rejects.toEqual(
|
||||
const context = makeContext(`uuidv4`);
|
||||
await expect(service.getTypistGroups(context, externalId)).rejects.toEqual(
|
||||
new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
@ -2005,7 +2013,13 @@ describe('getPartnerAccount', () => {
|
||||
const offset = 0;
|
||||
const limit = 20;
|
||||
|
||||
const response = await service.getPartnerLicenses(limit, offset, accountId);
|
||||
const context = makeContext(`uuidv4`);
|
||||
const response = await service.getPartnerLicenses(
|
||||
context,
|
||||
limit,
|
||||
offset,
|
||||
accountId,
|
||||
);
|
||||
|
||||
expect(response.total).toBe(2);
|
||||
|
||||
@ -2146,7 +2160,13 @@ describe('getPartnerAccount', () => {
|
||||
const offset = 0;
|
||||
const limit = 20;
|
||||
|
||||
const response = await service.getPartnerLicenses(limit, offset, accountId);
|
||||
const context = makeContext(`uuidv4`);
|
||||
const response = await service.getPartnerLicenses(
|
||||
context,
|
||||
limit,
|
||||
offset,
|
||||
accountId,
|
||||
);
|
||||
|
||||
// 有効期限間近(5件)+ 有効期限間近でない(3件)'Unallocated', 'Allocated', 'Reusable'+ 有効期限未設定(1件) → 9件
|
||||
expect(response.childrenPartnerLicenses[0].stockLicense).toBe(9);
|
||||
@ -2239,7 +2259,13 @@ describe('getOrderHistories', () => {
|
||||
const offset = 1;
|
||||
const limit = 2;
|
||||
|
||||
const response = await service.getOrderHistories(limit, offset, accountId);
|
||||
const context = makeContext(`uuidv4`);
|
||||
const response = await service.getOrderHistories(
|
||||
context,
|
||||
limit,
|
||||
offset,
|
||||
accountId,
|
||||
);
|
||||
|
||||
expect(response.total).toBe(5);
|
||||
|
||||
@ -2278,8 +2304,9 @@ describe('getOrderHistories', () => {
|
||||
licensesRepositoryMockValue,
|
||||
worktypesRepositoryMockValue,
|
||||
);
|
||||
const context = makeContext(`uuidv4`);
|
||||
await expect(
|
||||
service.getOrderHistories(limit, offset, accountId),
|
||||
service.getOrderHistories(context, limit, offset, accountId),
|
||||
).rejects.toEqual(
|
||||
new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
@ -2640,8 +2667,9 @@ describe('getDealers', () => {
|
||||
})
|
||||
).account;
|
||||
const service = module.get<AccountsService>(AccountsService);
|
||||
const context = makeContext(`uuidv4`);
|
||||
|
||||
expect(await service.getDealers()).toEqual({
|
||||
expect(await service.getDealers(context)).toEqual({
|
||||
dealers: [
|
||||
{
|
||||
country: 'JP',
|
||||
@ -2668,7 +2696,8 @@ describe('getDealers', () => {
|
||||
|
||||
const service = module.get<AccountsService>(AccountsService);
|
||||
|
||||
expect(await service.getDealers()).toEqual({
|
||||
const context = makeContext(`uuidv4`);
|
||||
expect(await service.getDealers(context)).toEqual({
|
||||
dealers: [],
|
||||
});
|
||||
});
|
||||
@ -2752,7 +2781,6 @@ describe('createTypistGroup', () => {
|
||||
expect(typistGroupUsers.map((user) => user.user_id)).toEqual(userIds);
|
||||
}
|
||||
});
|
||||
|
||||
it('typistIdsにRole:typist以外のユーザーが含まれていた場合、400エラーを返却する', async () => {
|
||||
if (!source) fail();
|
||||
const module = await makeTestingModule(source);
|
||||
@ -2859,6 +2887,58 @@ describe('createTypistGroup', () => {
|
||||
new HttpException(makeErrorResponse('E010204'), HttpStatus.BAD_REQUEST),
|
||||
);
|
||||
});
|
||||
it('typistIdsにメール未認証のユーザーが含まれていた場合、400エラーを返却する', async () => {
|
||||
if (!source) fail();
|
||||
const module = await makeTestingModule(source);
|
||||
if (!module) fail();
|
||||
const adminExternalId = 'admin-external-id';
|
||||
// 第五階層のアカウント作成
|
||||
const { id: accountId } = (
|
||||
await makeTestAccount(
|
||||
source,
|
||||
{ tier: 5 },
|
||||
{ external_id: adminExternalId },
|
||||
)
|
||||
).account;
|
||||
// 作成したアカウントにユーザーを3名追加する
|
||||
const typiptUserExternalIds = [
|
||||
'typist-user-external-id1',
|
||||
'typist-user-external-id2',
|
||||
'typist-user-external-id3',
|
||||
];
|
||||
const userIds: number[] = [];
|
||||
for (const typiptUserExternalId of typiptUserExternalIds) {
|
||||
const user = await makeTestUser(source, {
|
||||
account_id: accountId,
|
||||
external_id: typiptUserExternalId,
|
||||
role: 'typist',
|
||||
email_verified: false, // メール未認証のユーザーを追加
|
||||
});
|
||||
userIds.push(user?.id ?? 0);
|
||||
}
|
||||
//作成したデータを確認
|
||||
{
|
||||
const accounts = await getAccounts(source);
|
||||
expect(accounts.length).toBe(1);
|
||||
expect(accounts[0].id).toBe(accountId);
|
||||
const users = await getUsers(source);
|
||||
expect(users.length).toBe(4);
|
||||
}
|
||||
const service = module.get<AccountsService>(AccountsService);
|
||||
const typistGroupName = 'typist-group-name';
|
||||
const typistUserIds = [...userIds];
|
||||
const context = makeContext(adminExternalId);
|
||||
await expect(
|
||||
service.createTypistGroup(
|
||||
context,
|
||||
adminExternalId,
|
||||
typistGroupName,
|
||||
typistUserIds,
|
||||
),
|
||||
).rejects.toEqual(
|
||||
new HttpException(makeErrorResponse('E010204'), HttpStatus.BAD_REQUEST),
|
||||
);
|
||||
});
|
||||
it('DBアクセスに失敗した場合、500エラーを返却する', async () => {
|
||||
if (!source) fail();
|
||||
const module = await makeTestingModule(source);
|
||||
@ -3338,6 +3418,69 @@ describe('updateTypistGroup', () => {
|
||||
}
|
||||
}
|
||||
});
|
||||
it('typistIdsにメール未認証のユーザーが含まれていた場合、400エラーを返却する', async () => {
|
||||
if (!source) fail();
|
||||
const module = await makeTestingModule(source);
|
||||
if (!module) fail();
|
||||
// 第五階層のアカウント作成
|
||||
const { account, admin } = await makeTestAccount(source, { tier: 5 });
|
||||
// 作成したアカウントにユーザーを3名追加する
|
||||
const typiptUserExternalIds = [
|
||||
'typist-user-external-id1',
|
||||
'typist-user-external-id2',
|
||||
'typist-user-external-id3',
|
||||
];
|
||||
const userIds: number[] = [];
|
||||
for (const typiptUserExternalId of typiptUserExternalIds) {
|
||||
const user = await makeTestUser(source, {
|
||||
account_id: account.id,
|
||||
external_id: typiptUserExternalId,
|
||||
role: USER_ROLES.TYPIST,
|
||||
email_verified: typiptUserExternalId !== 'typist-user-external-id3', //typist-user-external-id3のみメール未認証
|
||||
});
|
||||
userIds.push(user?.id ?? 0);
|
||||
}
|
||||
|
||||
const typistGroupName = 'typist-group-name';
|
||||
const service = module.get<AccountsService>(AccountsService);
|
||||
const typistUserIds = [...userIds];
|
||||
const context = makeContext(admin.external_id);
|
||||
await service.createTypistGroup(
|
||||
context,
|
||||
admin.external_id,
|
||||
typistGroupName,
|
||||
[userIds[0]],
|
||||
);
|
||||
|
||||
//作成したデータを確認
|
||||
const group = await getTypistGroup(source, account.id);
|
||||
{
|
||||
expect(group.length).toBe(1);
|
||||
expect(group[0].name).toBe(typistGroupName);
|
||||
const groupUsers = await getTypistGroupMember(source, group[0].id);
|
||||
expect(groupUsers.length).toBe(1);
|
||||
expect(groupUsers[0].user_group_id).toEqual(group[0].id);
|
||||
expect(groupUsers[0].user_id).toEqual(userIds[0]);
|
||||
}
|
||||
const updateTypistGroupName = 'typist-group-name-update';
|
||||
|
||||
try {
|
||||
await service.updateTypistGroup(
|
||||
context,
|
||||
admin.external_id,
|
||||
group[0].id,
|
||||
updateTypistGroupName,
|
||||
typistUserIds,
|
||||
);
|
||||
} catch (e) {
|
||||
if (e instanceof HttpException) {
|
||||
expect(e.getStatus()).toEqual(HttpStatus.BAD_REQUEST);
|
||||
expect(e.getResponse()).toEqual(makeErrorResponse('E010204'));
|
||||
} else {
|
||||
fail();
|
||||
}
|
||||
}
|
||||
});
|
||||
it('タイピストグループが存在しない場合、400エラーを返却する', async () => {
|
||||
if (!source) fail();
|
||||
const module = await makeTestingModule(source);
|
||||
@ -5754,6 +5897,44 @@ describe('getAuthors', () => {
|
||||
expect(authors[1].authorId).toBe('AUTHOR_ID_2');
|
||||
}
|
||||
});
|
||||
it('アカウント内のAuthorユーザーの一覧を取得できる(未認証ユーザー以外)', async () => {
|
||||
if (!source) fail();
|
||||
const module = await makeTestingModule(source);
|
||||
if (!module) fail();
|
||||
// 第五階層のアカウント作成
|
||||
const { account, admin } = await makeTestAccount(source, { tier: 5 });
|
||||
|
||||
const userId1 = await makeTestUser(source, {
|
||||
account_id: account.id,
|
||||
role: USER_ROLES.AUTHOR,
|
||||
author_id: 'AUTHOR_ID_1',
|
||||
});
|
||||
const userId2 = await makeTestUser(source, {
|
||||
account_id: account.id,
|
||||
role: USER_ROLES.AUTHOR,
|
||||
author_id: 'AUTHOR_ID_2',
|
||||
email_verified: false,
|
||||
});
|
||||
|
||||
// 作成したデータを確認
|
||||
{
|
||||
const users = await getUsers(source);
|
||||
expect(users.length).toBe(3);
|
||||
expect(users[1].id).toBe(userId1.id);
|
||||
expect(users[2].id).toBe(userId2.id);
|
||||
}
|
||||
|
||||
const service = module.get<AccountsService>(AccountsService);
|
||||
const context = makeContext(admin.external_id);
|
||||
const authors = await service.getAuthors(context, admin.external_id);
|
||||
|
||||
//実行結果を確認
|
||||
{
|
||||
expect(authors.length).toBe(1);
|
||||
expect(authors[0].id).toBe(userId1.id);
|
||||
expect(authors[0].authorId).toBe('AUTHOR_ID_1');
|
||||
}
|
||||
});
|
||||
it('アカウント内のAuthorユーザーの一覧を取得できる(0件)', async () => {
|
||||
if (!source) fail();
|
||||
const module = await makeTestingModule(source);
|
||||
@ -5805,6 +5986,189 @@ describe('getAuthors', () => {
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('getTypists', () => {
|
||||
let source: DataSource | null = null;
|
||||
beforeEach(async () => {
|
||||
source = new DataSource({
|
||||
type: 'sqlite',
|
||||
database: ':memory:',
|
||||
logging: false,
|
||||
entities: [__dirname + '/../../**/*.entity{.ts,.js}'],
|
||||
synchronize: true, // trueにすると自動的にmigrationが行われるため注意
|
||||
});
|
||||
return source.initialize();
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
if (!source) return;
|
||||
await source.destroy();
|
||||
source = null;
|
||||
});
|
||||
it('アカウント内のTypistユーザーの一覧を取得できる', async () => {
|
||||
if (!source) fail();
|
||||
const module = await makeTestingModule(source);
|
||||
if (!module) fail();
|
||||
// 第五階層のアカウント作成
|
||||
const { account, admin } = await makeTestAccount(source, { tier: 5 });
|
||||
|
||||
const userId1 = await makeTestUser(source, {
|
||||
account_id: account.id,
|
||||
role: USER_ROLES.TYPIST,
|
||||
external_id: 'typist1',
|
||||
});
|
||||
const userId2 = await makeTestUser(source, {
|
||||
account_id: account.id,
|
||||
role: USER_ROLES.TYPIST,
|
||||
external_id: 'typist2',
|
||||
});
|
||||
const userId3 = await makeTestUser(source, {
|
||||
account_id: account.id,
|
||||
role: USER_ROLES.AUTHOR,
|
||||
author_id: 'AUTHOR_ID_1',
|
||||
external_id: 'author1',
|
||||
});
|
||||
|
||||
// 作成したデータを確認
|
||||
{
|
||||
const users = await getUsers(source);
|
||||
expect(users.length).toBe(4);
|
||||
expect(users[1].id).toBe(userId1.id);
|
||||
expect(users[2].id).toBe(userId2.id);
|
||||
expect(users[3].id).toBe(userId3.id);
|
||||
}
|
||||
|
||||
const service = module.get<AccountsService>(AccountsService);
|
||||
overrideAdB2cService(service, {
|
||||
getUsers: async () => [
|
||||
{ id: admin.external_id, displayName: '' },
|
||||
{ id: userId1.external_id, displayName: '' },
|
||||
{ id: userId2.external_id, displayName: '' },
|
||||
{ id: userId3.external_id, displayName: '' },
|
||||
],
|
||||
});
|
||||
|
||||
const context = makeContext(`uuidv4`);
|
||||
const typists = await service.getTypists(context, admin.external_id);
|
||||
|
||||
//実行結果を確認
|
||||
{
|
||||
expect(typists.length).toBe(2);
|
||||
expect(typists[0].id).toBe(userId1.id);
|
||||
expect(typists[1].id).toBe(userId2.id);
|
||||
}
|
||||
});
|
||||
it('アカウント内のTypistユーザーの一覧を取得できる(0件)', async () => {
|
||||
if (!source) fail();
|
||||
const module = await makeTestingModule(source);
|
||||
if (!module) fail();
|
||||
// 第五階層のアカウント作成
|
||||
const { admin } = await makeTestAccount(source, { tier: 5 });
|
||||
|
||||
// 作成したデータを確認
|
||||
{
|
||||
const users = await getUsers(source);
|
||||
expect(users.length).toBe(1);
|
||||
}
|
||||
|
||||
const service = module.get<AccountsService>(AccountsService);
|
||||
|
||||
overrideAdB2cService(service, {
|
||||
getUsers: async () => [{ id: admin.external_id, displayName: '' }],
|
||||
});
|
||||
const context = makeContext(`uuidv4`);
|
||||
const typists = await service.getTypists(context, admin.external_id);
|
||||
|
||||
//実行結果を確認
|
||||
{
|
||||
expect(typists.length).toBe(0);
|
||||
}
|
||||
});
|
||||
|
||||
it('アカウント内のTypistユーザーの一覧を取得できる(メール認証済みユーザーのみ)', async () => {
|
||||
if (!source) fail();
|
||||
const module = await makeTestingModule(source);
|
||||
if (!module) fail();
|
||||
// 第五階層のアカウント作成
|
||||
const { account, admin } = await makeTestAccount(source, { tier: 5 });
|
||||
|
||||
const userId1 = await makeTestUser(source, {
|
||||
account_id: account.id,
|
||||
role: USER_ROLES.TYPIST,
|
||||
});
|
||||
const userId2 = await makeTestUser(source, {
|
||||
account_id: account.id,
|
||||
role: USER_ROLES.TYPIST,
|
||||
});
|
||||
const userId3 = await makeTestUser(source, {
|
||||
account_id: account.id,
|
||||
role: USER_ROLES.TYPIST,
|
||||
email_verified: false,
|
||||
});
|
||||
|
||||
// 作成したデータを確認
|
||||
{
|
||||
const users = await getUsers(source);
|
||||
expect(users.length).toBe(4);
|
||||
expect(users[1].id).toBe(userId1.id);
|
||||
expect(users[2].id).toBe(userId2.id);
|
||||
expect(users[3].id).toBe(userId3.id);
|
||||
}
|
||||
|
||||
const service = module.get<AccountsService>(AccountsService);
|
||||
overrideAdB2cService(service, {
|
||||
getUsers: async () => [
|
||||
{ id: admin.external_id, displayName: '' },
|
||||
{ id: userId1.external_id, displayName: '' },
|
||||
{ id: userId2.external_id, displayName: '' },
|
||||
{ id: userId3.external_id, displayName: '' },
|
||||
],
|
||||
});
|
||||
|
||||
const context = makeContext(`uuidv4`);
|
||||
const typists = await service.getTypists(context, admin.external_id);
|
||||
|
||||
//実行結果を確認
|
||||
{
|
||||
expect(typists.length).toBe(2);
|
||||
expect(typists[0].id).toBe(userId1.id);
|
||||
expect(typists[1].id).toBe(userId2.id);
|
||||
}
|
||||
});
|
||||
it('DBアクセスに失敗した場合、500エラーとなる', async () => {
|
||||
if (!source) fail();
|
||||
const module = await makeTestingModule(source);
|
||||
if (!module) fail();
|
||||
// 第五階層のアカウント作成
|
||||
const { admin } = await makeTestAccount(source, { tier: 5 });
|
||||
|
||||
const service = module.get<AccountsService>(AccountsService);
|
||||
overrideAdB2cService(service, {
|
||||
getUsers: async () => [{ id: admin.external_id, displayName: '' }],
|
||||
});
|
||||
|
||||
//DBアクセスに失敗するようにする
|
||||
const usersService = module.get<UsersRepositoryService>(
|
||||
UsersRepositoryService,
|
||||
);
|
||||
usersService.findTypistUsers = jest.fn().mockRejectedValue('DB failed');
|
||||
const context = makeContext(`uuidv4`);
|
||||
|
||||
//実行結果を確認
|
||||
try {
|
||||
await service.getTypists(context, admin.external_id);
|
||||
fail();
|
||||
} catch (e) {
|
||||
if (e instanceof HttpException) {
|
||||
expect(e.getStatus()).toEqual(HttpStatus.INTERNAL_SERVER_ERROR);
|
||||
expect(e.getResponse()).toEqual(makeErrorResponse('E009999'));
|
||||
} else {
|
||||
fail();
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('deleteAccountAndData', () => {
|
||||
let source: DataSource | null = null;
|
||||
beforeEach(async () => {
|
||||
|
||||
@ -93,9 +93,14 @@ export class AccountsService {
|
||||
* @returns LicenseSummary
|
||||
*/
|
||||
async getLicenseSummary(
|
||||
context: Context,
|
||||
accountId: number,
|
||||
): Promise<GetLicenseSummaryResponse> {
|
||||
this.logger.log(`[IN] ${this.getLicenseSummary.name}`);
|
||||
this.logger.log(
|
||||
`[IN] [${context.getTrackingId()}] ${
|
||||
this.getLicenseSummary.name
|
||||
} | params: { ` + `accountId: ${accountId}, };`,
|
||||
);
|
||||
|
||||
try {
|
||||
const currentDate = new DateWithZeroTime();
|
||||
@ -139,8 +144,10 @@ export class AccountsService {
|
||||
};
|
||||
return licenseSummaryResponse;
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
this.logger.error('get licenseSummary failed');
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
this.logger.error(
|
||||
`[${context.getTrackingId()}] get licenseSummary failed`,
|
||||
);
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
@ -167,8 +174,9 @@ export class AccountsService {
|
||||
acceptedDpaVersion: string,
|
||||
): Promise<{ accountId: number; userId: number; externalUserId: string }> {
|
||||
this.logger.log(
|
||||
`[IN] [${context.trackingId}] ${this.createAccount.name} | params: { ` +
|
||||
`country: ${country}, ` +
|
||||
`[IN] [${context.getTrackingId()}] ${
|
||||
this.createAccount.name
|
||||
} | params: { ` +
|
||||
`dealerAccountId: ${dealerAccountId}, ` +
|
||||
`role: ${role}, ` +
|
||||
`acceptedEulaVersion: ${acceptedEulaVersion} }, ` +
|
||||
@ -185,8 +193,10 @@ export class AccountsService {
|
||||
username,
|
||||
);
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
this.logger.error('create externalUser failed');
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
this.logger.error(
|
||||
`[${context.getTrackingId()}] create externalUser failed`,
|
||||
);
|
||||
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
@ -196,7 +206,9 @@ export class AccountsService {
|
||||
|
||||
// メールアドレス重複エラー
|
||||
if (isConflictError(externalUser)) {
|
||||
this.logger.error(`email conflict. externalUser: ${externalUser}`);
|
||||
this.logger.error(
|
||||
`[${context.getTrackingId()}] email conflict. externalUser: ${externalUser}`,
|
||||
);
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E010301'),
|
||||
HttpStatus.BAD_REQUEST,
|
||||
@ -221,11 +233,13 @@ export class AccountsService {
|
||||
account = newAccount;
|
||||
user = adminUser;
|
||||
this.logger.log(
|
||||
`[${context.trackingId}] adminUser.external_id: ${user.external_id}`,
|
||||
`[${context.getTrackingId()}] adminUser.external_id: ${
|
||||
user.external_id
|
||||
}`,
|
||||
);
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
this.logger.error('create account failed');
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
this.logger.error(`[${context.getTrackingId()}] create account failed`);
|
||||
//リカバリ処理
|
||||
// idpのユーザーを削除
|
||||
await this.deleteAdB2cUser(externalUser.sub, context);
|
||||
@ -244,8 +258,10 @@ export class AccountsService {
|
||||
country,
|
||||
);
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
this.logger.error('create container failed');
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
this.logger.error(
|
||||
`[${context.getTrackingId()}] create container failed`,
|
||||
);
|
||||
//リカバリ処理
|
||||
// idpのユーザーを削除
|
||||
await this.deleteAdB2cUser(externalUser.sub, context);
|
||||
@ -279,8 +295,8 @@ export class AccountsService {
|
||||
html,
|
||||
);
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
this.logger.error('send E-mail failed');
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
this.logger.error(`[${context.getTrackingId()}] send E-mail failed`);
|
||||
//リカバリ処理
|
||||
// idpのユーザーを削除
|
||||
await this.deleteAdB2cUser(externalUser.sub, context);
|
||||
@ -306,7 +322,7 @@ export class AccountsService {
|
||||
throw e;
|
||||
} finally {
|
||||
this.logger.log(
|
||||
`[OUT] [${context.trackingId}] ${this.createAccount.name}`,
|
||||
`[OUT] [${context.getTrackingId()}] ${this.createAccount.name}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -320,12 +336,13 @@ export class AccountsService {
|
||||
try {
|
||||
await this.adB2cService.deleteUser(externalUserId, context);
|
||||
this.logger.log(
|
||||
`[${context.trackingId}] delete externalUser: ${externalUserId}`,
|
||||
`[${context.getTrackingId()}] delete externalUser: ${externalUserId} | params: { ` +
|
||||
`externalUserId: ${externalUserId}, };`,
|
||||
);
|
||||
} catch (error) {
|
||||
this.logger.error(`error=${error}`);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${error}`);
|
||||
this.logger.error(
|
||||
`${MANUAL_RECOVERY_REQUIRED} [${context.trackingId}] Failed to delete externalUser: ${externalUserId}`,
|
||||
`${MANUAL_RECOVERY_REQUIRED} [${context.getTrackingId()}] Failed to delete externalUser: ${externalUserId}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -336,15 +353,20 @@ export class AccountsService {
|
||||
userId: number,
|
||||
context: Context,
|
||||
): Promise<void> {
|
||||
this.logger.log(
|
||||
`[IN] [${context.getTrackingId()}] ${
|
||||
this.deleteAccount.name
|
||||
} | params: { accountId: ${accountId}, userId: ${userId} };`,
|
||||
);
|
||||
try {
|
||||
await this.accountRepository.deleteAccount(accountId, userId);
|
||||
this.logger.log(
|
||||
`[${context.trackingId}] delete account: ${accountId}, user: ${userId}`,
|
||||
`[${context.getTrackingId()}] delete account: ${accountId}, user: ${userId}`,
|
||||
);
|
||||
} catch (error) {
|
||||
this.logger.error(`error=${error}`);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${error}`);
|
||||
this.logger.error(
|
||||
`${MANUAL_RECOVERY_REQUIRED} [${context.trackingId}] Failed to delete account: ${accountId}, user: ${userId}`,
|
||||
`${MANUAL_RECOVERY_REQUIRED} [${context.getTrackingId()}] Failed to delete account: ${accountId}, user: ${userId}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -356,6 +378,11 @@ export class AccountsService {
|
||||
country: string,
|
||||
context: Context,
|
||||
): Promise<void> {
|
||||
this.logger.log(
|
||||
`[IN] [${context.getTrackingId()}] ${
|
||||
this.deleteBlobContainer.name
|
||||
} | params: { accountId: ${accountId} };`,
|
||||
);
|
||||
try {
|
||||
await this.blobStorageService.deleteContainer(
|
||||
context,
|
||||
@ -363,11 +390,11 @@ export class AccountsService {
|
||||
country,
|
||||
);
|
||||
this.logger.log(
|
||||
`[${context.trackingId}] delete container: ${accountId}, country: ${country}`,
|
||||
`[${context.getTrackingId()}] delete container: ${accountId}, country: ${country}`,
|
||||
);
|
||||
} catch (error) {
|
||||
this.logger.error(
|
||||
`${MANUAL_RECOVERY_REQUIRED} [${context.trackingId}] Failed to delete container: ${accountId}, country: ${country}`,
|
||||
`${MANUAL_RECOVERY_REQUIRED} [${context.getTrackingId()}] Failed to delete container: ${accountId}, country: ${country}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -382,8 +409,9 @@ export class AccountsService {
|
||||
externalId: string,
|
||||
): Promise<GetMyAccountResponse> {
|
||||
this.logger.log(
|
||||
`[IN] [${context.trackingId}] ${this.getAccountInfo.name} | params: { ` +
|
||||
`name: ${externalId}, };`,
|
||||
`[IN] [${context.getTrackingId()}] ${
|
||||
this.getAccountInfo.name
|
||||
} | params: { ` + `externalId: ${externalId}, };`,
|
||||
);
|
||||
try {
|
||||
let userInfo: User;
|
||||
@ -415,7 +443,7 @@ export class AccountsService {
|
||||
},
|
||||
};
|
||||
} catch (e) {
|
||||
this.logger.error(`[${context.trackingId}] error=${e}`);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
switch (e.constructor) {
|
||||
case UserNotFoundError:
|
||||
throw new HttpException(
|
||||
@ -435,13 +463,20 @@ export class AccountsService {
|
||||
}
|
||||
} finally {
|
||||
this.logger.log(
|
||||
`[OUT] [${context.trackingId}] ${this.getAccountInfo.name}`,
|
||||
`[OUT] [${context.getTrackingId()}] ${this.getAccountInfo.name}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
async getTypistGroups(externalId: string): Promise<TypistGroup[]> {
|
||||
this.logger.log(`[IN] ${this.getTypistGroups.name}`);
|
||||
async getTypistGroups(
|
||||
context: Context,
|
||||
externalId: string,
|
||||
): Promise<TypistGroup[]> {
|
||||
this.logger.log(
|
||||
`[IN] [${context.getTrackingId()}] ${
|
||||
this.getTypistGroups.name
|
||||
} | params: { externalId: ${externalId} };`,
|
||||
);
|
||||
|
||||
// TypistGroup取得
|
||||
try {
|
||||
@ -452,13 +487,15 @@ export class AccountsService {
|
||||
|
||||
return userGroups.map((x) => ({ id: x.id, name: x.name }));
|
||||
} catch (e) {
|
||||
this.logger.error(e);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
} finally {
|
||||
this.logger.log(`[OUT] ${this.getTypistGroups.name}`);
|
||||
this.logger.log(
|
||||
`[OUT] [${context.getTrackingId()}] ${this.getTypistGroups.name}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
/**
|
||||
@ -474,7 +511,9 @@ export class AccountsService {
|
||||
typistGroupId: number,
|
||||
): Promise<GetTypistGroupResponse> {
|
||||
this.logger.log(
|
||||
`[IN] [${context.trackingId}] ${this.getTypistGroup.name} | params: { externalId: ${externalId}, typistGroupId: ${typistGroupId} };`,
|
||||
`[IN] [${context.getTrackingId()}] ${
|
||||
this.getTypistGroup.name
|
||||
} | params: { externalId: ${externalId}, typistGroupId: ${typistGroupId} };`,
|
||||
);
|
||||
|
||||
try {
|
||||
@ -497,7 +536,7 @@ export class AccountsService {
|
||||
typistIds: userGroupMembers.map((x) => x.user_id),
|
||||
};
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
if (e instanceof Error) {
|
||||
switch (e.constructor) {
|
||||
case TypistGroupNotExistError:
|
||||
@ -518,7 +557,7 @@ export class AccountsService {
|
||||
);
|
||||
} finally {
|
||||
this.logger.log(
|
||||
`[OUT] [${context.trackingId}] ${this.getTypistGroup.name}`,
|
||||
`[OUT] [${context.getTrackingId()}] ${this.getTypistGroup.name}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -528,8 +567,12 @@ export class AccountsService {
|
||||
* @param externalId
|
||||
* @returns typists
|
||||
*/
|
||||
async getTypists(externalId: string): Promise<Typist[]> {
|
||||
this.logger.log(`[IN] ${this.getTypists.name}`);
|
||||
async getTypists(context: Context, externalId: string): Promise<Typist[]> {
|
||||
this.logger.log(
|
||||
`[IN] [${context.getTrackingId()}] ${
|
||||
this.getTypists.name
|
||||
} | params: { externalId: ${externalId} };`,
|
||||
);
|
||||
|
||||
// Typist取得
|
||||
try {
|
||||
@ -539,9 +582,9 @@ export class AccountsService {
|
||||
const externalIds = typistUsers.map((x) => x.external_id);
|
||||
|
||||
// B2Cからユーザー名を取得する
|
||||
const trackingId = new Context(context.trackingId);
|
||||
const adb2cUsers = await this.adB2cService.getUsers(
|
||||
// TODO: 外部連携以外のログ強化時に、ContollerからContextを取得するように修正する
|
||||
{ trackingId: 'dummy' },
|
||||
trackingId,
|
||||
externalIds,
|
||||
);
|
||||
|
||||
@ -560,13 +603,15 @@ export class AccountsService {
|
||||
|
||||
return typists;
|
||||
} catch (e) {
|
||||
this.logger.error(e);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
} finally {
|
||||
this.logger.log(`[OUT] ${this.getTypists.name}`);
|
||||
this.logger.log(
|
||||
`[OUT] [${context.getTrackingId()}] ${this.getTypists.name}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -578,7 +623,9 @@ export class AccountsService {
|
||||
*/
|
||||
async getAuthors(context: Context, externalId: string): Promise<Author[]> {
|
||||
this.logger.log(
|
||||
`[IN] [${context.trackingId}] ${this.getAuthors.name} | params: { externalId: ${externalId} };`,
|
||||
`[IN] [${context.getTrackingId()}] ${
|
||||
this.getAuthors.name
|
||||
} | params: { externalId: ${externalId} };`,
|
||||
);
|
||||
|
||||
try {
|
||||
@ -609,7 +656,7 @@ export class AccountsService {
|
||||
});
|
||||
return authors;
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
if (e instanceof Error) {
|
||||
switch (e.constructor) {
|
||||
case AccountNotFoundError:
|
||||
@ -629,7 +676,9 @@ export class AccountsService {
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
} finally {
|
||||
this.logger.log(`[OUT] [${context.trackingId}] ${this.getAuthors.name}`);
|
||||
this.logger.log(
|
||||
`[OUT] [${context.getTrackingId()}] ${this.getAuthors.name}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -652,7 +701,9 @@ export class AccountsService {
|
||||
creatorAccountTier: number,
|
||||
): Promise<{ accountId: number }> {
|
||||
this.logger.log(
|
||||
`[IN] [${context.trackingId}] ${this.createPartnerAccount.name} | params: { creatorUserId: ${creatorUserId}, creatorAccountTier: ${creatorAccountTier} };`,
|
||||
`[IN] [${context.getTrackingId()}] ${
|
||||
this.createPartnerAccount.name
|
||||
} | params: { creatorUserId: ${creatorUserId}, creatorAccountTier: ${creatorAccountTier} };`,
|
||||
);
|
||||
|
||||
try {
|
||||
@ -664,7 +715,7 @@ export class AccountsService {
|
||||
await this.usersRepository.findUserByExternalId(creatorUserId)
|
||||
).account_id;
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
if (e instanceof UserNotFoundError) {
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E010204'),
|
||||
@ -691,7 +742,7 @@ export class AccountsService {
|
||||
adminName,
|
||||
);
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
@ -723,8 +774,10 @@ export class AccountsService {
|
||||
account = newAccount;
|
||||
user = adminUser;
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
this.logger.error('create partner account failed');
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
this.logger.error(
|
||||
`[${context.getTrackingId()}] create partner account failed`,
|
||||
);
|
||||
//リカバリ処理
|
||||
// idpのユーザーを削除
|
||||
await this.deleteAdB2cUser(externalUser.sub, context);
|
||||
@ -743,8 +796,10 @@ export class AccountsService {
|
||||
country,
|
||||
);
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
this.logger.error('create partner container failed');
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
this.logger.error(
|
||||
`[${context.getTrackingId()}] create partner container failed`,
|
||||
);
|
||||
//リカバリ処理
|
||||
// idpのユーザーを削除
|
||||
await this.deleteAdB2cUser(externalUser.sub, context);
|
||||
@ -761,6 +816,7 @@ export class AccountsService {
|
||||
try {
|
||||
const { subject, text, html } =
|
||||
await this.sendgridService.createMailContentFromEmailConfirmForNormalUser(
|
||||
context,
|
||||
account.id,
|
||||
user.id,
|
||||
email,
|
||||
@ -775,8 +831,10 @@ export class AccountsService {
|
||||
);
|
||||
return { accountId: account.id };
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
this.logger.error('create partner account send mail failed');
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
this.logger.error(
|
||||
`[${context.getTrackingId()}] create partner account send mail failed`,
|
||||
);
|
||||
//リカバリ処理
|
||||
// idpのユーザーを削除
|
||||
await this.deleteAdB2cUser(externalUser.sub, context);
|
||||
@ -796,7 +854,7 @@ export class AccountsService {
|
||||
throw e;
|
||||
} finally {
|
||||
this.logger.log(
|
||||
`[OUT] [${context.trackingId}] ${this.createPartnerAccount.name}`,
|
||||
`[OUT] [${context.getTrackingId()}] ${this.createPartnerAccount.name}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -809,11 +867,16 @@ export class AccountsService {
|
||||
* @returns getPartnerLicensesResponse
|
||||
*/
|
||||
async getPartnerLicenses(
|
||||
context: Context,
|
||||
limit: number,
|
||||
offset: number,
|
||||
accountId: number,
|
||||
): Promise<GetPartnerLicensesResponse> {
|
||||
this.logger.log(`[IN] ${this.getPartnerLicenses.name}`);
|
||||
this.logger.log(
|
||||
`[IN] [${context.getTrackingId()}] ${
|
||||
this.getPartnerLicenses.name
|
||||
} | params: { limit: ${limit}, offset: ${offset}, accountId: ${accountId} };`,
|
||||
);
|
||||
|
||||
try {
|
||||
const currentDate = new DateWithZeroTime();
|
||||
@ -891,13 +954,15 @@ export class AccountsService {
|
||||
|
||||
return getPartnerLicensesResponse;
|
||||
} catch (e) {
|
||||
this.logger.error(e);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
} finally {
|
||||
this.logger.log(`[OUT] ${this.getPartnerLicenses.name}`);
|
||||
this.logger.log(
|
||||
`[OUT] [${context.getTrackingId()}] ${this.getPartnerLicenses.name}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
/**
|
||||
@ -908,11 +973,16 @@ export class AccountsService {
|
||||
* @returns getOrderHistoriesResponse
|
||||
*/
|
||||
async getOrderHistories(
|
||||
context: Context,
|
||||
limit: number,
|
||||
offset: number,
|
||||
accountId: number,
|
||||
): Promise<GetOrderHistoriesResponse> {
|
||||
this.logger.log(`[IN] ${this.getOrderHistories.name}`);
|
||||
this.logger.log(
|
||||
`[IN] [${context.getTrackingId()}] ${
|
||||
this.getOrderHistories.name
|
||||
} | params: { limit: ${limit}, offset: ${offset}, accountId: ${accountId} };`,
|
||||
);
|
||||
|
||||
try {
|
||||
const licenseHistoryInfo =
|
||||
@ -949,13 +1019,15 @@ export class AccountsService {
|
||||
};
|
||||
return getOrderHistoriesResponse;
|
||||
} catch (e) {
|
||||
this.logger.error(e);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
} finally {
|
||||
this.logger.log(`[OUT] ${this.getOrderHistories.name}`);
|
||||
this.logger.log(
|
||||
`[OUT] [${context.getTrackingId()}] ${this.getOrderHistories.name}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -975,7 +1047,9 @@ export class AccountsService {
|
||||
poNumber: string,
|
||||
): Promise<void> {
|
||||
this.logger.log(
|
||||
`[IN] [${context.trackingId}] ${this.issueLicense.name} | params: { ` +
|
||||
`[IN] [${context.getTrackingId()}] ${
|
||||
this.issueLicense.name
|
||||
} | params: { ` +
|
||||
`orderedAccountId: ${orderedAccountId}, ` +
|
||||
`userId: ${userId}, ` +
|
||||
`tier: ${tier}, ` +
|
||||
@ -993,7 +1067,7 @@ export class AccountsService {
|
||||
poNumber,
|
||||
);
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
if (e instanceof Error) {
|
||||
switch (e.constructor) {
|
||||
case OrderNotFoundError:
|
||||
@ -1020,14 +1094,16 @@ export class AccountsService {
|
||||
}
|
||||
} finally {
|
||||
this.logger.log(
|
||||
`[OUT] [${context.trackingId}] ${this.issueLicense.name}`,
|
||||
`[OUT] [${context.getTrackingId()}] ${this.issueLicense.name}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// dealersのアカウント情報を取得する
|
||||
async getDealers(): Promise<GetDealersResponse> {
|
||||
this.logger.log(`[IN] ${this.getDealers.name}`);
|
||||
async getDealers(context: Context): Promise<GetDealersResponse> {
|
||||
this.logger.log(
|
||||
`[IN] [${context.getTrackingId()}] ${this.getDealers.name}`,
|
||||
);
|
||||
|
||||
try {
|
||||
const dealerAccounts = await this.accountRepository.findDealerAccounts();
|
||||
@ -1044,13 +1120,15 @@ export class AccountsService {
|
||||
|
||||
return dealers;
|
||||
} catch (e) {
|
||||
this.logger.error(e);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
} finally {
|
||||
this.logger.log(`[OUT] ${this.getDealers.name}`);
|
||||
this.logger.log(
|
||||
`[OUT] [${context.getTrackingId()}] ${this.getDealers.name}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
/**
|
||||
@ -1068,7 +1146,9 @@ export class AccountsService {
|
||||
typistIds: number[],
|
||||
): Promise<void> {
|
||||
this.logger.log(
|
||||
`[IN] [${context.trackingId}] ${this.createTypistGroup.name} | params: { ` +
|
||||
`[IN] [${context.getTrackingId()}] ${
|
||||
this.createTypistGroup.name
|
||||
} | params: { ` +
|
||||
`externalId: ${externalId}, ` +
|
||||
`typistGroupName: ${typistGroupName}, ` +
|
||||
`typistIds: ${typistIds} };`,
|
||||
@ -1085,7 +1165,7 @@ export class AccountsService {
|
||||
account_id,
|
||||
);
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
if (e instanceof Error) {
|
||||
switch (e.constructor) {
|
||||
case TypistIdInvalidError:
|
||||
@ -1124,7 +1204,13 @@ export class AccountsService {
|
||||
typistIds: number[],
|
||||
): Promise<void> {
|
||||
this.logger.log(
|
||||
`[IN] [${context.trackingId}] ${this.updateTypistGroup.name} | params: { typistGroupId: ${typistGroupId}, typistGroupName: ${typistGroupName}, typistIds: ${typistIds} };`,
|
||||
`[IN] [${context.getTrackingId()}] ${
|
||||
this.updateTypistGroup.name
|
||||
} | params: { ` +
|
||||
`externalId: ${externalId}, ` +
|
||||
`typistGroupId: ${typistGroupId}, ` +
|
||||
`typistGroupName: ${typistGroupName}, ` +
|
||||
`typistIds: ${typistIds} };`,
|
||||
);
|
||||
try {
|
||||
// 外部IDをもとにユーザー情報を取得する
|
||||
@ -1140,7 +1226,7 @@ export class AccountsService {
|
||||
typistIds,
|
||||
);
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
if (e instanceof Error) {
|
||||
switch (e.constructor) {
|
||||
// タイピストIDが存在しない場合は400エラーを返す
|
||||
@ -1168,7 +1254,7 @@ export class AccountsService {
|
||||
);
|
||||
} finally {
|
||||
this.logger.log(
|
||||
`[OUT] [${context.trackingId}] ${this.updateTypistGroup.name}`,
|
||||
`[OUT] [${context.getTrackingId()}] ${this.updateTypistGroup.name}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -1187,7 +1273,9 @@ export class AccountsService {
|
||||
orderedAccountId: number,
|
||||
): Promise<void> {
|
||||
this.logger.log(
|
||||
`[IN] [${context.trackingId}] ${this.cancelIssue.name} | params: { ` +
|
||||
`[IN] [${context.getTrackingId()}] ${
|
||||
this.cancelIssue.name
|
||||
} | params: { ` +
|
||||
`extarnalId: ${extarnalId}, ` +
|
||||
`poNumber: ${poNumber}, ` +
|
||||
`orderedAccountId: ${orderedAccountId}, };`,
|
||||
@ -1200,7 +1288,7 @@ export class AccountsService {
|
||||
await this.usersRepository.findUserByExternalId(extarnalId)
|
||||
).account_id;
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
switch (e.constructor) {
|
||||
default:
|
||||
throw new HttpException(
|
||||
@ -1209,7 +1297,9 @@ export class AccountsService {
|
||||
);
|
||||
}
|
||||
} finally {
|
||||
this.logger.log(`[OUT] [${context.trackingId}] ${this.cancelIssue.name}`);
|
||||
this.logger.log(
|
||||
`[OUT] [${context.getTrackingId()}] ${this.cancelIssue.name}`,
|
||||
);
|
||||
}
|
||||
|
||||
// 注文元アカウントIDの親世代を取得
|
||||
@ -1218,7 +1308,9 @@ export class AccountsService {
|
||||
);
|
||||
// 自身が存在しない場合、エラー
|
||||
if (!parentAccountIds.includes(myAccountId)) {
|
||||
this.logger.log(`[OUT] [${context.trackingId}] ${this.cancelIssue.name}`);
|
||||
this.logger.log(
|
||||
`[OUT] [${context.getTrackingId()}] ${this.cancelIssue.name}`,
|
||||
);
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E000108'),
|
||||
HttpStatus.UNAUTHORIZED,
|
||||
@ -1229,7 +1321,7 @@ export class AccountsService {
|
||||
// 発行キャンセル処理
|
||||
await this.accountRepository.cancelIssue(orderedAccountId, poNumber);
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
switch (e.constructor) {
|
||||
case AlreadyLicenseStatusChangedError:
|
||||
throw new HttpException(
|
||||
@ -1253,7 +1345,9 @@ export class AccountsService {
|
||||
);
|
||||
}
|
||||
} finally {
|
||||
this.logger.log(`[OUT] [${context.trackingId}] ${this.cancelIssue.name}`);
|
||||
this.logger.log(
|
||||
`[OUT] [${context.getTrackingId()}] ${this.cancelIssue.name}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1267,7 +1361,11 @@ export class AccountsService {
|
||||
context: Context,
|
||||
externalId: string,
|
||||
): Promise<GetWorktypesResponse> {
|
||||
this.logger.log(`[IN] [${context.trackingId}] ${this.getWorktypes.name}`);
|
||||
this.logger.log(
|
||||
`[IN] [${context.getTrackingId()}] ${
|
||||
this.getWorktypes.name
|
||||
} | params: { externalId: ${externalId} };`,
|
||||
);
|
||||
try {
|
||||
// 外部IDをもとにユーザー情報を取得する
|
||||
const { account_id: accountId } =
|
||||
@ -1286,7 +1384,7 @@ export class AccountsService {
|
||||
active: active_worktype_id,
|
||||
};
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
if (e instanceof Error) {
|
||||
switch (e.constructor) {
|
||||
case AccountNotFoundError:
|
||||
@ -1307,7 +1405,7 @@ export class AccountsService {
|
||||
);
|
||||
} finally {
|
||||
this.logger.log(
|
||||
`[OUT] [${context.trackingId}] ${this.getWorktypes.name}`,
|
||||
`[OUT] [${context.getTrackingId()}] ${this.getWorktypes.name}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -1325,7 +1423,11 @@ export class AccountsService {
|
||||
worktypeId: string,
|
||||
description?: string,
|
||||
): Promise<void> {
|
||||
this.logger.log(`[IN] [${context.trackingId}] ${this.createWorktype.name}`);
|
||||
this.logger.log(
|
||||
`[IN] [${context.getTrackingId()}] ${
|
||||
this.createWorktype.name
|
||||
} | params: { externalId: ${externalId}, worktypeId: ${worktypeId}, description: ${description} };`,
|
||||
);
|
||||
|
||||
try {
|
||||
// 外部IDをもとにユーザー情報を取得する
|
||||
@ -1338,7 +1440,7 @@ export class AccountsService {
|
||||
description,
|
||||
);
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
if (e instanceof Error) {
|
||||
switch (e.constructor) {
|
||||
// WorktypeIDが既に存在する場合は400エラーを返す
|
||||
@ -1366,7 +1468,7 @@ export class AccountsService {
|
||||
);
|
||||
} finally {
|
||||
this.logger.log(
|
||||
`[OUT] [${context.trackingId}] ${this.createWorktype.name}`,
|
||||
`[OUT] [${context.getTrackingId()}] ${this.createWorktype.name}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -1388,7 +1490,9 @@ export class AccountsService {
|
||||
description?: string,
|
||||
): Promise<void> {
|
||||
this.logger.log(
|
||||
`[IN] [${context.trackingId}] ${this.updateWorktype.name} | params: { ` +
|
||||
`[IN] [${context.getTrackingId()}] ${
|
||||
this.updateWorktype.name
|
||||
} | params: { ` +
|
||||
`externalId: ${externalId}, ` +
|
||||
`id: ${id}, ` +
|
||||
`worktypeId: ${worktypeId}, ` +
|
||||
@ -1408,7 +1512,7 @@ export class AccountsService {
|
||||
description,
|
||||
);
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
if (e instanceof Error) {
|
||||
switch (e.constructor) {
|
||||
// ユーザーが設定したWorktypeIDが既存WorktypeのWorktypeIDと重複する場合は400エラーを返す
|
||||
@ -1436,7 +1540,7 @@ export class AccountsService {
|
||||
);
|
||||
} finally {
|
||||
this.logger.log(
|
||||
`[OUT] [${context.trackingId}] ${this.updateWorktype.name}`,
|
||||
`[OUT] [${context.getTrackingId()}] ${this.updateWorktype.name}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -1454,7 +1558,9 @@ export class AccountsService {
|
||||
id: number,
|
||||
): Promise<void> {
|
||||
this.logger.log(
|
||||
`[IN] [${context.trackingId}] ${this.deleteWorktype.name} | params: { ` +
|
||||
`[IN] [${context.getTrackingId()}] ${
|
||||
this.deleteWorktype.name
|
||||
} | params: { ` +
|
||||
`externalId: ${externalId}, ` +
|
||||
`id: ${id} };`,
|
||||
);
|
||||
@ -1473,7 +1579,7 @@ export class AccountsService {
|
||||
// ワークタイプを削除する
|
||||
await this.worktypesRepository.deleteWorktype(accountId, id);
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
if (e instanceof Error) {
|
||||
switch (e.constructor) {
|
||||
case UserNotFoundError:
|
||||
@ -1511,7 +1617,7 @@ export class AccountsService {
|
||||
);
|
||||
} finally {
|
||||
this.logger.log(
|
||||
`[OUT] [${context.trackingId}] ${this.deleteWorktype.name}`,
|
||||
`[OUT] [${context.getTrackingId()}] ${this.deleteWorktype.name}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -1529,7 +1635,9 @@ export class AccountsService {
|
||||
id: number,
|
||||
): Promise<GetOptionItemsResponse> {
|
||||
this.logger.log(
|
||||
`[IN] [${context.trackingId}] ${this.getOptionItems.name} | params: { ` +
|
||||
`[IN] [${context.getTrackingId()}] ${
|
||||
this.getOptionItems.name
|
||||
} | params: { ` +
|
||||
`externalId: ${externalId}, ` +
|
||||
`id: ${id} };`,
|
||||
);
|
||||
@ -1553,7 +1661,7 @@ export class AccountsService {
|
||||
})),
|
||||
};
|
||||
} catch (e) {
|
||||
this.logger.error(e);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
if (e instanceof Error) {
|
||||
switch (e.constructor) {
|
||||
// 内部IDで指定されたWorktypeが存在しない場合は400エラーを返す
|
||||
@ -1575,7 +1683,7 @@ export class AccountsService {
|
||||
);
|
||||
} finally {
|
||||
this.logger.log(
|
||||
`[OUT] [${context.trackingId}] ${this.getOptionItems.name}`,
|
||||
`[OUT] [${context.getTrackingId()}] ${this.getOptionItems.name}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -1595,7 +1703,9 @@ export class AccountsService {
|
||||
optionItems: PostWorktypeOptionItem[],
|
||||
): Promise<void> {
|
||||
this.logger.log(
|
||||
`[IN] [${context.trackingId}] ${this.updateOptionItems.name} | params: { ` +
|
||||
`[IN] [${context.getTrackingId()}] ${
|
||||
this.updateOptionItems.name
|
||||
} | params: { ` +
|
||||
`externalId: ${externalId}, ` +
|
||||
`id: ${id}, ` +
|
||||
`optionItems: ${JSON.stringify(optionItems)} };`,
|
||||
@ -1620,7 +1730,7 @@ export class AccountsService {
|
||||
})),
|
||||
);
|
||||
} catch (e) {
|
||||
this.logger.error(e);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
if (e instanceof Error) {
|
||||
switch (e.constructor) {
|
||||
// 内部IDで指定されたWorktypeが存在しない場合は400エラーを返す
|
||||
@ -1642,7 +1752,7 @@ export class AccountsService {
|
||||
);
|
||||
} finally {
|
||||
this.logger.log(
|
||||
`[OUT] [${context.trackingId}] ${this.updateOptionItems.name}`,
|
||||
`[OUT] [${context.getTrackingId()}] ${this.updateOptionItems.name}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -1660,7 +1770,9 @@ export class AccountsService {
|
||||
id: number | undefined,
|
||||
): Promise<void> {
|
||||
this.logger.log(
|
||||
`[IN] [${context.trackingId}] ${this.updateActiveWorktype.name} | params: { ` +
|
||||
`[IN] [${context.getTrackingId()}] ${
|
||||
this.updateActiveWorktype.name
|
||||
} | params: { ` +
|
||||
`externalId: ${externalId}, ` +
|
||||
`id: ${id} };`,
|
||||
);
|
||||
@ -1672,7 +1784,7 @@ export class AccountsService {
|
||||
// ActiveWorktypeを更新する
|
||||
await this.accountRepository.updateActiveWorktypeId(accountId, id);
|
||||
} catch (e) {
|
||||
this.logger.error(e);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
if (e instanceof Error) {
|
||||
switch (e.constructor) {
|
||||
// 内部IDで指定されたWorktypeが存在しない場合は400エラーを返す
|
||||
@ -1694,7 +1806,7 @@ export class AccountsService {
|
||||
);
|
||||
} finally {
|
||||
this.logger.log(
|
||||
`[OUT] [${context.trackingId}] ${this.updateActiveWorktype.name}`,
|
||||
`[OUT] [${context.getTrackingId()}] ${this.updateActiveWorktype.name}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -1714,7 +1826,9 @@ export class AccountsService {
|
||||
offset: number,
|
||||
): Promise<GetPartnersResponse> {
|
||||
this.logger.log(
|
||||
`[IN] [${context.trackingId}] ${this.getPartners.name} | params: { ` +
|
||||
`[IN] [${context.getTrackingId()}] ${
|
||||
this.getPartners.name
|
||||
} | params: { ` +
|
||||
`externalId: ${externalId}, ` +
|
||||
`limit: ${limit}, ` +
|
||||
`offset: ${offset}, };`,
|
||||
@ -1774,13 +1888,15 @@ export class AccountsService {
|
||||
partners: partners,
|
||||
};
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
} finally {
|
||||
this.logger.log(`[OUT] [${context.trackingId}] ${this.getPartners.name}`);
|
||||
this.logger.log(
|
||||
`[OUT] [${context.getTrackingId()}] ${this.getPartners.name}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1805,8 +1921,11 @@ export class AccountsService {
|
||||
secondryAdminUserId?: number,
|
||||
): Promise<void> {
|
||||
this.logger.log(
|
||||
`[IN] [${context.trackingId}] ${this.updateAccountInfo.name} | params: { ` +
|
||||
`[IN] [${context.getTrackingId()}] ${
|
||||
this.updateAccountInfo.name
|
||||
} | params: { ` +
|
||||
`externalId: ${externalId}, ` +
|
||||
`tier: ${tier}, ` +
|
||||
`delegationPermission: ${delegationPermission}, ` +
|
||||
`primaryAdminUserId: ${primaryAdminUserId}, ` +
|
||||
`parentAccountId: ${parentAccountId}, ` +
|
||||
@ -1825,7 +1944,7 @@ export class AccountsService {
|
||||
secondryAdminUserId,
|
||||
);
|
||||
} catch (e) {
|
||||
this.logger.error(`[${context.trackingId}] error=${e}`);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
if (e instanceof Error) {
|
||||
switch (e.constructor) {
|
||||
case DealerAccountNotFoundError:
|
||||
@ -1847,7 +1966,7 @@ export class AccountsService {
|
||||
);
|
||||
} finally {
|
||||
this.logger.log(
|
||||
`[OUT] [${context.trackingId}] ${this.updateAccountInfo.name}`,
|
||||
`[OUT] [${context.getTrackingId()}] ${this.updateAccountInfo.name}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -1864,7 +1983,9 @@ export class AccountsService {
|
||||
accountId: number,
|
||||
): Promise<void> {
|
||||
this.logger.log(
|
||||
`[IN] [${context.trackingId}] ${this.deleteAccountAndData.name} | params: { ` +
|
||||
`[IN] [${context.getTrackingId()}] ${
|
||||
this.deleteAccountAndData.name
|
||||
} | params: { ` +
|
||||
`externalId: ${externalId}, ` +
|
||||
`accountId: ${accountId}, };`,
|
||||
);
|
||||
@ -1889,13 +2010,15 @@ export class AccountsService {
|
||||
dbUsers = await this.accountRepository.deleteAccountAndInsertArchives(
|
||||
accountId,
|
||||
);
|
||||
this.logger.log(`[${context.trackingId}] delete account: ${accountId}`);
|
||||
this.logger.log(
|
||||
`[${context.getTrackingId()}] delete account: ${accountId}`,
|
||||
);
|
||||
country = targetAccount.country;
|
||||
} catch (e) {
|
||||
// アカウントの削除に失敗した場合はエラーを返す
|
||||
this.logger.log(`[${context.trackingId}] ${e}`);
|
||||
this.logger.log(`[${context.getTrackingId()}] ${e}`);
|
||||
this.logger.log(
|
||||
`[OUT] [${context.trackingId}] ${this.deleteAccountAndData.name}`,
|
||||
`[OUT] [${context.getTrackingId()}] ${this.deleteAccountAndData.name}`,
|
||||
);
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
@ -1910,19 +2033,15 @@ export class AccountsService {
|
||||
context,
|
||||
);
|
||||
this.logger.log(
|
||||
`[${
|
||||
context.trackingId
|
||||
}] delete ADB2C users: ${accountId}, users_id: ${dbUsers.map(
|
||||
`[${context.getTrackingId()}] delete ADB2C users: ${accountId}, users_id: ${dbUsers.map(
|
||||
(x) => x.external_id,
|
||||
)}`,
|
||||
);
|
||||
} catch (e) {
|
||||
// ADB2Cユーザーの削除失敗時は、MANUAL_RECOVERY_REQUIREDを出して処理続行
|
||||
this.logger.log(`[${context.trackingId}] ${e}`);
|
||||
this.logger.log(`[${context.getTrackingId()}] ${e}`);
|
||||
this.logger.log(
|
||||
`${MANUAL_RECOVERY_REQUIRED} [${
|
||||
context.trackingId
|
||||
}] Failed to delete ADB2C users: ${accountId}, users_id: ${dbUsers.map(
|
||||
`${MANUAL_RECOVERY_REQUIRED} [${context.getTrackingId()}] Failed to delete ADB2C users: ${accountId}, users_id: ${dbUsers.map(
|
||||
(x) => x.external_id,
|
||||
)}`,
|
||||
);
|
||||
@ -1932,18 +2051,18 @@ export class AccountsService {
|
||||
// blobstorageコンテナを削除する
|
||||
await this.deleteBlobContainer(accountId, country, context);
|
||||
this.logger.log(
|
||||
`[${context.trackingId}] delete blob container: ${accountId}-${country}`,
|
||||
`[${context.getTrackingId()}] delete blob container: ${accountId}-${country}`,
|
||||
);
|
||||
} catch (e) {
|
||||
// blobstorageコンテナを削除で失敗した場合は、MANUAL_RECOVERY_REQUIRED出して正常終了
|
||||
this.logger.log(`[${context.trackingId}] ${e}`);
|
||||
this.logger.log(`[${context.getTrackingId()}] ${e}`);
|
||||
this.logger.log(
|
||||
`${MANUAL_RECOVERY_REQUIRED}[${context.trackingId}] Failed to delete blob container: ${accountId}, country: ${country}`,
|
||||
`${MANUAL_RECOVERY_REQUIRED}[${context.getTrackingId()}] Failed to delete blob container: ${accountId}, country: ${country}`,
|
||||
);
|
||||
}
|
||||
|
||||
this.logger.log(
|
||||
`[OUT] [${context.trackingId}] ${this.deleteAccountAndData.name}`,
|
||||
`[OUT] [${context.getTrackingId()}] ${this.deleteAccountAndData.name}`,
|
||||
);
|
||||
}
|
||||
|
||||
@ -1958,7 +2077,9 @@ export class AccountsService {
|
||||
externalId: string,
|
||||
): Promise<number> {
|
||||
this.logger.log(
|
||||
`[IN] [${context.trackingId}] ${this.getAccountInfoMinimalAccess.name} | params: { externalId: ${externalId} };`,
|
||||
`[IN] [${context.getTrackingId()}] ${
|
||||
this.getAccountInfoMinimalAccess.name
|
||||
} | params: { externalId: ${externalId} };`,
|
||||
);
|
||||
|
||||
try {
|
||||
@ -1973,7 +2094,7 @@ export class AccountsService {
|
||||
|
||||
return account.tier;
|
||||
} catch (e) {
|
||||
this.logger.error(`[${context.trackingId}] error=${e}`);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
if (e instanceof Error) {
|
||||
switch (e.constructor) {
|
||||
case UserNotFoundError:
|
||||
@ -1999,7 +2120,9 @@ export class AccountsService {
|
||||
);
|
||||
} finally {
|
||||
this.logger.log(
|
||||
`[OUT] [${context.trackingId}] ${this.getAccountInfoMinimalAccess.name}`,
|
||||
`[OUT] [${context.getTrackingId()}] ${
|
||||
this.getAccountInfoMinimalAccess.name
|
||||
}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -40,8 +40,6 @@ import { RedisService } from '../../gateways/redis/redis.service';
|
||||
@Controller('auth')
|
||||
export class AuthController {
|
||||
constructor(
|
||||
// TODO「タスク 1828: IDトークンを一度しか使えないようにする」で使用する予定
|
||||
// private readonly redisService: RedisService,
|
||||
private readonly authService: AuthService,
|
||||
private readonly redisService: RedisService,
|
||||
) {}
|
||||
@ -68,9 +66,13 @@ export class AuthController {
|
||||
operationId: 'token',
|
||||
})
|
||||
async token(@Body() body: TokenRequest): Promise<TokenResponse> {
|
||||
const idToken = await this.authService.getVerifiedIdToken(body.idToken);
|
||||
const context = makeContext(uuidv4());
|
||||
const idToken = await this.authService.getVerifiedIdToken(
|
||||
context,
|
||||
body.idToken,
|
||||
);
|
||||
|
||||
const isVerified = await this.authService.isVerifiedUser(idToken);
|
||||
const isVerified = await this.authService.isVerifiedUser(context, idToken);
|
||||
if (!isVerified) {
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E010201'),
|
||||
@ -78,20 +80,16 @@ export class AuthController {
|
||||
);
|
||||
}
|
||||
|
||||
const context = makeContext(uuidv4());
|
||||
|
||||
const key = makeIDTokenKey(body.idToken);
|
||||
const isTokenExists = await this.redisService.get<boolean>(key);
|
||||
if (!isTokenExists) {
|
||||
// IDトークンがキャッシュに存在しない場合(idTokenの有効期限をADB2Cの有効期限と合わせる(300秒))
|
||||
await this.redisService.set(key, true, 300);
|
||||
} else {
|
||||
const isTokenExists = await this.redisService.get<boolean>(context, key);
|
||||
if (isTokenExists) {
|
||||
// IDトークンがキャッシュに存在する場合エラー
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E000106'),
|
||||
HttpStatus.UNAUTHORIZED,
|
||||
);
|
||||
}
|
||||
|
||||
// 同意済み利用規約バージョンが最新かチェック
|
||||
const isAcceptedLatestVersion =
|
||||
await this.authService.isAcceptedLatestVersion(context, idToken);
|
||||
@ -104,6 +102,9 @@ export class AuthController {
|
||||
);
|
||||
}
|
||||
|
||||
// IDトークンをキャッシュに保存(idTokenの有効期限をADB2Cの有効期限と合わせる(300秒))
|
||||
await this.redisService.set(context, key, true, 300);
|
||||
|
||||
const refreshToken = await this.authService.generateRefreshToken(
|
||||
context,
|
||||
idToken,
|
||||
|
||||
@ -31,7 +31,10 @@ describe('AuthService', () => {
|
||||
const token =
|
||||
'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImtpZCJ9.eyJleHAiOjkwMDAwMDAwMDAsIm5iZiI6MTAwMDAwMDAwMCwidmVyIjoiMS4wIiwiaXNzIjoiaXNzdWVyIiwic3ViIjoic3ViIiwiYXVkIjoiYXVkIiwibm9uY2UiOiJkZWZhdWx0Tm9uY2UiLCJpYXQiOjEwMDAwMDAwMDAsImF1dGhfdGltZSI6MTAwMDAwMDAwMCwiZW1haWxzIjpbInh4eEB4eC5jb20iXSwidGZwIjoic2lnbmluX3VzZXJmbG93In0.RyieW-VHsHPQOjXbbhRc307AYJOc1sq2hrcu4SW1-K0pvLlkplepxvx02a3vCwQrnBYrIP5w6HExG-S_JgW5nYyWr6DeY11mA484n9KA8GeAcAXV37StH1gfWUJvfGb4C8BaMbMM9Ix4Z9NGwKA9vjNwevfmBZnz9lQUePgv6BJNmyvCt8ElJ01O-1WODbZuojJ4xXymA1OqluzfbphPOsqWTSNmTn0emkLjjnlMQf1iwM4C_kvvr8dUCFg0_UGDfQVJnzPEKB38UqnhLnC5WacrddDwQ0kBuGKZgZ_63Q_7fOvqAZivqLK7BPmbPxi6mx3R1S9Eq2ugzpY1LfJOjA';
|
||||
|
||||
expect(await service.getVerifiedIdToken(token)).toEqual(idTokenPayload);
|
||||
const context = makeContext(`uuidv4`);
|
||||
expect(await service.getVerifiedIdToken(context, token)).toEqual(
|
||||
idTokenPayload,
|
||||
);
|
||||
});
|
||||
|
||||
it('IDトークンの形式が不正な場合、形式不正エラーとなる。', async () => {
|
||||
@ -40,7 +43,8 @@ describe('AuthService', () => {
|
||||
const service = await makeAuthServiceMock(adb2cParam, configMockValue);
|
||||
const token = 'invalid.id.token';
|
||||
|
||||
await expect(service.getVerifiedIdToken(token)).rejects.toEqual(
|
||||
const context = makeContext(`uuidv4`);
|
||||
await expect(service.getVerifiedIdToken(context, token)).rejects.toEqual(
|
||||
new HttpException(makeErrorResponse('E000101'), HttpStatus.UNAUTHORIZED),
|
||||
);
|
||||
});
|
||||
@ -54,7 +58,8 @@ describe('AuthService', () => {
|
||||
const token =
|
||||
'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImtpZCJ9.eyJleHAiOjEwMDAwMDAwMDAsIm5iZiI6MTAwMDAwMDAwMCwidmVyIjoiMS4wIiwiaXNzIjoiaXNzdWVyIiwic3ViIjoic3ViIiwiYXVkIjoiYXVkIiwibm9uY2UiOiJkZWZhdWx0Tm9uY2UiLCJpYXQiOjEwMDAwMDAwMDAsImF1dGhfdGltZSI6MTAwMDAwMDAwMCwiZW1haWxzIjpbInh4eEB4eC5jb20iXSwidGZwIjoic2lnbmluX3VzZXJmbG93In0.r9x61Mf1S2qFgU_QDKB6tRFBmTQXyOEtpoacOlL_bQzFz1t3GsxMy6SJIvQQ-LtDgylQ1UCdMFiRuy4V8nyLuME0fR-9IkKsboGvwllHB_Isai3XFoja0jpDHMVby1m0B3Z9xOTb7YsaQGyEH-qs1TtnRm6Ny98h4Po80nK8HGefQZHBOlfQN_B1LiHwI3nLXV18NL-4olKXj2NloNRYtnWM0PaqDQcGvZFaSNvtrSYpo9ddD906QWDGVOQ7WvGSUgdNCoxX8Lb3r2-VSj6n84jpb-Y1Fz-GhLluNglAsBhasnJfUIvCIO3iG5pRyTYjHFAVHmzjr8xMOmhS3s41Jw';
|
||||
|
||||
await expect(service.getVerifiedIdToken(token)).rejects.toEqual(
|
||||
const context = makeContext(`uuidv4`);
|
||||
await expect(service.getVerifiedIdToken(context, token)).rejects.toEqual(
|
||||
new HttpException(makeErrorResponse('E000102'), HttpStatus.UNAUTHORIZED),
|
||||
);
|
||||
});
|
||||
@ -68,7 +73,8 @@ describe('AuthService', () => {
|
||||
const token =
|
||||
'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImtpZCJ9.eyJleHAiOjkwMDAwMDAwMDAsIm5iZiI6OTAwMDAwMDAwMCwidmVyIjoiMS4wIiwiaXNzIjoiaXNzdWVyIiwic3ViIjoic3ViIiwiYXVkIjoiYXVkIiwibm9uY2UiOiJkZWZhdWx0Tm9uY2UiLCJpYXQiOjEwMDAwMDAwMDAsImF1dGhfdGltZSI6MTAwMDAwMDAwMCwiZW1haWxzIjpbInh4eEB4eC5jb20iXSwidGZwIjoic2lnbmluX3VzZXJmbG93In0.fX2Gbd7fDPNE3Lw-xbum_5CVqQYqEmMhv_v5u8A-U81pmPD2P5rsJEJx66ns1taFLVaE3j9_OzotxrqjqqQqbACkagGcN5wvA3_ZIxyqmhrKYFJc53ZcO7d0pFWiQlluNBI_pnFNDlSMB2Ut8Th5aiPy2uamBM9wC99bcjo7HkHvTKBf6ljU6rPKoD51qGDWqNxjoH-hdSJ29wprvyxyk_yX6dp-cxXUj5DIgXYQuIZF71rdiPtGlAiyTBns8rS2QlEEXapZVlvYrK4mkpUXVDA7ifD8q6gAC2BStqHeys7CGp2MbV4ZwKCVbAUbMs6Tboh8rADZvQhuTEq7qlhZ-w';
|
||||
|
||||
await expect(service.getVerifiedIdToken(token)).rejects.toEqual(
|
||||
const context = makeContext(`uuidv4`);
|
||||
await expect(service.getVerifiedIdToken(context, token)).rejects.toEqual(
|
||||
new HttpException(makeErrorResponse('E000103'), HttpStatus.UNAUTHORIZED),
|
||||
);
|
||||
});
|
||||
@ -80,7 +86,8 @@ describe('AuthService', () => {
|
||||
const token =
|
||||
'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImtpZCJ9.eyJleHAiOjkwMDAwMDAwMDAsIm5iZiI6MTAwMDAwMDAwMCwidmVyIjoiMS4wIiwiaXNzIjoiaXNzdXNlciIsInN1YiI6InN1YiIsImF1ZCI6ImF1ZCIsIm5vbmNlIjoiZGVmYXVsdE5vbmNlIiwiaWF0IjoxMDAwMDAwMDAwLCJhdXRoX3RpbWUiOjEwMDAwMDAwMDAsImVtYWlscyI6WyJ4eHhAeHguY29tIl0sInRmcCI6InNpZ25pbl91c2VyZmxvdyJ9.sign';
|
||||
|
||||
await expect(service.getVerifiedIdToken(token)).rejects.toEqual(
|
||||
const context = makeContext(`uuidv4`);
|
||||
await expect(service.getVerifiedIdToken(context, token)).rejects.toEqual(
|
||||
new HttpException(makeErrorResponse('E000104'), HttpStatus.UNAUTHORIZED),
|
||||
);
|
||||
});
|
||||
@ -94,7 +101,8 @@ describe('AuthService', () => {
|
||||
const token =
|
||||
'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImtpZCJ9.eyJleHAiOjkwMDAwMDAwMDAsIm5iZiI6MTAwMDAwMDAwMCwidmVyIjoiMS4wIiwiaXNzIjoiaW52bGlkX2lzc3VlciIsInN1YiI6InN1YiIsImF1ZCI6ImF1ZCIsIm5vbmNlIjoiZGVmYXVsdE5vbmNlIiwiaWF0IjoxMDAwMDAwMDAwLCJhdXRoX3RpbWUiOjEwMDAwMDAwMDAsImVtYWlscyI6WyJ4eHhAeHguY29tIl0sInRmcCI6InNpZ25pbl91c2VyZmxvdyJ9.0bp3e1mDG78PX3lo8zgOLXGenIqG_Vi6kw7CbwauAQM-cnUZ_aVCoJ_dAv_QmPElOQKcCkRrAvAZ91FwuHDlBGuuDqx8OwqN0VaD-4NPouoAswj-9HNvBm8gUn-pGaXkvWt_72UdCJavZJjDj_RHur8y8kFt5Qeab3mUP2x-uNcV2Q2x3M_IIfcRiIZkRZm_azKfiVIy7tzoUFLDss97y938aR8imMVxazoSQvj7RWIWylgeRr9yVt7qYl18cnEVL0IGtslFbqhfNsiEmRCMsttm5kXs7E9B0bhhUe_xbJW9VumQ6G7dgMrswevp_jRgbpWJoZsgErtqIRl9Tc9ikA';
|
||||
|
||||
await expect(service.getVerifiedIdToken(token)).rejects.toEqual(
|
||||
const context = makeContext(`uuidv4`);
|
||||
await expect(service.getVerifiedIdToken(context, token)).rejects.toEqual(
|
||||
new HttpException(makeErrorResponse('E000105'), HttpStatus.UNAUTHORIZED),
|
||||
);
|
||||
});
|
||||
@ -107,7 +115,8 @@ describe('AuthService', () => {
|
||||
const token =
|
||||
'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImtpZCJ9.eyJleHAiOjkwMDAwMDAwMDAsIm5iZiI6MTAwMDAwMDAwMCwidmVyIjoiMS4wIiwiaXNzIjoiaXNzdWVyIiwic3ViIjoic3ViIiwiYXVkIjoiYXVkIiwibm9uY2UiOiJkZWZhdWx0Tm9uY2UiLCJpYXQiOjEwMDAwMDAwMDAsImF1dGhfdGltZSI6MTAwMDAwMDAwMCwiZW1haWxzIjpbInh4eEB4eC5jb20iXSwidGZwIjoic2lnbmluX3VzZXJmbG93In0.RyieW-VHsHPQOjXbbhRc307AYJOc1sq2hrcu4SW1-K0pvLlkplepxvx02a3vCwQrnBYrIP5w6HExG-S_JgW5nYyWr6DeY11mA484n9KA8GeAcAXV37StH1gfWUJvfGb4C8BaMbMM9Ix4Z9NGwKA9vjNwevfmBZnz9lQUePgv6BJNmyvCt8ElJ01O-1WODbZuojJ4xXymA1OqluzfbphPOsqWTSNmTn0emkLjjnlMQf1iwM4C_kvvr8dUCFg0_UGDfQVJnzPEKB38UqnhLnC5WacrddDwQ0kBuGKZgZ_63Q_7fOvqAZivqLK7BPmbPxi6mx3R1S9Eq2ugzpY1LfJOjA';
|
||||
|
||||
await expect(service.getVerifiedIdToken(token)).rejects.toEqual(
|
||||
const context = makeContext(`uuidv4`);
|
||||
await expect(service.getVerifiedIdToken(context, token)).rejects.toEqual(
|
||||
new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
@ -122,7 +131,8 @@ describe('AuthService', () => {
|
||||
const token =
|
||||
'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImtpZCJ9.eyJleHAiOjkwMDAwMDAwMDAsIm5iZiI6MTAwMDAwMDAwMCwidmVyIjoiMS4wIiwiaXNzIjoiaXNzdWVyIiwic3ViIjoic3ViIiwiYXVkIjoiYXVkIiwibm9uY2UiOiJkZWZhdWx0Tm9uY2UiLCJpYXQiOjEwMDAwMDAwMDAsImF1dGhfdGltZSI6MTAwMDAwMDAwMCwiZW1haWxzIjpbInh4eEB4eC5jb20iXSwidGZwIjoic2lnbmluX3VzZXJmbG93In0.RyieW-VHsHPQOjXbbhRc307AYJOc1sq2hrcu4SW1-K0pvLlkplepxvx02a3vCwQrnBYrIP5w6HExG-S_JgW5nYyWr6DeY11mA484n9KA8GeAcAXV37StH1gfWUJvfGb4C8BaMbMM9Ix4Z9NGwKA9vjNwevfmBZnz9lQUePgv6BJNmyvCt8ElJ01O-1WODbZuojJ4xXymA1OqluzfbphPOsqWTSNmTn0emkLjjnlMQf1iwM4C_kvvr8dUCFg0_UGDfQVJnzPEKB38UqnhLnC5WacrddDwQ0kBuGKZgZ_63Q_7fOvqAZivqLK7BPmbPxi6mx3R1S9Eq2ugzpY1LfJOjA';
|
||||
|
||||
await expect(service.getVerifiedIdToken(token)).rejects.toEqual(
|
||||
const context = makeContext(`uuidv4`);
|
||||
await expect(service.getVerifiedIdToken(context, token)).rejects.toEqual(
|
||||
new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
@ -140,7 +150,8 @@ describe('AuthService', () => {
|
||||
const token =
|
||||
'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImtpZCJ9.eyJleHAiOjkwMDAwMDAwMDAsIm5iZiI6MTAwMDAwMDAwMCwidmVyIjoiMS4wIiwiaXNzIjoiaXNzdWVyIiwic3ViIjoic3ViIiwiYXVkIjoiYXVkIiwibm9uY2UiOiJkZWZhdWx0Tm9uY2UiLCJpYXQiOjEwMDAwMDAwMDAsImF1dGhfdGltZSI6MTAwMDAwMDAwMCwiZW1haWxzIjpbInh4eEB4eC5jb20iXSwidGZwIjoic2lnbmluX3VzZXJmbG93In0.RyieW-VHsHPQOjXbbhRc307AYJOc1sq2hrcu4SW1-K0pvLlkplepxvx02a3vCwQrnBYrIP5w6HExG-S_JgW5nYyWr6DeY11mA484n9KA8GeAcAXV37StH1gfWUJvfGb4C8BaMbMM9Ix4Z9NGwKA9vjNwevfmBZnz9lQUePgv6BJNmyvCt8ElJ01O-1WODbZuojJ4xXymA1OqluzfbphPOsqWTSNmTn0emkLjjnlMQf1iwM4C_kvvr8dUCFg0_UGDfQVJnzPEKB38UqnhLnC5WacrddDwQ0kBuGKZgZ_63Q_7fOvqAZivqLK7BPmbPxi6mx3R1S9Eq2ugzpY1LfJOjA';
|
||||
|
||||
await expect(service.getVerifiedIdToken(token)).rejects.toEqual(
|
||||
const context = makeContext(`uuidv4`);
|
||||
await expect(service.getVerifiedIdToken(context, token)).rejects.toEqual(
|
||||
new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
|
||||
@ -55,21 +55,25 @@ export class AuthService {
|
||||
* @param idToken AzureAD B2Cにより発行されたIDトークン
|
||||
* @returns verified user
|
||||
*/
|
||||
async isVerifiedUser(idToken: IDToken): Promise<boolean> {
|
||||
this.logger.log(`[IN] ${this.isVerifiedUser.name}`);
|
||||
async isVerifiedUser(context: Context, idToken: IDToken): Promise<boolean> {
|
||||
this.logger.log(
|
||||
`[IN] [${context.getTrackingId()}] ${this.isVerifiedUser.name}`,
|
||||
);
|
||||
try {
|
||||
// IDトークンのユーザーがDBに登録されていてメール認証が完了しているユーザーか検証
|
||||
const user = await this.usersRepository.findVerifiedUser(idToken.sub);
|
||||
|
||||
return user !== undefined;
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
} finally {
|
||||
this.logger.log(`[OUT] ${this.isVerifiedUser.name}`);
|
||||
this.logger.log(
|
||||
`[OUT] [${context.getTrackingId()}] ${this.isVerifiedUser.name}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -85,7 +89,9 @@ export class AuthService {
|
||||
type: string,
|
||||
): Promise<string> {
|
||||
this.logger.log(
|
||||
`[IN] [${context.trackingId}] ${this.generateRefreshToken.name}`,
|
||||
`[IN] [${context.getTrackingId()}] ${
|
||||
this.generateRefreshToken.name
|
||||
} | params: { type: ${type} };`,
|
||||
);
|
||||
|
||||
// ユーザー情報とユーザーが属しているアカウント情報を取得
|
||||
@ -133,7 +139,7 @@ export class AuthService {
|
||||
|
||||
return token;
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
if (e instanceof Error) {
|
||||
switch (e.constructor) {
|
||||
case TierUnexpectedError:
|
||||
@ -156,7 +162,7 @@ export class AuthService {
|
||||
);
|
||||
} finally {
|
||||
this.logger.log(
|
||||
`[OUT] [${context.trackingId}] ${this.generateRefreshToken.name}`,
|
||||
`[OUT] [${context.getTrackingId()}] ${this.generateRefreshToken.name}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -171,7 +177,7 @@ export class AuthService {
|
||||
refreshToken: string,
|
||||
): Promise<string> {
|
||||
this.logger.log(
|
||||
`[IN] [${context.trackingId}] ${this.generateAccessToken.name}`,
|
||||
`[IN] [${context.getTrackingId()}] ${this.generateAccessToken.name}`,
|
||||
);
|
||||
|
||||
const privateKey = getPrivateKey(this.configService);
|
||||
@ -179,9 +185,11 @@ export class AuthService {
|
||||
|
||||
const token = verify<RefreshToken>(refreshToken, pubkey);
|
||||
if (isVerifyError(token)) {
|
||||
this.logger.error(`${token.reason} | ${token.message}`);
|
||||
this.logger.error(
|
||||
`[${context.getTrackingId()}] ${token.reason} | ${token.message}`,
|
||||
);
|
||||
this.logger.log(
|
||||
`[OUT] [${context.trackingId}] ${this.generateAccessToken.name}`,
|
||||
`[OUT] [${context.getTrackingId()}] ${this.generateAccessToken.name}`,
|
||||
);
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E000101'),
|
||||
@ -200,7 +208,7 @@ export class AuthService {
|
||||
);
|
||||
|
||||
this.logger.log(
|
||||
`[OUT] [${context.trackingId}] ${this.generateAccessToken.name}`,
|
||||
`[OUT] [${context.getTrackingId()}] ${this.generateAccessToken.name}`,
|
||||
);
|
||||
return accessToken;
|
||||
}
|
||||
@ -218,7 +226,9 @@ export class AuthService {
|
||||
originAccountId: number,
|
||||
): Promise<string> {
|
||||
this.logger.log(
|
||||
`[IN] [${context.trackingId}] ${this.generateDelegationRefreshToken.name} | params: { ` +
|
||||
`[IN] [${context.getTrackingId()}] ${
|
||||
this.generateDelegationRefreshToken.name
|
||||
} | params: { ` +
|
||||
`delegateUserExternalId: ${delegateUserExternalId}, ` +
|
||||
`originAccountId: ${originAccountId}, };`,
|
||||
);
|
||||
@ -255,7 +265,7 @@ export class AuthService {
|
||||
|
||||
return token;
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
if (e instanceof Error) {
|
||||
switch (e.constructor) {
|
||||
case AccountNotFoundError:
|
||||
@ -284,7 +294,9 @@ export class AuthService {
|
||||
);
|
||||
} finally {
|
||||
this.logger.log(
|
||||
`[OUT] [${context.trackingId}] ${this.generateDelegationRefreshToken.name}`,
|
||||
`[OUT] [${context.getTrackingId()}] ${
|
||||
this.generateDelegationRefreshToken.name
|
||||
}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -300,7 +312,9 @@ export class AuthService {
|
||||
refreshToken: string,
|
||||
): Promise<string> {
|
||||
this.logger.log(
|
||||
`[IN] [${context.trackingId}] ${this.generateDelegationAccessToken.name}`,
|
||||
`[IN] [${context.getTrackingId()}] ${
|
||||
this.generateDelegationAccessToken.name
|
||||
}`,
|
||||
);
|
||||
|
||||
const privateKey = getPrivateKey(this.configService);
|
||||
@ -308,9 +322,13 @@ export class AuthService {
|
||||
|
||||
const token = verify<RefreshToken>(refreshToken, pubkey);
|
||||
if (isVerifyError(token)) {
|
||||
this.logger.error(`${token.reason} | ${token.message}`);
|
||||
this.logger.error(
|
||||
`[${context.getTrackingId()}] ${token.reason} | ${token.message}`,
|
||||
);
|
||||
this.logger.log(
|
||||
`[OUT] [${context.trackingId}] ${this.generateDelegationAccessToken.name}`,
|
||||
`[OUT] [${context.getTrackingId()}] ${
|
||||
this.generateDelegationAccessToken.name
|
||||
}`,
|
||||
);
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E000101'),
|
||||
@ -330,7 +348,9 @@ export class AuthService {
|
||||
);
|
||||
|
||||
this.logger.log(
|
||||
`[OUT] [${context.trackingId}] ${this.generateDelegationAccessToken.name}`,
|
||||
`[OUT] [${context.getTrackingId()}] ${
|
||||
this.generateDelegationAccessToken.name
|
||||
}`,
|
||||
);
|
||||
return accessToken;
|
||||
}
|
||||
@ -350,7 +370,9 @@ export class AuthService {
|
||||
refreshToken: string,
|
||||
): Promise<string> {
|
||||
this.logger.log(
|
||||
`[IN] [${context.trackingId}] ${this.updateDelegationAccessToken.name} | params: { ` +
|
||||
`[IN] [${context.getTrackingId()}] ${
|
||||
this.updateDelegationAccessToken.name
|
||||
} | params: { ` +
|
||||
`delegateUserExternalId: ${delegateUserExternalId}, ` +
|
||||
`originUserExternalId: ${originUserExternalId}, };`,
|
||||
);
|
||||
@ -407,7 +429,7 @@ export class AuthService {
|
||||
|
||||
return accessToken;
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
if (e instanceof HttpException) {
|
||||
throw e;
|
||||
}
|
||||
@ -440,7 +462,9 @@ export class AuthService {
|
||||
);
|
||||
} finally {
|
||||
this.logger.log(
|
||||
`[OUT] [${context.trackingId}] ${this.updateDelegationAccessToken.name}`,
|
||||
`[OUT] [${context.getTrackingId()}] ${
|
||||
this.updateDelegationAccessToken.name
|
||||
}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -450,8 +474,10 @@ export class AuthService {
|
||||
* @param token
|
||||
* @returns id token
|
||||
*/
|
||||
async getVerifiedIdToken(token: string): Promise<IDToken> {
|
||||
this.logger.log(`[IN] ${this.getVerifiedIdToken.name}`);
|
||||
async getVerifiedIdToken(context: Context, token: string): Promise<IDToken> {
|
||||
this.logger.log(
|
||||
`[IN] [${context.getTrackingId()}] ${this.getVerifiedIdToken.name}`,
|
||||
);
|
||||
|
||||
let kid: string | undefined = '';
|
||||
try {
|
||||
@ -462,7 +488,7 @@ export class AuthService {
|
||||
throw new Error('kid not found');
|
||||
}
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E000101'),
|
||||
HttpStatus.UNAUTHORIZED,
|
||||
@ -471,8 +497,8 @@ export class AuthService {
|
||||
|
||||
let issuer = '';
|
||||
try {
|
||||
const metadata = await this.adB2cService.getMetaData();
|
||||
const keySets = await this.adB2cService.getSignKeySets();
|
||||
const metadata = await this.adB2cService.getMetaData(context);
|
||||
const keySets = await this.adB2cService.getSignKeySets(context);
|
||||
|
||||
issuer = metadata.issuer;
|
||||
|
||||
@ -482,7 +508,7 @@ export class AuthService {
|
||||
throw new Error('Public Key Not Found.');
|
||||
}
|
||||
|
||||
const publicKey = this.getPublicKeyFromJwk(jwkKey);
|
||||
const publicKey = this.getPublicKeyFromJwk(context, jwkKey);
|
||||
|
||||
const verifiedToken = jwt.verify(token, publicKey, {
|
||||
algorithms: ['RS256'],
|
||||
@ -496,7 +522,9 @@ export class AuthService {
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
const { name, message } = e;
|
||||
this.logger.error(`error=${name}: ${message}`);
|
||||
this.logger.error(
|
||||
`[${context.getTrackingId()}] error=${name}: ${message}`,
|
||||
);
|
||||
|
||||
switch (e.constructor) {
|
||||
case jwt.TokenExpiredError:
|
||||
@ -519,18 +547,20 @@ export class AuthService {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
this.logger.error(`error=${e}`);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
}
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
} finally {
|
||||
this.logger.log(`[OUT] ${this.getVerifiedIdToken.name}`);
|
||||
this.logger.log(
|
||||
`[OUT] [${context.getTrackingId()}] ${this.getVerifiedIdToken.name}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
getPublicKeyFromJwk(jwkKey: JwkSignKey): string {
|
||||
getPublicKeyFromJwk(context: Context, jwkKey: JwkSignKey): string {
|
||||
try {
|
||||
// JWK形式のJSONなのでJWTの公開鍵として使えるようにPEM形式に変換
|
||||
const publicKey = jwkToPem({
|
||||
@ -541,10 +571,12 @@ export class AuthService {
|
||||
|
||||
return publicKey;
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
throw e;
|
||||
} finally {
|
||||
this.logger.log(`[OUT] ${this.getPublicKeyFromJwk.name}`);
|
||||
this.logger.log(
|
||||
`[OUT] [${context.getTrackingId()}] ${this.getPublicKeyFromJwk.name}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -613,8 +645,9 @@ export class AuthService {
|
||||
idToken: IDToken,
|
||||
): Promise<boolean> {
|
||||
this.logger.log(
|
||||
`[IN] [${context.trackingId}] ${this.isAcceptedLatestVersion.name} | params: { ` +
|
||||
`idToken.sub: ${idToken.sub}, };`,
|
||||
`[IN] [${context.getTrackingId()}] ${
|
||||
this.isAcceptedLatestVersion.name
|
||||
} | params: { ` + `idToken.sub: ${idToken.sub}, };`,
|
||||
);
|
||||
|
||||
try {
|
||||
@ -646,14 +679,16 @@ export class AuthService {
|
||||
return eulaAccepted && dpaAccepted;
|
||||
}
|
||||
} catch (e) {
|
||||
this.logger.error(`[${context.trackingId}] error=${e}`);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
} finally {
|
||||
this.logger.log(
|
||||
`[OUT] [${context.trackingId}] ${this.isAcceptedLatestVersion.name}`,
|
||||
`[OUT] [${context.getTrackingId()}] ${
|
||||
this.isAcceptedLatestVersion.name
|
||||
}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,6 +4,7 @@ import { JwkSignKey, B2cMetadata } from '../../../common/token';
|
||||
import { AuthService } from '../auth.service';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import { UsersRepositoryService } from '../../../repositories/users/users.repository.service';
|
||||
import { Context } from '../../../common/log';
|
||||
|
||||
export type AdB2cMockValue = {
|
||||
getMetaData: B2cMetadata | Error;
|
||||
@ -71,7 +72,10 @@ export const makeAdB2cServiceMock = (value: AdB2cMockValue) => {
|
||||
};
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
export const makeDefaultGetPublicKeyFromJwk = (jwkKey: JwkSignKey): string => {
|
||||
export const makeDefaultGetPublicKeyFromJwk = (
|
||||
context: Context,
|
||||
jwkKey: JwkSignKey,
|
||||
): string => {
|
||||
return [
|
||||
'-----BEGIN PUBLIC KEY-----',
|
||||
'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5IZZNgDew9eGmuFTezwd',
|
||||
|
||||
@ -140,6 +140,11 @@ export class FilesController {
|
||||
type: AudioUploadLocationResponse,
|
||||
description: '成功時のレスポンス',
|
||||
})
|
||||
@ApiResponse({
|
||||
status: HttpStatus.BAD_REQUEST,
|
||||
description: '不正なパラメータ',
|
||||
type: ErrorResponse,
|
||||
})
|
||||
@ApiResponse({
|
||||
status: HttpStatus.UNAUTHORIZED,
|
||||
description: '認証エラー',
|
||||
|
||||
@ -1,13 +1,9 @@
|
||||
import { HttpException, HttpStatus } from '@nestjs/common';
|
||||
import { makeErrorResponse } from '../../common/error/makeErrorResponse';
|
||||
import {
|
||||
makeBlobstorageServiceMockValue,
|
||||
makeDefaultTasksRepositoryMockValue,
|
||||
makeDefaultUsersRepositoryMockValue,
|
||||
makeFilesServiceMock,
|
||||
} from './test/files.service.mock';
|
||||
import { makeBlobstorageServiceMockValue } from './test/files.service.mock';
|
||||
import { DataSource } from 'typeorm';
|
||||
import {
|
||||
createLicense,
|
||||
createTask,
|
||||
createUserGroupAndMember,
|
||||
getTaskFromJobNumber,
|
||||
@ -16,6 +12,7 @@ import {
|
||||
import { FilesService } from './files.service';
|
||||
import { makeContext } from '../../common/log';
|
||||
import {
|
||||
makeHierarchicalAccounts,
|
||||
makeTestAccount,
|
||||
makeTestSimpleAccount,
|
||||
makeTestUser,
|
||||
@ -35,91 +32,244 @@ import {
|
||||
import { createWorktype } from '../accounts/test/utility';
|
||||
import { TasksRepositoryService } from '../../repositories/tasks/tasks.repository.service';
|
||||
import { NotificationhubService } from '../../gateways/notificationhub/notificationhub.service';
|
||||
import { makeNotifyMessage } from '../../common/notify/makeNotifyMessage';
|
||||
import { getCheckoutPermissions, getTask } from '../tasks/test/utility';
|
||||
import { DateWithZeroTime } from '../licenses/types/types';
|
||||
import { LICENSE_ALLOCATED_STATUS, LICENSE_TYPE } from '../../constants';
|
||||
|
||||
describe('音声ファイルアップロードURL取得', () => {
|
||||
it('アップロードSASトークンが乗っているURLを返却する', async () => {
|
||||
const blobParam = makeBlobstorageServiceMockValue();
|
||||
const userRepoParam = makeDefaultUsersRepositoryMockValue();
|
||||
const taskRepoParam = makeDefaultTasksRepositoryMockValue();
|
||||
const service = await makeFilesServiceMock(
|
||||
blobParam,
|
||||
userRepoParam,
|
||||
taskRepoParam,
|
||||
);
|
||||
|
||||
expect(
|
||||
await service.publishUploadSas(
|
||||
makeContext('trackingId'),
|
||||
'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx',
|
||||
),
|
||||
).toEqual('https://blob-storage?sas-token');
|
||||
describe('publishUploadSas', () => {
|
||||
let source: DataSource | null = null;
|
||||
beforeEach(async () => {
|
||||
source = new DataSource({
|
||||
type: 'sqlite',
|
||||
database: ':memory:',
|
||||
logging: false,
|
||||
entities: [__dirname + '/../../**/*.entity{.ts,.js}'],
|
||||
synchronize: true, // trueにすると自動的にmigrationが行われるため注意
|
||||
});
|
||||
return source.initialize();
|
||||
});
|
||||
|
||||
it('アカウント専用コンテナが無い場合でも、コンテナ作成しURLを返却する', async () => {
|
||||
const blobParam = makeBlobstorageServiceMockValue();
|
||||
const userRepoParam = makeDefaultUsersRepositoryMockValue();
|
||||
const taskRepoParam = makeDefaultTasksRepositoryMockValue();
|
||||
|
||||
blobParam.containerExists = false;
|
||||
|
||||
const service = await makeFilesServiceMock(
|
||||
blobParam,
|
||||
userRepoParam,
|
||||
taskRepoParam,
|
||||
);
|
||||
|
||||
expect(
|
||||
await service.publishUploadSas(
|
||||
makeContext('trackingId'),
|
||||
'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx',
|
||||
),
|
||||
).toEqual('https://blob-storage?sas-token');
|
||||
afterEach(async () => {
|
||||
if (!source) return;
|
||||
await source.destroy();
|
||||
source = null;
|
||||
});
|
||||
|
||||
it('ユーザー情報の取得に失敗した場合、例外エラーを返却する', async () => {
|
||||
const blobParam = makeBlobstorageServiceMockValue();
|
||||
const taskRepoParam = makeDefaultTasksRepositoryMockValue();
|
||||
it('音声アップロードSASトークンが乗っているURLを取得できる', async () => {
|
||||
if (!source) fail();
|
||||
const module = await makeTestingModule(source);
|
||||
if (!module) fail();
|
||||
const service = module.get<FilesService>(FilesService);
|
||||
// 第五階層のアカウント作成
|
||||
const { account: account } = await makeTestAccount(source, { tier: 5 });
|
||||
const { external_id: externalId, id: userId } = await makeTestUser(source, {
|
||||
account_id: account.id,
|
||||
external_id: 'author-user-external-id',
|
||||
role: 'author',
|
||||
author_id: 'AUTHOR_ID',
|
||||
});
|
||||
// 本日の日付を作成
|
||||
let today = new Date();
|
||||
today.setDate(today.getDate());
|
||||
today = new DateWithZeroTime(today);
|
||||
// 有効期限内のライセンスを作成して紐づける
|
||||
await createLicense(
|
||||
source,
|
||||
1,
|
||||
today,
|
||||
account.id,
|
||||
LICENSE_TYPE.NORMAL,
|
||||
LICENSE_ALLOCATED_STATUS.ALLOCATED,
|
||||
userId,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
);
|
||||
const context = makeContext(externalId);
|
||||
const baseUrl = `https://saodmsusdev.blob.core.windows.net/account-${account.id}/${userId}`;
|
||||
|
||||
const service = await makeFilesServiceMock(
|
||||
blobParam,
|
||||
{
|
||||
findUserByExternalId: new Error(''),
|
||||
//SASトークンを返却する
|
||||
overrideBlobstorageService(service, {
|
||||
containerExists: async () => true,
|
||||
publishUploadSas: async () => `${baseUrl}?sas-token`,
|
||||
});
|
||||
|
||||
const url = await service.publishUploadSas(context, externalId);
|
||||
|
||||
expect(url).toBe(`${baseUrl}?sas-token`);
|
||||
});
|
||||
|
||||
it('blobストレージにコンテナが存在しない場合はエラーとなる', async () => {
|
||||
if (!source) fail();
|
||||
const module = await makeTestingModule(source);
|
||||
if (!module) fail();
|
||||
const service = module.get<FilesService>(FilesService);
|
||||
// 第四階層のアカウント作成
|
||||
const { admin } = await makeTestAccount(source, { tier: 4 });
|
||||
|
||||
const context = makeContext(admin.external_id);
|
||||
|
||||
//Blobコンテナ存在チェックに失敗するようにする
|
||||
overrideBlobstorageService(service, {
|
||||
containerExists: async () => false,
|
||||
publishUploadSas: async () => '',
|
||||
});
|
||||
|
||||
try {
|
||||
await service.publishUploadSas(context, admin.external_id);
|
||||
} catch (e) {
|
||||
if (e instanceof HttpException) {
|
||||
expect(e.getStatus()).toBe(HttpStatus.INTERNAL_SERVER_ERROR);
|
||||
expect(e.getResponse()).toEqual(makeErrorResponse('E009999'));
|
||||
} else {
|
||||
fail();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it('SASトークンの取得に失敗した場合はエラーとなる', async () => {
|
||||
if (!source) fail();
|
||||
const module = await makeTestingModule(source);
|
||||
if (!module) fail();
|
||||
const service = module.get<FilesService>(FilesService);
|
||||
// 第四階層のアカウント作成
|
||||
const { admin } = await makeTestAccount(source, { tier: 4 });
|
||||
|
||||
const context = makeContext(admin.external_id);
|
||||
|
||||
//BlobのSASトークン生成に失敗するようにする
|
||||
overrideBlobstorageService(service, {
|
||||
containerExists: async () => true,
|
||||
publishUploadSas: async () => {
|
||||
throw new Error('blob failed');
|
||||
},
|
||||
taskRepoParam,
|
||||
});
|
||||
|
||||
try {
|
||||
await service.publishUploadSas(context, admin.external_id);
|
||||
} catch (e) {
|
||||
if (e instanceof HttpException) {
|
||||
expect(e.getStatus()).toBe(HttpStatus.INTERNAL_SERVER_ERROR);
|
||||
expect(e.getResponse()).toEqual(makeErrorResponse('E009999'));
|
||||
} else {
|
||||
fail();
|
||||
}
|
||||
}
|
||||
});
|
||||
it('アカウントがロックされている場合、エラーとなる', async () => {
|
||||
if (!source) fail();
|
||||
const module = await makeTestingModule(source);
|
||||
if (!module) fail();
|
||||
const service = module.get<FilesService>(FilesService);
|
||||
// 第五階層のアカウント作成
|
||||
const { admin } = await makeTestAccount(source, { tier: 5, locked: true });
|
||||
|
||||
const context = makeContext(admin.external_id);
|
||||
|
||||
try {
|
||||
await service.publishUploadSas(context, admin.external_id);
|
||||
} catch (e) {
|
||||
if (e instanceof HttpException) {
|
||||
expect(e.getStatus()).toBe(HttpStatus.BAD_REQUEST);
|
||||
expect(e.getResponse()).toEqual(makeErrorResponse('E010504'));
|
||||
} else {
|
||||
fail();
|
||||
}
|
||||
}
|
||||
});
|
||||
it('アップロード時にユーザーにライセンスが未割当の場合エラーとなる(第五階層限定)', async () => {
|
||||
if (!source) fail();
|
||||
// 第五階層のアカウントまで作成し、そのアカウントに紐づくユーザーを作成する(ライセンスは作成しない)
|
||||
const { tier4Accounts: tier4Accounts } = await makeHierarchicalAccounts(
|
||||
source,
|
||||
);
|
||||
const tier5Accounts = await makeTestAccount(source, {
|
||||
parent_account_id: tier4Accounts[0].account.id,
|
||||
tier: 5,
|
||||
});
|
||||
const { external_id: externalId, id: userId } = await makeTestUser(source, {
|
||||
account_id: tier5Accounts.account.id,
|
||||
external_id: 'author-user-external-id',
|
||||
role: 'author',
|
||||
author_id: 'AUTHOR_ID',
|
||||
});
|
||||
const url = `https://saodmsusdev.blob.core.windows.net/account-${tier5Accounts.account.id}/${userId}`;
|
||||
|
||||
const blobParam = makeBlobstorageServiceMockValue();
|
||||
blobParam.publishUploadSas = `${url}?sas-token`;
|
||||
blobParam.fileExists = false;
|
||||
|
||||
const notificationParam = makeDefaultNotificationhubServiceMockValue();
|
||||
const module = await makeTestingModuleWithBlobAndNotification(
|
||||
source,
|
||||
blobParam,
|
||||
notificationParam,
|
||||
);
|
||||
if (!module) fail();
|
||||
const service = module.get<FilesService>(FilesService);
|
||||
|
||||
await expect(
|
||||
service.publishUploadSas(
|
||||
makeContext('trackingId'),
|
||||
'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx',
|
||||
),
|
||||
service.publishUploadSas(makeContext('trackingId'), externalId),
|
||||
).rejects.toEqual(
|
||||
new HttpException(makeErrorResponse('E009999'), HttpStatus.UNAUTHORIZED),
|
||||
new HttpException(makeErrorResponse('E010812'), HttpStatus.BAD_REQUEST),
|
||||
);
|
||||
});
|
||||
|
||||
it('コンテナ作成に失敗した場合、例外エラーを返却する', async () => {
|
||||
const blobParam = makeBlobstorageServiceMockValue();
|
||||
const taskRepoParam = makeDefaultTasksRepositoryMockValue();
|
||||
|
||||
const service = await makeFilesServiceMock(
|
||||
blobParam,
|
||||
{
|
||||
findUserByExternalId: new Error(''),
|
||||
},
|
||||
taskRepoParam,
|
||||
it('アップロード時にユーザーに割り当てられたライセンスが有効期限切れの場合エラー(第五階層限定)', async () => {
|
||||
if (!source) fail();
|
||||
// 第五階層のアカウントまで作成し、そのアカウントに紐づくユーザーを作成する
|
||||
const { tier4Accounts: tier4Accounts } = await makeHierarchicalAccounts(
|
||||
source,
|
||||
);
|
||||
blobParam.publishUploadSas = new Error('Azure service down');
|
||||
const tier5Accounts = await makeTestAccount(source, {
|
||||
parent_account_id: tier4Accounts[0].account.id,
|
||||
tier: 5,
|
||||
});
|
||||
const {
|
||||
external_id: externalId,
|
||||
id: userId,
|
||||
author_id: authorId,
|
||||
} = await makeTestUser(source, {
|
||||
account_id: tier5Accounts.account.id,
|
||||
external_id: 'author-user-external-id',
|
||||
role: 'author',
|
||||
author_id: 'AUTHOR_ID',
|
||||
});
|
||||
// 昨日の日付を作成
|
||||
let yesterday = new Date();
|
||||
yesterday.setDate(yesterday.getDate() - 1);
|
||||
yesterday = new DateWithZeroTime(yesterday);
|
||||
// 期限切れのライセンスを作成して紐づける
|
||||
await createLicense(
|
||||
source,
|
||||
1,
|
||||
yesterday,
|
||||
tier5Accounts.account.id,
|
||||
LICENSE_TYPE.NORMAL,
|
||||
LICENSE_ALLOCATED_STATUS.ALLOCATED,
|
||||
userId,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
);
|
||||
const url = `https://saodmsusdev.blob.core.windows.net/account-${tier5Accounts.account.id}/${userId}`;
|
||||
|
||||
const blobParam = makeBlobstorageServiceMockValue();
|
||||
blobParam.publishUploadSas = `${url}?sas-token`;
|
||||
blobParam.fileExists = false;
|
||||
|
||||
const notificationParam = makeDefaultNotificationhubServiceMockValue();
|
||||
const module = await makeTestingModuleWithBlobAndNotification(
|
||||
source,
|
||||
blobParam,
|
||||
notificationParam,
|
||||
);
|
||||
if (!module) fail();
|
||||
const service = module.get<FilesService>(FilesService);
|
||||
|
||||
await expect(
|
||||
service.publishUploadSas(
|
||||
makeContext('trackingId'),
|
||||
'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx',
|
||||
),
|
||||
service.publishUploadSas(makeContext('trackingId'), externalId),
|
||||
).rejects.toEqual(
|
||||
new HttpException(makeErrorResponse('E009999'), HttpStatus.UNAUTHORIZED),
|
||||
new HttpException(makeErrorResponse('E010805'), HttpStatus.BAD_REQUEST),
|
||||
);
|
||||
});
|
||||
});
|
||||
@ -220,7 +370,12 @@ describe('タスク作成から自動ルーティング(DB使用)', () => {
|
||||
expect(NotificationHubService.notify).toHaveBeenCalledWith(
|
||||
makeContext('trackingId'),
|
||||
[`user_${typistUserId}`],
|
||||
makeNotifyMessage('M000101'),
|
||||
{
|
||||
authorId: 'AUTHOR_ID',
|
||||
filename: 'file',
|
||||
priority: 'High',
|
||||
uploadedAt: '2023-05-26T11:22:33.444',
|
||||
},
|
||||
);
|
||||
// 作成したタスクを取得
|
||||
const resultTask = await getTaskFromJobNumber(source, result.jobNumber);
|
||||
@ -316,7 +471,12 @@ describe('タスク作成から自動ルーティング(DB使用)', () => {
|
||||
expect(NotificationHubService.notify).toHaveBeenCalledWith(
|
||||
makeContext('trackingId'),
|
||||
[`user_${typistUserId}`],
|
||||
makeNotifyMessage('M000101'),
|
||||
{
|
||||
authorId: 'AUTHOR_ID',
|
||||
filename: 'file',
|
||||
priority: 'High',
|
||||
uploadedAt: '2023-05-26T11:22:33.444',
|
||||
},
|
||||
);
|
||||
// 作成したタスクを取得
|
||||
const resultTask = await getTaskFromJobNumber(source, result.jobNumber);
|
||||
@ -434,7 +594,12 @@ describe('タスク作成から自動ルーティング(DB使用)', () => {
|
||||
expect(NotificationHubService.notify).toHaveBeenCalledWith(
|
||||
makeContext('trackingId'),
|
||||
[`user_${typistUserId}`],
|
||||
makeNotifyMessage('M000101'),
|
||||
{
|
||||
authorId: 'AUTHOR_ID',
|
||||
filename: 'file',
|
||||
priority: 'High',
|
||||
uploadedAt: '2023-05-26T11:22:33.444',
|
||||
},
|
||||
);
|
||||
// 作成したタスクを取得
|
||||
const resultTask = await getTaskFromJobNumber(source, result.jobNumber);
|
||||
@ -551,7 +716,12 @@ describe('タスク作成から自動ルーティング(DB使用)', () => {
|
||||
expect(NotificationHubService.notify).toHaveBeenCalledWith(
|
||||
makeContext('trackingId'),
|
||||
[`user_${typistUserId}`],
|
||||
makeNotifyMessage('M000101'),
|
||||
{
|
||||
authorId: 'XXXXXXXXXX',
|
||||
filename: 'file',
|
||||
priority: 'High',
|
||||
uploadedAt: '2023-05-26T11:22:33.444',
|
||||
},
|
||||
);
|
||||
// 作成したタスクを取得
|
||||
const resultTask = await getTaskFromJobNumber(source, result.jobNumber);
|
||||
@ -565,7 +735,7 @@ describe('タスク作成から自動ルーティング(DB使用)', () => {
|
||||
// タスクのチェックアウト権限が想定通り(ワークフローで設定されている)のユーザーIDで作成されているか確認
|
||||
expect(resultCheckoutPermission.length).toEqual(1);
|
||||
expect(resultCheckoutPermission[0].user_group_id).toEqual(userGroupId);
|
||||
}, 1000000);
|
||||
});
|
||||
|
||||
it('ワークフローが見つからない場合、タスク作成時に、自動ルーティングを行うことができない', async () => {
|
||||
if (!source) fail();
|
||||
@ -879,7 +1049,76 @@ describe('音声ファイルダウンロードURL取得', () => {
|
||||
),
|
||||
).toEqual(`${url}?sas-token`);
|
||||
});
|
||||
it('ダウンロードSASトークンが乗っているURLを取得できる(第五階層の場合ライセンスのチェックを行う)', async () => {
|
||||
if (!source) fail();
|
||||
// 第五階層のアカウントまで作成し、そのアカウントに紐づくユーザーを作成する
|
||||
const { tier4Accounts: tier4Accounts } = await makeHierarchicalAccounts(
|
||||
source,
|
||||
);
|
||||
const tier5Accounts = await makeTestAccount(source, {
|
||||
parent_account_id: tier4Accounts[0].account.id,
|
||||
tier: 5,
|
||||
});
|
||||
const {
|
||||
external_id: externalId,
|
||||
id: userId,
|
||||
author_id: authorId,
|
||||
} = await makeTestUser(source, {
|
||||
account_id: tier5Accounts.account.id,
|
||||
external_id: 'author-user-external-id',
|
||||
role: 'author',
|
||||
author_id: 'AUTHOR_ID',
|
||||
});
|
||||
// 本日の日付を作成
|
||||
let today = new Date();
|
||||
today.setDate(today.getDate());
|
||||
today = new DateWithZeroTime(today);
|
||||
// 有効期限内のライセンスを作成して紐づける
|
||||
await createLicense(
|
||||
source,
|
||||
1,
|
||||
today,
|
||||
tier5Accounts.account.id,
|
||||
LICENSE_TYPE.NORMAL,
|
||||
LICENSE_ALLOCATED_STATUS.ALLOCATED,
|
||||
userId,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
);
|
||||
const url = `https://saodmsusdev.blob.core.windows.net/account-${tier5Accounts.account.id}/${userId}`;
|
||||
|
||||
const { audioFileId } = await createTask(
|
||||
source,
|
||||
tier5Accounts.account.id,
|
||||
url,
|
||||
'test.zip',
|
||||
'InProgress',
|
||||
undefined,
|
||||
authorId ?? '',
|
||||
);
|
||||
|
||||
const blobParam = makeBlobstorageServiceMockValue();
|
||||
blobParam.publishDownloadSas = `${url}?sas-token`;
|
||||
blobParam.fileExists = true;
|
||||
|
||||
const notificationParam = makeDefaultNotificationhubServiceMockValue();
|
||||
const module = await makeTestingModuleWithBlobAndNotification(
|
||||
source,
|
||||
blobParam,
|
||||
notificationParam,
|
||||
);
|
||||
if (!module) fail();
|
||||
const service = module.get<FilesService>(FilesService);
|
||||
|
||||
expect(
|
||||
await service.publishAudioFileDownloadSas(
|
||||
makeContext('trackingId'),
|
||||
externalId,
|
||||
audioFileId,
|
||||
),
|
||||
).toEqual(`${url}?sas-token`);
|
||||
});
|
||||
it('Typistの場合、タスクのステータスが[Inprogress,Pending]以外でエラー', async () => {
|
||||
if (!source) fail();
|
||||
const { id: accountId } = await makeTestSimpleAccount(source);
|
||||
@ -1109,6 +1348,133 @@ describe('音声ファイルダウンロードURL取得', () => {
|
||||
new HttpException(makeErrorResponse('E010701'), HttpStatus.BAD_REQUEST),
|
||||
);
|
||||
});
|
||||
it('ダウンロード時にユーザーにライセンスが未割当の場合エラーとなる(第五階層限定)', async () => {
|
||||
if (!source) fail();
|
||||
// 第五階層のアカウントまで作成し、そのアカウントに紐づくユーザーを作成する(ライセンスは作成しない)
|
||||
const { tier4Accounts: tier4Accounts } = await makeHierarchicalAccounts(
|
||||
source,
|
||||
);
|
||||
const tier5Accounts = await makeTestAccount(source, {
|
||||
parent_account_id: tier4Accounts[0].account.id,
|
||||
tier: 5,
|
||||
});
|
||||
const {
|
||||
external_id: externalId,
|
||||
id: userId,
|
||||
author_id: authorId,
|
||||
} = await makeTestUser(source, {
|
||||
account_id: tier5Accounts.account.id,
|
||||
external_id: 'author-user-external-id',
|
||||
role: 'author',
|
||||
author_id: 'AUTHOR_ID',
|
||||
});
|
||||
const url = `https://saodmsusdev.blob.core.windows.net/account-${tier5Accounts.account.id}/${userId}`;
|
||||
|
||||
const { audioFileId } = await createTask(
|
||||
source,
|
||||
tier5Accounts.account.id,
|
||||
url,
|
||||
'test.zip',
|
||||
'InProgress',
|
||||
undefined,
|
||||
authorId ?? '',
|
||||
);
|
||||
|
||||
const blobParam = makeBlobstorageServiceMockValue();
|
||||
blobParam.publishDownloadSas = `${url}?sas-token`;
|
||||
blobParam.fileExists = false;
|
||||
|
||||
const notificationParam = makeDefaultNotificationhubServiceMockValue();
|
||||
const module = await makeTestingModuleWithBlobAndNotification(
|
||||
source,
|
||||
blobParam,
|
||||
notificationParam,
|
||||
);
|
||||
if (!module) fail();
|
||||
const service = module.get<FilesService>(FilesService);
|
||||
|
||||
await expect(
|
||||
service.publishAudioFileDownloadSas(
|
||||
makeContext('trackingId'),
|
||||
externalId,
|
||||
audioFileId,
|
||||
),
|
||||
).rejects.toEqual(
|
||||
new HttpException(makeErrorResponse('E010812'), HttpStatus.BAD_REQUEST),
|
||||
);
|
||||
});
|
||||
it('ダウンロード時にユーザーに割り当てられたライセンスが有効期限切れの場合エラー(第五階層限定)', async () => {
|
||||
if (!source) fail();
|
||||
// 第五階層のアカウントまで作成し、そのアカウントに紐づくユーザーを作成する
|
||||
const { tier4Accounts: tier4Accounts } = await makeHierarchicalAccounts(
|
||||
source,
|
||||
);
|
||||
const tier5Accounts = await makeTestAccount(source, {
|
||||
parent_account_id: tier4Accounts[0].account.id,
|
||||
tier: 5,
|
||||
});
|
||||
const {
|
||||
external_id: externalId,
|
||||
id: userId,
|
||||
author_id: authorId,
|
||||
} = await makeTestUser(source, {
|
||||
account_id: tier5Accounts.account.id,
|
||||
external_id: 'author-user-external-id',
|
||||
role: 'author',
|
||||
author_id: 'AUTHOR_ID',
|
||||
});
|
||||
// 昨日の日付を作成
|
||||
let yesterday = new Date();
|
||||
yesterday.setDate(yesterday.getDate() - 1);
|
||||
yesterday = new DateWithZeroTime(yesterday);
|
||||
// 期限切れのライセンスを作成して紐づける
|
||||
await createLicense(
|
||||
source,
|
||||
1,
|
||||
yesterday,
|
||||
tier5Accounts.account.id,
|
||||
LICENSE_TYPE.NORMAL,
|
||||
LICENSE_ALLOCATED_STATUS.ALLOCATED,
|
||||
userId,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
);
|
||||
const url = `https://saodmsusdev.blob.core.windows.net/account-${tier5Accounts.account.id}/${userId}`;
|
||||
|
||||
const { audioFileId } = await createTask(
|
||||
source,
|
||||
tier5Accounts.account.id,
|
||||
url,
|
||||
'test.zip',
|
||||
'InProgress',
|
||||
undefined,
|
||||
authorId ?? '',
|
||||
);
|
||||
|
||||
const blobParam = makeBlobstorageServiceMockValue();
|
||||
blobParam.publishDownloadSas = `${url}?sas-token`;
|
||||
blobParam.fileExists = false;
|
||||
|
||||
const notificationParam = makeDefaultNotificationhubServiceMockValue();
|
||||
const module = await makeTestingModuleWithBlobAndNotification(
|
||||
source,
|
||||
blobParam,
|
||||
notificationParam,
|
||||
);
|
||||
if (!module) fail();
|
||||
const service = module.get<FilesService>(FilesService);
|
||||
|
||||
await expect(
|
||||
service.publishAudioFileDownloadSas(
|
||||
makeContext('trackingId'),
|
||||
externalId,
|
||||
audioFileId,
|
||||
),
|
||||
).rejects.toEqual(
|
||||
new HttpException(makeErrorResponse('E010805'), HttpStatus.BAD_REQUEST),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('テンプレートファイルダウンロードURL取得', () => {
|
||||
@ -1175,7 +1541,76 @@ describe('テンプレートファイルダウンロードURL取得', () => {
|
||||
),
|
||||
).toEqual(`${url}?sas-token`);
|
||||
});
|
||||
it('ダウンロードSASトークンが乗っているURLを取得できる(第五階層の場合ライセンスのチェックを行う)', async () => {
|
||||
if (!source) fail();
|
||||
// 第五階層のアカウントまで作成し、そのアカウントに紐づくユーザーを作成する
|
||||
const { tier4Accounts: tier4Accounts } = await makeHierarchicalAccounts(
|
||||
source,
|
||||
);
|
||||
const tier5Accounts = await makeTestAccount(source, {
|
||||
parent_account_id: tier4Accounts[0].account.id,
|
||||
tier: 5,
|
||||
});
|
||||
const {
|
||||
external_id: externalId,
|
||||
id: userId,
|
||||
author_id: authorId,
|
||||
} = await makeTestUser(source, {
|
||||
account_id: tier5Accounts.account.id,
|
||||
external_id: 'author-user-external-id',
|
||||
role: 'author',
|
||||
author_id: 'AUTHOR_ID',
|
||||
});
|
||||
// 本日の日付を作成
|
||||
let yesterday = new Date();
|
||||
yesterday.setDate(yesterday.getDate());
|
||||
yesterday = new DateWithZeroTime(yesterday);
|
||||
// 有効期限内のライセンスを作成して紐づける
|
||||
await createLicense(
|
||||
source,
|
||||
1,
|
||||
yesterday,
|
||||
tier5Accounts.account.id,
|
||||
LICENSE_TYPE.NORMAL,
|
||||
LICENSE_ALLOCATED_STATUS.ALLOCATED,
|
||||
userId,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
);
|
||||
const url = `https://saodmsusdev.blob.core.windows.net/account-${tier5Accounts.account.id}/${userId}`;
|
||||
|
||||
const { audioFileId } = await createTask(
|
||||
source,
|
||||
tier5Accounts.account.id,
|
||||
url,
|
||||
'test.zip',
|
||||
'InProgress',
|
||||
undefined,
|
||||
authorId ?? '',
|
||||
);
|
||||
|
||||
const blobParam = makeBlobstorageServiceMockValue();
|
||||
blobParam.publishDownloadSas = `${url}?sas-token`;
|
||||
blobParam.fileExists = true;
|
||||
|
||||
const notificationParam = makeDefaultNotificationhubServiceMockValue();
|
||||
const module = await makeTestingModuleWithBlobAndNotification(
|
||||
source,
|
||||
blobParam,
|
||||
notificationParam,
|
||||
);
|
||||
if (!module) fail();
|
||||
const service = module.get<FilesService>(FilesService);
|
||||
|
||||
expect(
|
||||
await service.publishTemplateFileDownloadSas(
|
||||
makeContext('trackingId'),
|
||||
externalId,
|
||||
audioFileId,
|
||||
),
|
||||
).toEqual(`${url}?sas-token`);
|
||||
});
|
||||
it('Typistの場合、タスクのステータスが[Inprogress,Pending]以外でエラー', async () => {
|
||||
if (!source) fail();
|
||||
const { id: accountId } = await makeTestSimpleAccount(source);
|
||||
@ -1394,6 +1829,133 @@ describe('テンプレートファイルダウンロードURL取得', () => {
|
||||
new HttpException(makeErrorResponse('E010701'), HttpStatus.BAD_REQUEST),
|
||||
);
|
||||
});
|
||||
it('ダウンロード時にユーザーにライセンスが未割当の場合エラーとなる(第五階層限定)', async () => {
|
||||
if (!source) fail();
|
||||
// 第五階層のアカウントまで作成し、そのアカウントに紐づくユーザーを作成する(ライセンスは作成しない)
|
||||
const { tier4Accounts: tier4Accounts } = await makeHierarchicalAccounts(
|
||||
source,
|
||||
);
|
||||
const tier5Accounts = await makeTestAccount(source, {
|
||||
parent_account_id: tier4Accounts[0].account.id,
|
||||
tier: 5,
|
||||
});
|
||||
const {
|
||||
external_id: externalId,
|
||||
id: userId,
|
||||
author_id: authorId,
|
||||
} = await makeTestUser(source, {
|
||||
account_id: tier5Accounts.account.id,
|
||||
external_id: 'author-user-external-id',
|
||||
role: 'author',
|
||||
author_id: 'AUTHOR_ID',
|
||||
});
|
||||
const url = `https://saodmsusdev.blob.core.windows.net/account-${tier5Accounts.account.id}/${userId}`;
|
||||
|
||||
const { audioFileId } = await createTask(
|
||||
source,
|
||||
tier5Accounts.account.id,
|
||||
url,
|
||||
'test.zip',
|
||||
'InProgress',
|
||||
undefined,
|
||||
authorId ?? '',
|
||||
);
|
||||
|
||||
const blobParam = makeBlobstorageServiceMockValue();
|
||||
blobParam.publishDownloadSas = `${url}?sas-token`;
|
||||
blobParam.fileExists = false;
|
||||
|
||||
const notificationParam = makeDefaultNotificationhubServiceMockValue();
|
||||
const module = await makeTestingModuleWithBlobAndNotification(
|
||||
source,
|
||||
blobParam,
|
||||
notificationParam,
|
||||
);
|
||||
if (!module) fail();
|
||||
const service = module.get<FilesService>(FilesService);
|
||||
|
||||
await expect(
|
||||
service.publishTemplateFileDownloadSas(
|
||||
makeContext('trackingId'),
|
||||
externalId,
|
||||
audioFileId,
|
||||
),
|
||||
).rejects.toEqual(
|
||||
new HttpException(makeErrorResponse('E010812'), HttpStatus.BAD_REQUEST),
|
||||
);
|
||||
});
|
||||
it('ダウンロード時にユーザーに割り当てられたライセンスが有効期限切れの場合エラー(第五階層限定)', async () => {
|
||||
if (!source) fail();
|
||||
// 第五階層のアカウントまで作成し、そのアカウントに紐づくユーザーを作成する
|
||||
const { tier4Accounts: tier4Accounts } = await makeHierarchicalAccounts(
|
||||
source,
|
||||
);
|
||||
const tier5Accounts = await makeTestAccount(source, {
|
||||
parent_account_id: tier4Accounts[0].account.id,
|
||||
tier: 5,
|
||||
});
|
||||
const {
|
||||
external_id: externalId,
|
||||
id: userId,
|
||||
author_id: authorId,
|
||||
} = await makeTestUser(source, {
|
||||
account_id: tier5Accounts.account.id,
|
||||
external_id: 'author-user-external-id',
|
||||
role: 'author',
|
||||
author_id: 'AUTHOR_ID',
|
||||
});
|
||||
// 昨日の日付を作成
|
||||
let yesterday = new Date();
|
||||
yesterday.setDate(yesterday.getDate() - 1);
|
||||
yesterday = new DateWithZeroTime(yesterday);
|
||||
// 期限切れのライセンスを作成して紐づける
|
||||
await createLicense(
|
||||
source,
|
||||
1,
|
||||
yesterday,
|
||||
tier5Accounts.account.id,
|
||||
LICENSE_TYPE.NORMAL,
|
||||
LICENSE_ALLOCATED_STATUS.ALLOCATED,
|
||||
userId,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
);
|
||||
const url = `https://saodmsusdev.blob.core.windows.net/account-${tier5Accounts.account.id}/${userId}`;
|
||||
|
||||
const { audioFileId } = await createTask(
|
||||
source,
|
||||
tier5Accounts.account.id,
|
||||
url,
|
||||
'test.zip',
|
||||
'InProgress',
|
||||
undefined,
|
||||
authorId ?? '',
|
||||
);
|
||||
|
||||
const blobParam = makeBlobstorageServiceMockValue();
|
||||
blobParam.publishDownloadSas = `${url}?sas-token`;
|
||||
blobParam.fileExists = false;
|
||||
|
||||
const notificationParam = makeDefaultNotificationhubServiceMockValue();
|
||||
const module = await makeTestingModuleWithBlobAndNotification(
|
||||
source,
|
||||
blobParam,
|
||||
notificationParam,
|
||||
);
|
||||
if (!module) fail();
|
||||
const service = module.get<FilesService>(FilesService);
|
||||
|
||||
await expect(
|
||||
service.publishTemplateFileDownloadSas(
|
||||
makeContext('trackingId'),
|
||||
externalId,
|
||||
audioFileId,
|
||||
),
|
||||
).rejects.toEqual(
|
||||
new HttpException(makeErrorResponse('E010805'), HttpStatus.BAD_REQUEST),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('publishTemplateFileUploadSas', () => {
|
||||
|
||||
@ -7,6 +7,7 @@ import { AudioOptionItem, AudioUploadFinishedResponse } from './types/types';
|
||||
import {
|
||||
OPTION_ITEM_NUM,
|
||||
TASK_STATUS,
|
||||
TIERS,
|
||||
USER_ROLES,
|
||||
} from '../../constants/index';
|
||||
import { User } from '../../repositories/users/entity/user.entity';
|
||||
@ -23,11 +24,18 @@ import {
|
||||
} from '../../repositories/tasks/errors/types';
|
||||
import { Context } from '../../common/log';
|
||||
import { TemplateFilesRepositoryService } from '../../repositories/template_files/template_files.repository.service';
|
||||
import { AccountNotFoundError } from '../../repositories/accounts/errors/types';
|
||||
import {
|
||||
AccountNotFoundError,
|
||||
AccountLockedError,
|
||||
} from '../../repositories/accounts/errors/types';
|
||||
import { Task } from '../../repositories/tasks/entity/task.entity';
|
||||
import { UserGroupsRepositoryService } from '../../repositories/user_groups/user_groups.repository.service';
|
||||
import { makeNotifyMessage } from '../../common/notify/makeNotifyMessage';
|
||||
import { NotificationhubService } from '../../gateways/notificationhub/notificationhub.service';
|
||||
import {
|
||||
LicenseExpiredError,
|
||||
LicenseNotAllocatedError,
|
||||
} from '../../repositories/licenses/errors/types';
|
||||
import { DateWithZeroTime } from '../licenses/types/types';
|
||||
|
||||
@Injectable()
|
||||
export class FilesService {
|
||||
@ -79,7 +87,10 @@ export class FilesService {
|
||||
isEncrypted: boolean,
|
||||
): Promise<AudioUploadFinishedResponse> {
|
||||
this.logger.log(
|
||||
`[IN] [${context.trackingId}] ${this.uploadFinished.name} | params: { ` +
|
||||
`[IN] [${context.getTrackingId()}] ${
|
||||
this.uploadFinished.name
|
||||
} | params: { ` +
|
||||
`userId: ${userId}, ` +
|
||||
`url: ${url}, ` +
|
||||
`authorId: ${authorId}, ` +
|
||||
`fileName: ${fileName}, ` +
|
||||
@ -112,21 +123,21 @@ export class FilesService {
|
||||
) {
|
||||
if (isInvalidCreatedDate) {
|
||||
this.logger.error(
|
||||
`param createdDate is invalid format:[createdDate=${createdDate}]`,
|
||||
`[${context.getTrackingId()}] param createdDate is invalid format:[createdDate=${createdDate}]`,
|
||||
);
|
||||
}
|
||||
if (isInvalidFinishedDate) {
|
||||
this.logger.error(
|
||||
`param finishedDate is invalid format:[finishedDate=${finishedDate}]`,
|
||||
`[${context.getTrackingId()}] param finishedDate is invalid format:[finishedDate=${finishedDate}]`,
|
||||
);
|
||||
}
|
||||
if (isInvalidUploadedDate) {
|
||||
this.logger.error(
|
||||
`param uploadedDate is invalid format:[uploadedDate=${uploadedDate}]`,
|
||||
`[${context.getTrackingId()}] param uploadedDate is invalid format:[uploadedDate=${uploadedDate}]`,
|
||||
);
|
||||
}
|
||||
this.logger.log(
|
||||
`[OUT] [${context.trackingId}] ${this.uploadFinished.name}`,
|
||||
`[OUT] [${context.getTrackingId()}] ${this.uploadFinished.name}`,
|
||||
);
|
||||
|
||||
throw new HttpException(
|
||||
@ -138,10 +149,12 @@ export class FilesService {
|
||||
// オプションアイテムが10個ない場合はパラメータ不正
|
||||
if (optionItemList.length !== OPTION_ITEM_NUM) {
|
||||
this.logger.error(
|
||||
`param optionItemList expects ${OPTION_ITEM_NUM} items, but has ${optionItemList.length} items`,
|
||||
`[${context.getTrackingId()}] param optionItemList expects ${OPTION_ITEM_NUM} items, but has ${
|
||||
optionItemList.length
|
||||
} items`,
|
||||
);
|
||||
this.logger.log(
|
||||
`[OUT] [${context.trackingId}] ${this.uploadFinished.name}`,
|
||||
`[OUT] [${context.getTrackingId()}] ${this.uploadFinished.name}`,
|
||||
);
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E010001'),
|
||||
@ -154,9 +167,9 @@ export class FilesService {
|
||||
// ユーザー取得
|
||||
user = await this.usersRepository.findUserByExternalId(userId);
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
this.logger.log(
|
||||
`[OUT] [${context.trackingId}] ${this.uploadFinished.name}`,
|
||||
`[OUT] [${context.getTrackingId()}] ${this.uploadFinished.name}`,
|
||||
);
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
@ -169,7 +182,9 @@ export class FilesService {
|
||||
const urlObj = new URL(url);
|
||||
urlObj.search = '';
|
||||
const fileUrl = urlObj.toString();
|
||||
this.logger.log(`Request URL: ${url}, Without param URL${fileUrl}`);
|
||||
this.logger.log(
|
||||
`[${context.getTrackingId()}] Request URL: ${url}, Without param URL${fileUrl}`,
|
||||
);
|
||||
|
||||
// 文字起こしタスク追加(音声ファイルとオプションアイテムも同時に追加)
|
||||
// 追加時に末尾のJOBナンバーにインクリメントする
|
||||
@ -192,7 +207,7 @@ export class FilesService {
|
||||
optionItemList,
|
||||
);
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
@ -219,31 +234,34 @@ export class FilesService {
|
||||
|
||||
// 割り当てられたユーザーがいない場合は通知不要
|
||||
if (distinctUserIds.length === 0) {
|
||||
this.logger.log('No user assigned.');
|
||||
this.logger.log(`[${context.getTrackingId()}] No user assigned.`);
|
||||
return { jobNumber: task.job_number };
|
||||
}
|
||||
|
||||
// タグを生成
|
||||
const tags = distinctUserIds.map((x) => `user_${x}`);
|
||||
this.logger.log(`tags: ${tags}`);
|
||||
this.logger.log(`[${context.getTrackingId()}] tags: ${tags}`);
|
||||
|
||||
// タグ対象に通知送信
|
||||
await this.notificationhubService.notify(
|
||||
context,
|
||||
tags,
|
||||
makeNotifyMessage('M000101'),
|
||||
);
|
||||
await this.notificationhubService.notify(context, tags, {
|
||||
authorId: authorId,
|
||||
filename: fileName.replace('.zip', ''),
|
||||
priority: priority === '00' ? 'Normal' : 'High',
|
||||
uploadedAt: uploadedDate,
|
||||
});
|
||||
|
||||
// 追加したタスクのJOBナンバーを返却
|
||||
return { jobNumber: task.job_number };
|
||||
} catch (error) {
|
||||
// 処理の本筋はタスク生成のため自動ルーティングに失敗してもエラーにしない
|
||||
this.logger.error(`Automatic routing or notification failed.`);
|
||||
this.logger.error(`error=${error}`);
|
||||
this.logger.error(
|
||||
`[${context.getTrackingId()}] Automatic routing or notification failed.`,
|
||||
);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${error}`);
|
||||
return { jobNumber: task.job_number };
|
||||
} finally {
|
||||
this.logger.log(
|
||||
`[OUT] [${context.trackingId}] ${this.uploadFinished.name}`,
|
||||
`[OUT] [${context.getTrackingId()}] ${this.uploadFinished.name}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -258,7 +276,9 @@ export class FilesService {
|
||||
externalId: string,
|
||||
): Promise<string> {
|
||||
this.logger.log(
|
||||
`[IN] [${context.trackingId}] ${this.publishUploadSas.name} | params: { externalId: ${externalId} };`,
|
||||
`[IN] [${context.getTrackingId()}] ${
|
||||
this.publishUploadSas.name
|
||||
} | params: { externalId: ${externalId} };`,
|
||||
);
|
||||
|
||||
//DBから国情報とアカウントIDを取得する
|
||||
@ -269,7 +289,21 @@ export class FilesService {
|
||||
}
|
||||
const accountId = user.account_id;
|
||||
const country = user.account.country;
|
||||
|
||||
// 第五階層のみチェック
|
||||
if (user.account.tier === TIERS.TIER5) {
|
||||
// アカウントがロックされている場合、エラー
|
||||
if (user.account.locked) {
|
||||
throw new AccountLockedError('account is locked.');
|
||||
}
|
||||
// ライセンスの有効性をチェック
|
||||
const { licenseError } = await this.checkLicenseValidityByUserId(
|
||||
context,
|
||||
user.id,
|
||||
);
|
||||
if (licenseError) {
|
||||
throw licenseError;
|
||||
}
|
||||
}
|
||||
// 国に応じたリージョンのBlobストレージにコンテナが存在するか確認
|
||||
await this.blobStorageService.containerExists(
|
||||
context,
|
||||
@ -285,14 +319,32 @@ export class FilesService {
|
||||
);
|
||||
return url;
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
switch (e.constructor) {
|
||||
case AccountLockedError:
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E010504'),
|
||||
HttpStatus.BAD_REQUEST,
|
||||
);
|
||||
case LicenseExpiredError:
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E010805'),
|
||||
HttpStatus.BAD_REQUEST,
|
||||
);
|
||||
case LicenseNotAllocatedError:
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E010812'),
|
||||
HttpStatus.BAD_REQUEST,
|
||||
);
|
||||
default:
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
} finally {
|
||||
this.logger.log(
|
||||
`[OUT] [${context.trackingId}] ${this.publishUploadSas.name}`,
|
||||
`[OUT] [${context.getTrackingId()}] ${this.publishUploadSas.name}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -309,7 +361,9 @@ export class FilesService {
|
||||
audioFileId: number,
|
||||
): Promise<string> {
|
||||
this.logger.log(
|
||||
`[IN] [${context.trackingId}] ${this.publishAudioFileDownloadSas.name} | params: { externalId: ${externalId}, audioFileId: ${audioFileId} };`,
|
||||
`[IN] [${context.getTrackingId()}] ${
|
||||
this.publishAudioFileDownloadSas.name
|
||||
} | params: { externalId: ${externalId}, audioFileId: ${audioFileId} };`,
|
||||
);
|
||||
|
||||
//DBから国情報とアカウントID,ユーザーIDを取得する
|
||||
@ -323,21 +377,46 @@ export class FilesService {
|
||||
if (!user.account) {
|
||||
throw new AccountNotFoundError('account not found.');
|
||||
}
|
||||
// 第五階層のみチェック
|
||||
if (user.account.tier === TIERS.TIER5) {
|
||||
// ライセンスの有効性をチェック
|
||||
const { licenseError } = await this.checkLicenseValidityByUserId(
|
||||
context,
|
||||
user.id,
|
||||
);
|
||||
if (licenseError) {
|
||||
throw licenseError;
|
||||
}
|
||||
}
|
||||
accountId = user.account.id;
|
||||
userId = user.id;
|
||||
country = user.account.country;
|
||||
isTypist = user.role === USER_ROLES.TYPIST;
|
||||
authorId = user.author_id ?? undefined;
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
this.logger.log(
|
||||
`[OUT] [${context.trackingId}] ${this.publishAudioFileDownloadSas.name}`,
|
||||
);
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
`[OUT] [${context.getTrackingId()}] ${
|
||||
this.publishAudioFileDownloadSas.name
|
||||
}`,
|
||||
);
|
||||
switch (e.constructor) {
|
||||
case LicenseExpiredError:
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E010805'),
|
||||
HttpStatus.BAD_REQUEST,
|
||||
);
|
||||
case LicenseNotAllocatedError:
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E010812'),
|
||||
HttpStatus.BAD_REQUEST,
|
||||
);
|
||||
default:
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
@ -384,7 +463,7 @@ export class FilesService {
|
||||
);
|
||||
|
||||
if (!isFileExist) {
|
||||
this.logger.log(`filePath:${filePath}`);
|
||||
this.logger.log(`[${context.getTrackingId()}] filePath:${filePath}`);
|
||||
throw new AudioFileNotFoundError(
|
||||
`Audio file is not exists in blob storage. audio_file_id:${audioFileId}, url:${file.url}, fileName:${file.file_name}`,
|
||||
);
|
||||
@ -399,7 +478,7 @@ export class FilesService {
|
||||
);
|
||||
return url;
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
if (e instanceof Error) {
|
||||
switch (e.constructor) {
|
||||
case TasksNotFoundError:
|
||||
@ -429,7 +508,9 @@ export class FilesService {
|
||||
);
|
||||
} finally {
|
||||
this.logger.log(
|
||||
`[OUT] [${context.trackingId}] ${this.publishAudioFileDownloadSas.name}`,
|
||||
`[OUT] [${context.getTrackingId()}] ${
|
||||
this.publishAudioFileDownloadSas.name
|
||||
}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -446,7 +527,9 @@ export class FilesService {
|
||||
audioFileId: number,
|
||||
): Promise<string> {
|
||||
this.logger.log(
|
||||
`[IN] [${context.trackingId}] ${this.publishTemplateFileDownloadSas.name} | params: { externalId: ${externalId}, audioFileId: ${audioFileId} };`,
|
||||
`[IN] [${context.getTrackingId()}] ${
|
||||
this.publishTemplateFileDownloadSas.name
|
||||
} | params: { externalId: ${externalId}, audioFileId: ${audioFileId} };`,
|
||||
);
|
||||
|
||||
//DBから国情報とアカウントID,ユーザーIDを取得する
|
||||
@ -460,20 +543,46 @@ export class FilesService {
|
||||
if (!user.account) {
|
||||
throw new AccountNotFoundError('account not found.');
|
||||
}
|
||||
// 第五階層のみチェック
|
||||
if (user.account.tier === TIERS.TIER5) {
|
||||
// ライセンスの有効性をチェック
|
||||
const { licenseError } = await this.checkLicenseValidityByUserId(
|
||||
context,
|
||||
user.id,
|
||||
);
|
||||
if (licenseError) {
|
||||
throw licenseError;
|
||||
}
|
||||
}
|
||||
accountId = user.account_id;
|
||||
userId = user.id;
|
||||
country = user.account.country;
|
||||
isTypist = user.role === USER_ROLES.TYPIST;
|
||||
authorId = user.author_id ?? undefined;
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
this.logger.log(
|
||||
`[OUT] [${context.trackingId}] ${this.publishTemplateFileDownloadSas.name}`,
|
||||
);
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
`[OUT] [${context.getTrackingId()}] ${
|
||||
this.publishTemplateFileDownloadSas.name
|
||||
}`,
|
||||
);
|
||||
switch (e.constructor) {
|
||||
case LicenseExpiredError:
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E010805'),
|
||||
HttpStatus.BAD_REQUEST,
|
||||
);
|
||||
case LicenseNotAllocatedError:
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E010812'),
|
||||
HttpStatus.BAD_REQUEST,
|
||||
);
|
||||
default:
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
@ -544,7 +653,7 @@ export class FilesService {
|
||||
);
|
||||
return url;
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
if (e instanceof Error) {
|
||||
switch (e.constructor) {
|
||||
case TasksNotFoundError:
|
||||
@ -562,6 +671,7 @@ export class FilesService {
|
||||
makeErrorResponse('E010701'),
|
||||
HttpStatus.BAD_REQUEST,
|
||||
);
|
||||
|
||||
default:
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
@ -575,7 +685,9 @@ export class FilesService {
|
||||
);
|
||||
} finally {
|
||||
this.logger.log(
|
||||
`[OUT] [${context.trackingId}] ${this.publishTemplateFileDownloadSas.name}`,
|
||||
`[OUT] [${context.getTrackingId()}] ${
|
||||
this.publishTemplateFileDownloadSas.name
|
||||
}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -591,7 +703,9 @@ export class FilesService {
|
||||
externalId: string,
|
||||
): Promise<string> {
|
||||
this.logger.log(
|
||||
`[IN] [${context.trackingId}] ${this.publishTemplateFileUploadSas.name} | params: { externalId: ${externalId} };`,
|
||||
`[IN] [${context.getTrackingId()}] ${
|
||||
this.publishTemplateFileUploadSas.name
|
||||
} | params: { externalId: ${externalId} };`,
|
||||
);
|
||||
try {
|
||||
const { account } = await this.usersRepository.findUserByExternalId(
|
||||
@ -620,14 +734,16 @@ export class FilesService {
|
||||
|
||||
return url;
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
} finally {
|
||||
this.logger.log(
|
||||
`[OUT] [${context.trackingId}] ${this.publishTemplateFileUploadSas.name}`,
|
||||
`[OUT] [${context.getTrackingId()}] ${
|
||||
this.publishTemplateFileUploadSas.name
|
||||
}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -647,7 +763,9 @@ export class FilesService {
|
||||
fileName: string,
|
||||
): Promise<void> {
|
||||
this.logger.log(
|
||||
`[IN] [${context.trackingId}] ${this.templateUploadFinished.name} | params: { externalId: ${externalId}, url: ${url}, fileName: ${fileName} };`,
|
||||
`[IN] [${context.getTrackingId()}] ${
|
||||
this.templateUploadFinished.name
|
||||
} | params: { externalId: ${externalId}, url: ${url}, fileName: ${fileName} };`,
|
||||
);
|
||||
|
||||
try {
|
||||
@ -659,7 +777,9 @@ export class FilesService {
|
||||
const urlObj = new URL(url);
|
||||
urlObj.search = '';
|
||||
const fileUrl = urlObj.toString();
|
||||
this.logger.log(`Request URL: ${url}, Without param URL${fileUrl}`);
|
||||
this.logger.log(
|
||||
`[${context.getTrackingId()}] Request URL: ${url}, Without param URL${fileUrl}`,
|
||||
);
|
||||
|
||||
// テンプレートファイル情報をDBに登録
|
||||
await this.templateFilesRepository.upsertTemplateFile(
|
||||
@ -668,15 +788,63 @@ export class FilesService {
|
||||
fileUrl,
|
||||
);
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
} finally {
|
||||
this.logger.log(
|
||||
`[OUT] [${context.trackingId}] ${this.templateUploadFinished.name}`,
|
||||
`[OUT] [${context.getTrackingId()}] ${
|
||||
this.templateUploadFinished.name
|
||||
}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ユーザーに割り当てられているライセンスの有効性をチェックする。
|
||||
* ライセンスが割り当てられていない場合、またはライセンスが有効期限切れの場合、エラー返却する。
|
||||
* @param userId
|
||||
* @returns licenseError?
|
||||
*/
|
||||
// TODO: TASK3084で共通部品化する
|
||||
private async checkLicenseValidityByUserId(
|
||||
context: Context,
|
||||
userId: number,
|
||||
): Promise<{ licenseError?: Error }> {
|
||||
this.logger.log(
|
||||
`[IN] [${context.getTrackingId()}] ${
|
||||
this.checkLicenseValidityByUserId.name
|
||||
} | params: { userId: ${userId} };`,
|
||||
);
|
||||
try {
|
||||
const allocatedLicense = await this.usersRepository.findLicenseByUserId(
|
||||
userId,
|
||||
);
|
||||
|
||||
if (!allocatedLicense) {
|
||||
return {
|
||||
licenseError: new LicenseNotAllocatedError(
|
||||
'license is not allocated.',
|
||||
),
|
||||
};
|
||||
} else {
|
||||
const currentDate = new DateWithZeroTime();
|
||||
if (
|
||||
allocatedLicense.expiry_date &&
|
||||
allocatedLicense.expiry_date < currentDate
|
||||
) {
|
||||
return {
|
||||
licenseError: new LicenseExpiredError('license is expired.'),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return {}; // エラーがない場合は空のオブジェクトを返す
|
||||
} catch (e) {
|
||||
// リポジトリ層のエラーやその他の例外をハンドリング
|
||||
return e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -19,6 +19,7 @@ export type BlobstorageServiceMockValue = {
|
||||
|
||||
export type UsersRepositoryMockValue = {
|
||||
findUserByExternalId: User | Error;
|
||||
isUserLicenseValid: boolean | Error;
|
||||
};
|
||||
|
||||
export type TasksRepositoryMockValue = {
|
||||
@ -91,13 +92,17 @@ export const makeBlobstorageServiceMock = (
|
||||
};
|
||||
|
||||
export const makeUsersRepositoryMock = (value: UsersRepositoryMockValue) => {
|
||||
const { findUserByExternalId } = value;
|
||||
const { findUserByExternalId, isUserLicenseValid } = value;
|
||||
|
||||
return {
|
||||
findUserByExternalId:
|
||||
findUserByExternalId instanceof Error
|
||||
? jest.fn<Promise<void>, []>().mockRejectedValue(findUserByExternalId)
|
||||
: jest.fn<Promise<User>, []>().mockResolvedValue(findUserByExternalId),
|
||||
isUserLicenseValid:
|
||||
isUserLicenseValid instanceof Error
|
||||
? jest.fn<Promise<void>, []>().mockRejectedValue(isUserLicenseValid)
|
||||
: jest.fn<Promise<boolean>, []>().mockResolvedValue(isUserLicenseValid),
|
||||
};
|
||||
};
|
||||
|
||||
@ -169,6 +174,7 @@ export const makeDefaultUsersRepositoryMockValue =
|
||||
user: null,
|
||||
},
|
||||
},
|
||||
isUserLicenseValid: true,
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@ -43,6 +43,7 @@ import {
|
||||
} from '../../tasks/test/tasks.service.mock';
|
||||
import { UserGroup } from '../../../repositories/user_groups/entity/user_group.entity';
|
||||
import { UserGroupMember } from '../../../repositories/user_groups/entity/user_group_member.entity';
|
||||
import { License } from '../../../repositories/licenses/entity/license.entity';
|
||||
|
||||
export const createTask = async (
|
||||
datasource: DataSource,
|
||||
@ -205,3 +206,33 @@ export const makeTestingModuleWithBlobAndNotification = async (
|
||||
console.log(e);
|
||||
}
|
||||
};
|
||||
|
||||
export const createLicense = async (
|
||||
datasource: DataSource,
|
||||
licenseId: number,
|
||||
expiry_date: Date | null,
|
||||
accountId: number,
|
||||
type: string,
|
||||
status: string,
|
||||
allocated_user_id: number | null,
|
||||
order_id: number | null,
|
||||
deleted_at: Date | null,
|
||||
delete_order_id: number | null,
|
||||
): Promise<void> => {
|
||||
const { identifiers } = await datasource.getRepository(License).insert({
|
||||
id: licenseId,
|
||||
expiry_date: expiry_date,
|
||||
account_id: accountId,
|
||||
type: type,
|
||||
status: status,
|
||||
allocated_user_id: allocated_user_id,
|
||||
order_id: order_id,
|
||||
deleted_at: deleted_at,
|
||||
delete_order_id: delete_order_id,
|
||||
created_by: 'test_runner',
|
||||
created_at: new Date(),
|
||||
updated_by: 'updater',
|
||||
updated_at: new Date(),
|
||||
});
|
||||
identifiers.pop() as License;
|
||||
};
|
||||
|
||||
@ -91,9 +91,11 @@ export class LicensesController {
|
||||
);
|
||||
}
|
||||
const { userId } = decodedAccessToken as AccessToken;
|
||||
const context = makeContext(userId);
|
||||
|
||||
// ライセンス注文処理
|
||||
await this.licensesService.licenseOrders(
|
||||
context,
|
||||
userId,
|
||||
body.poNumber,
|
||||
body.orderCount,
|
||||
@ -142,8 +144,10 @@ export class LicensesController {
|
||||
);
|
||||
}
|
||||
const { userId } = decodedAccessToken as AccessToken;
|
||||
const context = makeContext(userId);
|
||||
|
||||
const cardLicenseKeys = await this.licensesService.issueCardLicenseKeys(
|
||||
context,
|
||||
userId,
|
||||
body.createCount,
|
||||
);
|
||||
@ -202,8 +206,10 @@ export class LicensesController {
|
||||
);
|
||||
}
|
||||
const { userId } = decodedAccessToken as AccessToken;
|
||||
const context = makeContext(userId);
|
||||
|
||||
await this.licensesService.activateCardLicenseKey(
|
||||
context,
|
||||
userId,
|
||||
body.cardLicenseKey,
|
||||
);
|
||||
|
||||
@ -59,8 +59,14 @@ describe('LicensesService', () => {
|
||||
const userId = '0001';
|
||||
body.orderCount = 1000;
|
||||
body.poNumber = '1';
|
||||
const context = makeContext(`uuidv4`);
|
||||
expect(
|
||||
await service.licenseOrders(userId, body.poNumber, body.orderCount),
|
||||
await service.licenseOrders(
|
||||
context,
|
||||
userId,
|
||||
body.poNumber,
|
||||
body.orderCount,
|
||||
),
|
||||
).toEqual(undefined);
|
||||
});
|
||||
it('ユーザID取得できなかった場合、エラーとなる', async () => {
|
||||
@ -81,8 +87,9 @@ describe('LicensesService', () => {
|
||||
const userId = '';
|
||||
body.orderCount = 1000;
|
||||
body.poNumber = '1';
|
||||
const context = makeContext(`uuidv4`);
|
||||
await expect(
|
||||
service.licenseOrders(userId, body.poNumber, body.orderCount),
|
||||
service.licenseOrders(context, userId, body.poNumber, body.orderCount),
|
||||
).rejects.toEqual(
|
||||
new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
@ -108,8 +115,9 @@ describe('LicensesService', () => {
|
||||
const userId = '0001';
|
||||
body.orderCount = 1000;
|
||||
body.poNumber = '1';
|
||||
const context = makeContext(`uuidv4`);
|
||||
await expect(
|
||||
service.licenseOrders(userId, body.poNumber, body.orderCount),
|
||||
service.licenseOrders(context, userId, body.poNumber, body.orderCount),
|
||||
).rejects.toEqual(
|
||||
new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
@ -133,8 +141,9 @@ describe('LicensesService', () => {
|
||||
const userId = '0001';
|
||||
body.orderCount = 1000;
|
||||
body.poNumber = '1';
|
||||
const context = makeContext(`uuidv4`);
|
||||
await expect(
|
||||
service.licenseOrders(userId, body.poNumber, body.orderCount),
|
||||
service.licenseOrders(context, userId, body.poNumber, body.orderCount),
|
||||
).rejects.toEqual(
|
||||
new HttpException(
|
||||
makeErrorResponse('E010401'),
|
||||
@ -170,8 +179,9 @@ describe('LicensesService', () => {
|
||||
'AEJWRFFSWRQYQQJ6WVLV',
|
||||
],
|
||||
};
|
||||
const context = makeContext(`uuidv4`);
|
||||
expect(
|
||||
await service.issueCardLicenseKeys(userId, body.createCount),
|
||||
await service.issueCardLicenseKeys(context, userId, body.createCount),
|
||||
).toEqual(issueCardLicensesResponse);
|
||||
});
|
||||
it('カードライセンス発行に失敗した場合、エラーになる', async () => {
|
||||
@ -189,8 +199,9 @@ describe('LicensesService', () => {
|
||||
const body = new IssueCardLicensesRequest();
|
||||
const userId = '0001';
|
||||
body.createCount = 1000;
|
||||
const context = makeContext(`uuidv4`);
|
||||
await expect(
|
||||
service.issueCardLicenseKeys(userId, body.createCount),
|
||||
service.issueCardLicenseKeys(context, userId, body.createCount),
|
||||
).rejects.toEqual(
|
||||
new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
@ -212,8 +223,13 @@ describe('LicensesService', () => {
|
||||
const body = new ActivateCardLicensesRequest();
|
||||
const userId = '0001';
|
||||
body.cardLicenseKey = 'WZCETXC0Z9PQZ9GKRGGY';
|
||||
const context = makeContext(`uuidv4`);
|
||||
expect(
|
||||
await service.activateCardLicenseKey(userId, body.cardLicenseKey),
|
||||
await service.activateCardLicenseKey(
|
||||
context,
|
||||
userId,
|
||||
body.cardLicenseKey,
|
||||
),
|
||||
).toEqual(undefined);
|
||||
});
|
||||
it('カードライセンス取り込みに失敗した場合、エラーになる(DBエラー)', async () => {
|
||||
@ -231,8 +247,9 @@ describe('LicensesService', () => {
|
||||
const body = new ActivateCardLicensesRequest();
|
||||
const userId = '0001';
|
||||
body.cardLicenseKey = 'WZCETXC0Z9PQZ9GKRGGY';
|
||||
const context = makeContext(`uuidv4`);
|
||||
await expect(
|
||||
service.activateCardLicenseKey(userId, body.cardLicenseKey),
|
||||
service.activateCardLicenseKey(context, userId, body.cardLicenseKey),
|
||||
).rejects.toEqual(
|
||||
new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
@ -256,8 +273,9 @@ describe('LicensesService', () => {
|
||||
const body = new ActivateCardLicensesRequest();
|
||||
const userId = '0001';
|
||||
body.cardLicenseKey = 'WZCETXC0Z9PQZ9GKRGGY';
|
||||
const context = makeContext(`uuidv4`);
|
||||
await expect(
|
||||
service.activateCardLicenseKey(userId, body.cardLicenseKey),
|
||||
service.activateCardLicenseKey(context, userId, body.cardLicenseKey),
|
||||
).rejects.toEqual(
|
||||
new HttpException(makeErrorResponse('E010801'), HttpStatus.BAD_REQUEST),
|
||||
);
|
||||
@ -278,8 +296,9 @@ describe('LicensesService', () => {
|
||||
const body = new ActivateCardLicensesRequest();
|
||||
const userId = '0001';
|
||||
body.cardLicenseKey = 'WZCETXC0Z9PQZ9GKRGGY';
|
||||
const context = makeContext(`uuidv4`);
|
||||
await expect(
|
||||
service.activateCardLicenseKey(userId, body.cardLicenseKey),
|
||||
service.activateCardLicenseKey(context, userId, body.cardLicenseKey),
|
||||
).rejects.toEqual(
|
||||
new HttpException(makeErrorResponse('E010802'), HttpStatus.BAD_REQUEST),
|
||||
);
|
||||
@ -320,7 +339,8 @@ describe('DBテスト', () => {
|
||||
|
||||
const service = module.get<LicensesService>(LicensesService);
|
||||
const issueCount = 500;
|
||||
await service.issueCardLicenseKeys(externalId, issueCount);
|
||||
const context = makeContext(`uuidv4`);
|
||||
await service.issueCardLicenseKeys(context, externalId, issueCount);
|
||||
const dbSelectResult = await selectCardLicensesCount(source);
|
||||
expect(dbSelectResult.count).toEqual(issueCount);
|
||||
});
|
||||
@ -359,8 +379,9 @@ describe('DBテスト', () => {
|
||||
await createCardLicenseIssue(source, issueId);
|
||||
|
||||
const service = module.get<LicensesService>(LicensesService);
|
||||
const context = makeContext(`uuidv4`);
|
||||
|
||||
await service.activateCardLicenseKey(externalId, cardLicenseKey);
|
||||
await service.activateCardLicenseKey(context, externalId, cardLicenseKey);
|
||||
const dbSelectResultFromCardLicense = await selectCardLicense(
|
||||
source,
|
||||
cardLicenseKey,
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
import { HttpException, HttpStatus, Injectable, Logger } from '@nestjs/common';
|
||||
import { makeErrorResponse } from '../../common/error/makeErrorResponse';
|
||||
import { AccessToken } from '../../common/token';
|
||||
import { UsersRepositoryService } from '../../repositories/users/users.repository.service';
|
||||
import { AccountsRepositoryService } from '../../repositories/accounts/accounts.repository.service';
|
||||
import { AccountNotFoundError } from '../../repositories/accounts/errors/types';
|
||||
@ -13,6 +12,7 @@ import {
|
||||
import { LicensesRepositoryService } from '../../repositories/licenses/licenses.repository.service';
|
||||
import { UserNotFoundError } from '../../repositories/users/errors/types';
|
||||
import {
|
||||
DateWithZeroTime,
|
||||
GetAllocatableLicensesResponse,
|
||||
IssueCardLicensesResponse,
|
||||
} from './types/types';
|
||||
@ -33,12 +33,17 @@ export class LicensesService {
|
||||
* @param body
|
||||
*/
|
||||
async licenseOrders(
|
||||
context: Context,
|
||||
externalId: string,
|
||||
poNumber: string,
|
||||
orderCount: number,
|
||||
): Promise<void> {
|
||||
//アクセストークンからユーザーIDを取得する
|
||||
this.logger.log(`[IN] ${this.licenseOrders.name}`);
|
||||
this.logger.log(
|
||||
`[IN] [${context.getTrackingId()}] ${
|
||||
this.licenseOrders.name
|
||||
} | params: { externalId: ${externalId}, poNumber: ${poNumber}, orderCount: ${orderCount} };`,
|
||||
);
|
||||
let myAccountId: number;
|
||||
let parentAccountId: number | undefined;
|
||||
|
||||
@ -48,7 +53,7 @@ export class LicensesService {
|
||||
await this.usersRepository.findUserByExternalId(externalId)
|
||||
).account_id;
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
switch (e.constructor) {
|
||||
case UserNotFoundError:
|
||||
throw new HttpException(
|
||||
@ -73,7 +78,7 @@ export class LicensesService {
|
||||
throw new Error('parent account id is undefined');
|
||||
}
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
switch (e.constructor) {
|
||||
case AccountNotFoundError:
|
||||
throw new HttpException(
|
||||
@ -111,9 +116,15 @@ export class LicensesService {
|
||||
}
|
||||
}
|
||||
async issueCardLicenseKeys(
|
||||
context: Context,
|
||||
externalId: string,
|
||||
createCount: number,
|
||||
): Promise<IssueCardLicensesResponse> {
|
||||
this.logger.log(
|
||||
`[IN] [${context.getTrackingId()}] ${
|
||||
this.issueCardLicenseKeys.name
|
||||
} | params: { externalId: ${externalId}, createCount: ${createCount} };`,
|
||||
);
|
||||
const issueCardLicensesResponse = new IssueCardLicensesResponse();
|
||||
let myAccountId: number;
|
||||
|
||||
@ -123,7 +134,7 @@ export class LicensesService {
|
||||
await this.usersRepository.findUserByExternalId(externalId)
|
||||
).account_id;
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
switch (e.constructor) {
|
||||
case UserNotFoundError:
|
||||
throw new HttpException(
|
||||
@ -145,8 +156,10 @@ export class LicensesService {
|
||||
issueCardLicensesResponse.cardLicenseKeys = licenseKeys;
|
||||
return issueCardLicensesResponse;
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
this.logger.error('get cardlicensekeys failed');
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
this.logger.error(
|
||||
`[${context.getTrackingId()}] get cardlicensekeys failed`,
|
||||
);
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
@ -160,11 +173,14 @@ export class LicensesService {
|
||||
* @param cardLicenseKey
|
||||
*/
|
||||
async activateCardLicenseKey(
|
||||
context: Context,
|
||||
externalId: string,
|
||||
cardLicenseKey: string,
|
||||
): Promise<void> {
|
||||
this.logger.log(
|
||||
`[IN] ${this.activateCardLicenseKey.name}, argCardLicenseKey: ${cardLicenseKey}`,
|
||||
`[IN] [${context.getTrackingId()}] ${
|
||||
this.activateCardLicenseKey.name
|
||||
} | params: { externalId: ${externalId}, argCardLicenseKey: ${cardLicenseKey} };`,
|
||||
);
|
||||
let myAccountId: number;
|
||||
|
||||
@ -174,7 +190,7 @@ export class LicensesService {
|
||||
await this.usersRepository.findUserByExternalId(externalId)
|
||||
).account_id;
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
switch (e.constructor) {
|
||||
case UserNotFoundError:
|
||||
throw new HttpException(
|
||||
@ -196,8 +212,10 @@ export class LicensesService {
|
||||
cardLicenseKey,
|
||||
);
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
this.logger.error('cardLicenseKey activate failed');
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
this.logger.error(
|
||||
`[${context.getTrackingId()}] cardLicenseKey activate failed`,
|
||||
);
|
||||
|
||||
switch (e.constructor) {
|
||||
case LicenseNotExistError:
|
||||
@ -217,7 +235,9 @@ export class LicensesService {
|
||||
);
|
||||
}
|
||||
}
|
||||
this.logger.log(`[OUT] ${this.activateCardLicenseKey.name}`);
|
||||
this.logger.log(
|
||||
`[OUT] [${context.getTrackingId()}] ${this.activateCardLicenseKey.name}`,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -232,8 +252,9 @@ export class LicensesService {
|
||||
userId: string,
|
||||
): Promise<GetAllocatableLicensesResponse> {
|
||||
this.logger.log(
|
||||
`[IN] [${context.trackingId}] ${this.getAllocatableLicenses.name} | params: { ` +
|
||||
`userId: ${userId}, `,
|
||||
`[IN] [${context.getTrackingId()}] ${
|
||||
this.getAllocatableLicenses.name
|
||||
} | params: { ` + `userId: ${userId}, `,
|
||||
);
|
||||
// ユーザIDからアカウントIDを取得する
|
||||
try {
|
||||
@ -248,15 +269,19 @@ export class LicensesService {
|
||||
allocatableLicenses,
|
||||
};
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
this.logger.error('get allocatable lisences failed');
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
this.logger.error(
|
||||
`[${context.getTrackingId()}] get allocatable lisences failed`,
|
||||
);
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
} finally {
|
||||
this.logger.log(
|
||||
`[OUT] [${context.trackingId}] ${this.getAllocatableLicenses.name}`,
|
||||
`[OUT] [${context.getTrackingId()}] ${
|
||||
this.getAllocatableLicenses.name
|
||||
}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -273,7 +298,9 @@ export class LicensesService {
|
||||
poNumber: string,
|
||||
): Promise<void> {
|
||||
this.logger.log(
|
||||
`[IN] [${context.trackingId}] ${this.cancelOrder.name} | params: { ` +
|
||||
`[IN] [${context.getTrackingId()}] ${
|
||||
this.cancelOrder.name
|
||||
} | params: { ` +
|
||||
`externalId: ${externalId}, ` +
|
||||
`poNumber: ${poNumber}, };`,
|
||||
);
|
||||
@ -287,7 +314,7 @@ export class LicensesService {
|
||||
// 注文キャンセル処理
|
||||
await this.licensesRepository.cancelOrder(myAccountId, poNumber);
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
switch (e.constructor) {
|
||||
case UserNotFoundError:
|
||||
throw new HttpException(
|
||||
@ -306,7 +333,9 @@ export class LicensesService {
|
||||
);
|
||||
}
|
||||
} finally {
|
||||
this.logger.log(`[OUT] [${context.trackingId}] ${this.cancelOrder.name}`);
|
||||
this.logger.log(
|
||||
`[OUT] [${context.getTrackingId()}] ${this.cancelOrder.name}`,
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@ -26,7 +26,9 @@ export class NotificationService {
|
||||
pnsHandler: string,
|
||||
): Promise<void> {
|
||||
this.logger.log(
|
||||
`[IN] [${context.trackingId}] ${this.register.name} | params: { externalId: ${externalId}, pns: ${pns}, pnsHandler: ${pnsHandler} }`,
|
||||
`[IN] [${context.getTrackingId()}] ${
|
||||
this.register.name
|
||||
} | params: { externalId: ${externalId}, pns: ${pns}, pnsHandler: ${pnsHandler} }`,
|
||||
);
|
||||
|
||||
// ユーザIDからアカウントIDを取得する
|
||||
@ -34,7 +36,7 @@ export class NotificationService {
|
||||
try {
|
||||
userId = (await this.usersRepository.findUserByExternalId(externalId)).id;
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
switch (e.constructor) {
|
||||
case UserNotFoundError:
|
||||
throw new HttpException(
|
||||
@ -53,7 +55,7 @@ export class NotificationService {
|
||||
// TODO: 登録毎に新規登録する想定でUUIDを付与している
|
||||
// もしデバイスごとに登録を上書きするようであればUUID部分にデバイス識別子を設定
|
||||
const installationId = `${pns}_${userId}_${uuidv4()}`;
|
||||
this.logger.log(installationId);
|
||||
this.logger.log(`[${context.getTrackingId()}] ${installationId}`);
|
||||
|
||||
await this.notificationhubService.register(
|
||||
context,
|
||||
@ -63,13 +65,15 @@ export class NotificationService {
|
||||
installationId,
|
||||
);
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
} finally {
|
||||
this.logger.log(`[OUT] [${context.trackingId}] ${this.register.name}`);
|
||||
this.logger.log(
|
||||
`[OUT] [${context.getTrackingId()}] ${this.register.name}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -318,7 +318,7 @@ export class TasksController {
|
||||
HttpStatus.UNAUTHORIZED,
|
||||
);
|
||||
}
|
||||
const { userId, role } = decodedAccessToken as AccessToken;
|
||||
const { userId } = decodedAccessToken as AccessToken;
|
||||
|
||||
const context = makeContext(userId);
|
||||
|
||||
|
||||
@ -35,7 +35,6 @@ import {
|
||||
} from '../workflows/test/utility';
|
||||
import { createTemplateFile } from '../templates/test/utility';
|
||||
import { NotificationhubService } from '../../gateways/notificationhub/notificationhub.service';
|
||||
import { makeNotifyMessage } from '../../common/notify/makeNotifyMessage';
|
||||
import { Roles } from '../../common/types/role';
|
||||
|
||||
describe('TasksService', () => {
|
||||
@ -835,6 +834,9 @@ describe('changeCheckoutPermission', () => {
|
||||
await createCheckoutPermissions(source, taskId, typistUserId_1);
|
||||
await createCheckoutPermissions(source, taskId, undefined, userGroupId);
|
||||
const service = module.get<TasksService>(TasksService);
|
||||
const NotificationHubService = module.get<NotificationhubService>(
|
||||
NotificationhubService,
|
||||
);
|
||||
await service.changeCheckoutPermission(
|
||||
makeContext('trackingId'),
|
||||
1,
|
||||
@ -850,6 +852,18 @@ describe('changeCheckoutPermission', () => {
|
||||
user_id: typistUserId_2,
|
||||
user_group_id: null,
|
||||
});
|
||||
const resultTask = await getTask(source, taskId);
|
||||
// 通知処理が想定通りの引数で呼ばれているか確認
|
||||
expect(NotificationHubService.notify).toHaveBeenCalledWith(
|
||||
makeContext('trackingId'),
|
||||
[`user_${typistUserId_2}`],
|
||||
{
|
||||
authorId: 'MY_AUTHOR_ID',
|
||||
filename: 'x',
|
||||
priority: 'High',
|
||||
uploadedAt: resultTask?.file?.uploaded_at.toISOString(),
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
it('タスクのチェックアウト権限を変更できる。(グループ指定)', async () => {
|
||||
@ -903,6 +917,9 @@ describe('changeCheckoutPermission', () => {
|
||||
await createCheckoutPermissions(source, taskId, typistUserId_1);
|
||||
await createCheckoutPermissions(source, taskId, undefined, userGroupId_1);
|
||||
const service = module.get<TasksService>(TasksService);
|
||||
const NotificationHubService = module.get<NotificationhubService>(
|
||||
NotificationhubService,
|
||||
);
|
||||
await service.changeCheckoutPermission(
|
||||
makeContext('trackingId'),
|
||||
1,
|
||||
@ -918,6 +935,19 @@ describe('changeCheckoutPermission', () => {
|
||||
user_id: null,
|
||||
user_group_id: userGroupId_2,
|
||||
});
|
||||
|
||||
const resultTask = await getTask(source, taskId);
|
||||
// 通知処理が想定通りの引数で呼ばれているか確認
|
||||
expect(NotificationHubService.notify).toHaveBeenCalledWith(
|
||||
makeContext('trackingId'),
|
||||
[`user_${typistUserId_2}`],
|
||||
{
|
||||
authorId: 'MY_AUTHOR_ID',
|
||||
filename: 'x',
|
||||
priority: 'High',
|
||||
uploadedAt: resultTask?.file?.uploaded_at.toISOString(),
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
it('タスクのチェックアウト権限を変更できる。(チェックアウト権限を外す)', async () => {
|
||||
@ -1012,17 +1042,89 @@ describe('changeCheckoutPermission', () => {
|
||||
await createCheckoutPermissions(source, taskId, undefined, userGroupId);
|
||||
const service = module.get<TasksService>(TasksService);
|
||||
|
||||
await expect(
|
||||
service.changeCheckoutPermission(
|
||||
try {
|
||||
await service.changeCheckoutPermission(
|
||||
makeContext('trackingId'),
|
||||
1,
|
||||
[{ typistName: 'not-exist-user', typistUserId: 999 }],
|
||||
'author-user-external-id',
|
||||
['admin'],
|
||||
),
|
||||
).rejects.toEqual(
|
||||
new HttpException(makeErrorResponse('E010204'), HttpStatus.BAD_REQUEST),
|
||||
);
|
||||
fail();
|
||||
} catch (e) {
|
||||
if (e instanceof HttpException) {
|
||||
expect(e.getStatus()).toEqual(HttpStatus.BAD_REQUEST);
|
||||
expect(e.getResponse()).toEqual(makeErrorResponse('E010204'));
|
||||
} else {
|
||||
fail();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it('ユーザーがメール認証されていない場合、タスクのチェックアウト権限を変更できない', async () => {
|
||||
if (!source) fail();
|
||||
const notificationhubServiceMockValue =
|
||||
makeDefaultNotificationhubServiceMockValue();
|
||||
const module = await makeTaskTestingModuleWithNotificaiton(
|
||||
source,
|
||||
notificationhubServiceMockValue,
|
||||
);
|
||||
if (!module) fail();
|
||||
const { id: accountId } = await makeTestSimpleAccount(source);
|
||||
const { id: typistUserId_1 } = await makeTestUser(source, {
|
||||
account_id: accountId,
|
||||
external_id: 'typist-user-external-id_1',
|
||||
role: 'typist',
|
||||
});
|
||||
const { id: typistUserId_2 } = await makeTestUser(source, {
|
||||
account_id: accountId,
|
||||
external_id: 'typist-user-external-id_2',
|
||||
role: 'typist',
|
||||
email_verified: false,
|
||||
});
|
||||
const { id: authorUserId } = await makeTestUser(source, {
|
||||
account_id: accountId,
|
||||
external_id: 'author-user-external-id',
|
||||
role: 'author',
|
||||
author_id: 'MY_AUTHOR_ID',
|
||||
});
|
||||
const { taskId } = await createTask(
|
||||
source,
|
||||
accountId,
|
||||
authorUserId,
|
||||
'MY_AUTHOR_ID',
|
||||
'',
|
||||
'01',
|
||||
'00000001',
|
||||
'Uploaded',
|
||||
);
|
||||
const { userGroupId } = await createUserGroup(
|
||||
source,
|
||||
accountId,
|
||||
'USER_GROUP_A',
|
||||
[typistUserId_1],
|
||||
);
|
||||
await createCheckoutPermissions(source, taskId, typistUserId_1);
|
||||
await createCheckoutPermissions(source, taskId, undefined, userGroupId);
|
||||
const service = module.get<TasksService>(TasksService);
|
||||
|
||||
try {
|
||||
await service.changeCheckoutPermission(
|
||||
makeContext('trackingId'),
|
||||
1,
|
||||
[{ typistName: 'not-verified-user', typistUserId: typistUserId_2 }],
|
||||
'author-user-external-id',
|
||||
['admin'],
|
||||
);
|
||||
fail();
|
||||
} catch (e) {
|
||||
if (e instanceof HttpException) {
|
||||
expect(e.getStatus()).toEqual(HttpStatus.BAD_REQUEST);
|
||||
expect(e.getResponse()).toEqual(makeErrorResponse('E010204'));
|
||||
} else {
|
||||
fail();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it('ユーザーグループが存在しない場合、タスクのチェックアウト権限を変更できない', async () => {
|
||||
@ -1066,17 +1168,23 @@ describe('changeCheckoutPermission', () => {
|
||||
await createCheckoutPermissions(source, taskId, undefined, userGroupId);
|
||||
const service = module.get<TasksService>(TasksService);
|
||||
|
||||
await expect(
|
||||
service.changeCheckoutPermission(
|
||||
try {
|
||||
await service.changeCheckoutPermission(
|
||||
makeContext('trackingId'),
|
||||
1,
|
||||
[{ typistName: 'not-exist-user-group', typistGroupId: 999 }],
|
||||
'author-user-external-id',
|
||||
['admin'],
|
||||
),
|
||||
).rejects.toEqual(
|
||||
new HttpException(makeErrorResponse('E010204'), HttpStatus.BAD_REQUEST),
|
||||
);
|
||||
fail();
|
||||
} catch (e) {
|
||||
if (e instanceof HttpException) {
|
||||
expect(e.getStatus()).toEqual(HttpStatus.BAD_REQUEST);
|
||||
expect(e.getResponse()).toEqual(makeErrorResponse('E010204'));
|
||||
} else {
|
||||
fail();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it('タスクが存在しない場合、タスクのチェックアウト権限を変更できない', async () => {
|
||||
@ -1102,17 +1210,23 @@ describe('changeCheckoutPermission', () => {
|
||||
});
|
||||
const service = module.get<TasksService>(TasksService);
|
||||
|
||||
await expect(
|
||||
service.changeCheckoutPermission(
|
||||
try {
|
||||
await service.changeCheckoutPermission(
|
||||
makeContext('trackingId'),
|
||||
1,
|
||||
[{ typistName: 'typist-user', typistUserId: typistUserId }],
|
||||
'author-user-external-id',
|
||||
['admin'],
|
||||
),
|
||||
).rejects.toEqual(
|
||||
new HttpException(makeErrorResponse('E010601'), HttpStatus.BAD_REQUEST),
|
||||
);
|
||||
fail();
|
||||
} catch (e) {
|
||||
if (e instanceof HttpException) {
|
||||
expect(e.getStatus()).toEqual(HttpStatus.BAD_REQUEST);
|
||||
expect(e.getResponse()).toEqual(makeErrorResponse('E010601'));
|
||||
} else {
|
||||
fail();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it('タスクのステータスがUploadedでない場合、タスクのチェックアウト権限を変更できない', async () => {
|
||||
@ -1148,17 +1262,23 @@ describe('changeCheckoutPermission', () => {
|
||||
);
|
||||
const service = module.get<TasksService>(TasksService);
|
||||
|
||||
await expect(
|
||||
service.changeCheckoutPermission(
|
||||
try {
|
||||
await service.changeCheckoutPermission(
|
||||
makeContext('trackingId'),
|
||||
1,
|
||||
[{ typistName: 'typist-user', typistUserId: typistUserId }],
|
||||
'author-user-external-id',
|
||||
['admin'],
|
||||
),
|
||||
).rejects.toEqual(
|
||||
new HttpException(makeErrorResponse('E010601'), HttpStatus.BAD_REQUEST),
|
||||
);
|
||||
fail();
|
||||
} catch (e) {
|
||||
if (e instanceof HttpException) {
|
||||
expect(e.getStatus()).toEqual(HttpStatus.BAD_REQUEST);
|
||||
expect(e.getResponse()).toEqual(makeErrorResponse('E010601'));
|
||||
} else {
|
||||
fail();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it('ユーザーのRoleがAuthorでタスクのAuthorIDと自身のAuthorIDが一致しない場合、タスクのチェックアウト権限を変更できない', async () => {
|
||||
@ -1194,17 +1314,23 @@ describe('changeCheckoutPermission', () => {
|
||||
);
|
||||
const service = module.get<TasksService>(TasksService);
|
||||
|
||||
await expect(
|
||||
service.changeCheckoutPermission(
|
||||
try {
|
||||
await service.changeCheckoutPermission(
|
||||
makeContext('trackingId'),
|
||||
1,
|
||||
[{ typistName: 'typist-user', typistUserId: typistUserId }],
|
||||
'author-user-external-id',
|
||||
['author'],
|
||||
),
|
||||
).rejects.toEqual(
|
||||
new HttpException(makeErrorResponse('E010601'), HttpStatus.BAD_REQUEST),
|
||||
);
|
||||
fail();
|
||||
} catch (e) {
|
||||
if (e instanceof HttpException) {
|
||||
expect(e.getStatus()).toEqual(HttpStatus.BAD_REQUEST);
|
||||
expect(e.getResponse()).toEqual(makeErrorResponse('E010601'));
|
||||
} else {
|
||||
fail();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it('通知に失敗した場合、エラーとなる', async () => {
|
||||
@ -1254,20 +1380,23 @@ describe('changeCheckoutPermission', () => {
|
||||
await createCheckoutPermissions(source, taskId, undefined, userGroupId);
|
||||
const service = module.get<TasksService>(TasksService);
|
||||
|
||||
await expect(
|
||||
service.changeCheckoutPermission(
|
||||
try {
|
||||
await service.changeCheckoutPermission(
|
||||
makeContext('trackingId'),
|
||||
1,
|
||||
[{ typistName: 'typist-user-2', typistUserId: typistUserId_2 }],
|
||||
'author-user-external-id',
|
||||
['admin'],
|
||||
),
|
||||
).rejects.toEqual(
|
||||
new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
),
|
||||
);
|
||||
fail();
|
||||
} catch (e) {
|
||||
if (e instanceof HttpException) {
|
||||
expect(e.getStatus()).toEqual(HttpStatus.INTERNAL_SERVER_ERROR);
|
||||
expect(e.getResponse()).toEqual(makeErrorResponse('E009999'));
|
||||
} else {
|
||||
fail();
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@ -1292,12 +1421,7 @@ describe('checkout', () => {
|
||||
|
||||
it('ユーザーのRoleがTypistで、タスクのチェックアウト権限が個人指定である時、タスクをチェックアウトできる', async () => {
|
||||
if (!source) fail();
|
||||
const notificationhubServiceMockValue =
|
||||
makeDefaultNotificationhubServiceMockValue();
|
||||
const module = await makeTaskTestingModuleWithNotificaiton(
|
||||
source,
|
||||
notificationhubServiceMockValue,
|
||||
);
|
||||
const module = await makeTestingModule(source);
|
||||
if (!module) fail();
|
||||
const { id: accountId } = await makeTestSimpleAccount(source);
|
||||
const { id: typistUserId } = await makeTestUser(source, {
|
||||
@ -1357,12 +1481,7 @@ describe('checkout', () => {
|
||||
|
||||
it('ユーザーのRoleがTypistで、タスクのチェックアウト権限がグループ指定である時、タスクをチェックアウトできる', async () => {
|
||||
if (!source) fail();
|
||||
const notificationhubServiceMockValue =
|
||||
makeDefaultNotificationhubServiceMockValue();
|
||||
const module = await makeTaskTestingModuleWithNotificaiton(
|
||||
source,
|
||||
notificationhubServiceMockValue,
|
||||
);
|
||||
const module = await makeTestingModule(source);
|
||||
if (!module) fail();
|
||||
const { id: accountId } = await makeTestSimpleAccount(source);
|
||||
const { id: typistUserId } = await makeTestUser(source, {
|
||||
@ -1422,12 +1541,7 @@ describe('checkout', () => {
|
||||
|
||||
it('ユーザーのRoleがTypistで、タスクのステータスがPendingである時、タスクをチェックアウトできる', async () => {
|
||||
if (!source) fail();
|
||||
const notificationhubServiceMockValue =
|
||||
makeDefaultNotificationhubServiceMockValue();
|
||||
const module = await makeTaskTestingModuleWithNotificaiton(
|
||||
source,
|
||||
notificationhubServiceMockValue,
|
||||
);
|
||||
const module = await makeTestingModule(source);
|
||||
if (!module) fail();
|
||||
const { id: accountId } = await makeTestSimpleAccount(source);
|
||||
const { id: typistUserId } = await makeTestUser(source, {
|
||||
@ -1481,12 +1595,7 @@ describe('checkout', () => {
|
||||
|
||||
it('ユーザーのRoleがTypistで、対象のタスクのStatus[Uploaded,Inprogress,Pending]以外の時、タスクをチェックアウトできない', async () => {
|
||||
if (!source) fail();
|
||||
const notificationhubServiceMockValue =
|
||||
makeDefaultNotificationhubServiceMockValue();
|
||||
const module = await makeTaskTestingModuleWithNotificaiton(
|
||||
source,
|
||||
notificationhubServiceMockValue,
|
||||
);
|
||||
const module = await makeTestingModule(source);
|
||||
if (!module) fail();
|
||||
const { id: accountId } = await makeTestSimpleAccount(source);
|
||||
await makeTestUser(source, {
|
||||
@ -1513,26 +1622,27 @@ describe('checkout', () => {
|
||||
);
|
||||
|
||||
const service = module.get<TasksService>(TasksService);
|
||||
await expect(
|
||||
service.checkout(
|
||||
try {
|
||||
await service.checkout(
|
||||
makeContext('trackingId'),
|
||||
1,
|
||||
['typist'],
|
||||
'typist-user-external-id',
|
||||
),
|
||||
).rejects.toEqual(
|
||||
new HttpException(makeErrorResponse('E010601'), HttpStatus.BAD_REQUEST),
|
||||
);
|
||||
);
|
||||
fail();
|
||||
} catch (e) {
|
||||
if (e instanceof HttpException) {
|
||||
expect(e.getStatus()).toBe(HttpStatus.BAD_REQUEST);
|
||||
expect(e.getResponse()).toEqual(makeErrorResponse('E010601'));
|
||||
} else {
|
||||
fail();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it('ユーザーのRoleがTypistで、チェックアウト権限が存在しない時、タスクをチェックアウトできない', async () => {
|
||||
if (!source) fail();
|
||||
const notificationhubServiceMockValue =
|
||||
makeDefaultNotificationhubServiceMockValue();
|
||||
const module = await makeTaskTestingModuleWithNotificaiton(
|
||||
source,
|
||||
notificationhubServiceMockValue,
|
||||
);
|
||||
const module = await makeTestingModule(source);
|
||||
if (!module) fail();
|
||||
const { id: accountId } = await makeTestSimpleAccount(source);
|
||||
await makeTestUser(source, {
|
||||
@ -1559,26 +1669,153 @@ describe('checkout', () => {
|
||||
);
|
||||
|
||||
const service = module.get<TasksService>(TasksService);
|
||||
await expect(
|
||||
service.checkout(
|
||||
try {
|
||||
await service.checkout(
|
||||
makeContext('trackingId'),
|
||||
1,
|
||||
['typist'],
|
||||
'typist-user-external-id',
|
||||
),
|
||||
).rejects.toEqual(
|
||||
new HttpException(makeErrorResponse('E010602'), HttpStatus.BAD_REQUEST),
|
||||
);
|
||||
fail();
|
||||
} catch (e) {
|
||||
if (e instanceof HttpException) {
|
||||
expect(e.getStatus()).toBe(HttpStatus.BAD_REQUEST);
|
||||
expect(e.getResponse()).toEqual(makeErrorResponse('E010602'));
|
||||
} else {
|
||||
fail();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it('ユーザーのRoleがTypistで、既にチェックアウト中のタスク(InProgress)がある時、タスクをチェックアウトできない', async () => {
|
||||
if (!source) fail();
|
||||
const module = await makeTestingModule(source);
|
||||
if (!module) fail();
|
||||
const { id: accountId } = await makeTestSimpleAccount(source);
|
||||
const { id: typistUserId } = await makeTestUser(source, {
|
||||
account_id: accountId,
|
||||
external_id: 'typist-user-external-id',
|
||||
role: 'typist',
|
||||
});
|
||||
const { id: authorUserId } = await makeTestUser(source, {
|
||||
account_id: accountId,
|
||||
external_id: 'author-user-external-id',
|
||||
role: 'author',
|
||||
author_id: 'MY_AUTHOR_ID',
|
||||
});
|
||||
|
||||
await createTask(
|
||||
source,
|
||||
accountId,
|
||||
authorUserId,
|
||||
'MY_AUTHOR_ID',
|
||||
'',
|
||||
'01',
|
||||
'00000001',
|
||||
TASK_STATUS.IN_PROGRESS,
|
||||
typistUserId,
|
||||
);
|
||||
const { taskId, audioFileId } = await createTask(
|
||||
source,
|
||||
accountId,
|
||||
authorUserId,
|
||||
'MY_AUTHOR_ID',
|
||||
'',
|
||||
'01',
|
||||
'00000002',
|
||||
TASK_STATUS.UPLOADED,
|
||||
);
|
||||
|
||||
await createCheckoutPermissions(source, taskId, typistUserId);
|
||||
|
||||
const service = module.get<TasksService>(TasksService);
|
||||
|
||||
try {
|
||||
await service.checkout(
|
||||
makeContext('trackingId'),
|
||||
audioFileId,
|
||||
['typist'],
|
||||
'typist-user-external-id',
|
||||
);
|
||||
fail();
|
||||
} catch (e) {
|
||||
if (e instanceof HttpException) {
|
||||
expect(e.getStatus()).toBe(HttpStatus.BAD_REQUEST);
|
||||
expect(e.getResponse()).toEqual(makeErrorResponse('E010601'));
|
||||
} else {
|
||||
fail();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it('ユーザーのRoleがTypistで、別ユーザーによってチェックアウト中のタスク(InProgress)がある時、タスクをチェックアウトできる', async () => {
|
||||
if (!source) fail();
|
||||
const module = await makeTestingModule(source);
|
||||
if (!module) fail();
|
||||
const { id: accountId } = await makeTestSimpleAccount(source);
|
||||
const { id: typistUserId1 } = await makeTestUser(source, {
|
||||
account_id: accountId,
|
||||
external_id: 'typist-user-external-id1',
|
||||
role: 'typist',
|
||||
});
|
||||
const { id: typistUserId2 } = await makeTestUser(source, {
|
||||
account_id: accountId,
|
||||
external_id: 'typist-user-external-id2',
|
||||
role: 'typist',
|
||||
});
|
||||
const { id: authorUserId } = await makeTestUser(source, {
|
||||
account_id: accountId,
|
||||
external_id: 'author-user-external-id',
|
||||
role: 'author',
|
||||
author_id: 'MY_AUTHOR_ID',
|
||||
});
|
||||
|
||||
await createTask(
|
||||
source,
|
||||
accountId,
|
||||
authorUserId,
|
||||
'MY_AUTHOR_ID',
|
||||
'',
|
||||
'01',
|
||||
'00000001',
|
||||
TASK_STATUS.IN_PROGRESS,
|
||||
typistUserId1,
|
||||
);
|
||||
const { taskId } = await createTask(
|
||||
source,
|
||||
accountId,
|
||||
authorUserId,
|
||||
'MY_AUTHOR_ID',
|
||||
'',
|
||||
'01',
|
||||
'00000002',
|
||||
TASK_STATUS.UPLOADED,
|
||||
);
|
||||
|
||||
await createCheckoutPermissions(source, taskId, typistUserId2);
|
||||
|
||||
const service = module.get<TasksService>(TasksService);
|
||||
|
||||
await service.checkout(
|
||||
makeContext('trackingId'),
|
||||
2,
|
||||
['typist'],
|
||||
'typist-user-external-id2',
|
||||
);
|
||||
|
||||
const resultTask = await getTask(source, taskId);
|
||||
const permisions = await getCheckoutPermissions(source, taskId);
|
||||
|
||||
expect(resultTask?.status).toEqual(TASK_STATUS.IN_PROGRESS);
|
||||
expect(resultTask?.typist_user_id).toEqual(typistUserId2);
|
||||
expect(permisions.length).toBe(1);
|
||||
expect(permisions[0].task_id).toBe(taskId);
|
||||
expect(permisions[0].user_id).toBe(typistUserId2);
|
||||
});
|
||||
|
||||
it('ユーザーのRoleがAuthorで、アップロードした音声ファイルに紐づいたタスクをチェックアウトできる(Uploaded)', async () => {
|
||||
if (!source) fail();
|
||||
const notificationhubServiceMockValue =
|
||||
makeDefaultNotificationhubServiceMockValue();
|
||||
const module = await makeTaskTestingModuleWithNotificaiton(
|
||||
source,
|
||||
notificationhubServiceMockValue,
|
||||
);
|
||||
const module = await makeTestingModule(source);
|
||||
if (!module) fail();
|
||||
const { id: accountId } = await makeTestSimpleAccount(source);
|
||||
const { id: authorUserId } = await makeTestUser(source, {
|
||||
@ -1611,12 +1848,7 @@ describe('checkout', () => {
|
||||
|
||||
it('ユーザーのRoleがAuthorで、アップロードした音声ファイルに紐づいたタスクをチェックアウトできる(Finished)', async () => {
|
||||
if (!source) fail();
|
||||
const notificationhubServiceMockValue =
|
||||
makeDefaultNotificationhubServiceMockValue();
|
||||
const module = await makeTaskTestingModuleWithNotificaiton(
|
||||
source,
|
||||
notificationhubServiceMockValue,
|
||||
);
|
||||
const module = await makeTestingModule(source);
|
||||
if (!module) fail();
|
||||
const { id: accountId } = await makeTestSimpleAccount(source);
|
||||
const { id: authorUserId } = await makeTestUser(source, {
|
||||
@ -1637,6 +1869,7 @@ describe('checkout', () => {
|
||||
);
|
||||
|
||||
const service = module.get<TasksService>(TasksService);
|
||||
|
||||
expect(
|
||||
await service.checkout(
|
||||
makeContext('trackingId'),
|
||||
@ -1649,12 +1882,7 @@ describe('checkout', () => {
|
||||
|
||||
it('ユーザーのRoleがAuthorで、アップロードした音声ファイルに紐づいたタスクが存在しない場合、タスクをチェックアウトできない', async () => {
|
||||
if (!source) fail();
|
||||
const notificationhubServiceMockValue =
|
||||
makeDefaultNotificationhubServiceMockValue();
|
||||
const module = await makeTaskTestingModuleWithNotificaiton(
|
||||
source,
|
||||
notificationhubServiceMockValue,
|
||||
);
|
||||
const module = await makeTestingModule(source);
|
||||
if (!module) fail();
|
||||
const { id: accountId } = await makeTestSimpleAccount(source);
|
||||
await makeTestUser(source, {
|
||||
@ -1665,26 +1893,27 @@ describe('checkout', () => {
|
||||
});
|
||||
|
||||
const service = module.get<TasksService>(TasksService);
|
||||
await expect(
|
||||
service.checkout(
|
||||
try {
|
||||
await service.checkout(
|
||||
makeContext('trackingId'),
|
||||
1,
|
||||
['author'],
|
||||
'author-user-external-id',
|
||||
),
|
||||
).rejects.toEqual(
|
||||
new HttpException(makeErrorResponse('E010601'), HttpStatus.BAD_REQUEST),
|
||||
);
|
||||
fail();
|
||||
} catch (e) {
|
||||
if (e instanceof HttpException) {
|
||||
expect(e.getStatus()).toBe(HttpStatus.NOT_FOUND);
|
||||
expect(e.getResponse()).toEqual(makeErrorResponse('E010601'));
|
||||
} else {
|
||||
fail();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it('ユーザーのRoleがAuthorで、音声ファイルに紐づいたタスクでユーザーと一致するAuthorIDでない場合、タスクをチェックアウトできない', async () => {
|
||||
if (!source) fail();
|
||||
const notificationhubServiceMockValue =
|
||||
makeDefaultNotificationhubServiceMockValue();
|
||||
const module = await makeTaskTestingModuleWithNotificaiton(
|
||||
source,
|
||||
notificationhubServiceMockValue,
|
||||
);
|
||||
const module = await makeTestingModule(source);
|
||||
if (!module) fail();
|
||||
const { id: accountId } = await makeTestSimpleAccount(source);
|
||||
const { id: authorUserId } = await makeTestUser(source, {
|
||||
@ -1705,26 +1934,27 @@ describe('checkout', () => {
|
||||
);
|
||||
|
||||
const service = module.get<TasksService>(TasksService);
|
||||
await expect(
|
||||
service.checkout(
|
||||
try {
|
||||
await service.checkout(
|
||||
makeContext('trackingId'),
|
||||
1,
|
||||
['author'],
|
||||
'author-user-external-id',
|
||||
),
|
||||
).rejects.toEqual(
|
||||
new HttpException(makeErrorResponse('E010602'), HttpStatus.BAD_REQUEST),
|
||||
);
|
||||
);
|
||||
fail();
|
||||
} catch (e) {
|
||||
if (e instanceof HttpException) {
|
||||
expect(e.getStatus()).toBe(HttpStatus.BAD_REQUEST);
|
||||
expect(e.getResponse()).toEqual(makeErrorResponse('E010602'));
|
||||
} else {
|
||||
fail();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it('ユーザーのRoleに[Typist,author]が設定されていない時、タスクをチェックアウトできない', async () => {
|
||||
if (!source) fail();
|
||||
const notificationhubServiceMockValue =
|
||||
makeDefaultNotificationhubServiceMockValue();
|
||||
const module = await makeTaskTestingModuleWithNotificaiton(
|
||||
source,
|
||||
notificationhubServiceMockValue,
|
||||
);
|
||||
const module = await makeTestingModule(source);
|
||||
if (!module) fail();
|
||||
const { id: accountId } = await makeTestSimpleAccount(source);
|
||||
await makeTestUser(source, {
|
||||
@ -1735,16 +1965,22 @@ describe('checkout', () => {
|
||||
});
|
||||
|
||||
const service = module.get<TasksService>(TasksService);
|
||||
await expect(
|
||||
service.checkout(
|
||||
try {
|
||||
await service.checkout(
|
||||
makeContext('trackingId'),
|
||||
1,
|
||||
['none'],
|
||||
'none-user-external-id',
|
||||
),
|
||||
).rejects.toEqual(
|
||||
new HttpException(makeErrorResponse('E010602'), HttpStatus.BAD_REQUEST),
|
||||
);
|
||||
);
|
||||
fail();
|
||||
} catch (e) {
|
||||
if (e instanceof HttpException) {
|
||||
expect(e.getStatus()).toBe(HttpStatus.BAD_REQUEST);
|
||||
expect(e.getResponse()).toEqual(makeErrorResponse('E010602'));
|
||||
} else {
|
||||
fail();
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@ -2556,9 +2792,14 @@ describe('cancel', () => {
|
||||
expect(NotificationHubService.notify).toHaveBeenCalledWith(
|
||||
makeContext('trackingId'),
|
||||
[`user_${typistUserId}`],
|
||||
makeNotifyMessage('M000101'),
|
||||
{
|
||||
authorId: 'AUTHOR_ID',
|
||||
filename: 'x',
|
||||
priority: 'High',
|
||||
uploadedAt: resultTask?.file?.uploaded_at.toISOString(),
|
||||
},
|
||||
);
|
||||
}, 1000000);
|
||||
});
|
||||
|
||||
it('API実行者のRoleがAdminの場合、自身が文字起こし実行中のタスクをキャンセルし、そのタスクの自動ルーティングを行う(API実行者のAuthorIDと音声ファイルに紐づくWorkType)', async () => {
|
||||
if (!source) fail();
|
||||
@ -2661,7 +2902,12 @@ describe('cancel', () => {
|
||||
expect(NotificationHubService.notify).toHaveBeenCalledWith(
|
||||
makeContext('trackingId'),
|
||||
[`user_${autoRoutingTypistUserId}`],
|
||||
makeNotifyMessage('M000101'),
|
||||
{
|
||||
authorId: 'AUTHOR_ID',
|
||||
filename: 'x',
|
||||
priority: 'High',
|
||||
uploadedAt: resultTask?.file?.uploaded_at.toISOString(),
|
||||
},
|
||||
);
|
||||
});
|
||||
it('API実行者のRoleがTypistの場合、自身が文字起こし実行中のタスクをキャンセルするが、一致するワークフローがない場合は自動ルーティングを行うことができない', async () => {
|
||||
|
||||
@ -19,6 +19,7 @@ import { AdB2cUser } from '../../gateways/adb2c/types/types';
|
||||
import { CheckoutPermission } from '../../repositories/checkout_permissions/entity/checkout_permission.entity';
|
||||
import {
|
||||
AccountNotMatchError,
|
||||
AlreadyHasInProgressTaskError,
|
||||
CheckoutPermissionNotFoundError,
|
||||
StatusNotMatchError,
|
||||
TaskAuthorIdNotMatchError,
|
||||
@ -31,7 +32,6 @@ import { Roles } from '../../common/types/role';
|
||||
import { InvalidRoleError } from './errors/types';
|
||||
import { NotificationhubService } from '../../gateways/notificationhub/notificationhub.service';
|
||||
import { UserGroupsRepositoryService } from '../../repositories/user_groups/user_groups.repository.service';
|
||||
import { makeNotifyMessage } from '../../common/notify/makeNotifyMessage';
|
||||
import { Context } from '../../common/log';
|
||||
import { User } from '../../repositories/users/entity/user.entity';
|
||||
|
||||
@ -57,7 +57,14 @@ export class TasksService {
|
||||
direction?: SortDirection,
|
||||
): Promise<{ tasks: Task[]; total: number }> {
|
||||
this.logger.log(
|
||||
`[IN] [${context.trackingId}] ${this.getTasks.name} | params: { offset: ${offset}, limit: ${limit}, status: ${status}, paramName: ${paramName}, direction: ${direction} };`,
|
||||
`[IN] [${context.getTrackingId()}] ${this.getTasks.name} | params: { ` +
|
||||
`userId: ${userId}, ` +
|
||||
`roles: ${roles}, ` +
|
||||
`offset: ${offset},` +
|
||||
`limit: ${limit}, ` +
|
||||
`status: ${status}, ` +
|
||||
`paramName: ${paramName}, ` +
|
||||
`direction: ${direction} };`,
|
||||
);
|
||||
|
||||
// パラメータが省略された場合のデフォルト値: 保存するソート条件の値の初期値と揃える
|
||||
@ -141,7 +148,7 @@ export class TasksService {
|
||||
|
||||
throw new Error(`invalid roles: ${roles.join(',')}`);
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
if (e instanceof Error) {
|
||||
if (e.constructor === Adb2cTooManyRequestsError) {
|
||||
throw new HttpException(
|
||||
@ -155,7 +162,9 @@ export class TasksService {
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
} finally {
|
||||
this.logger.log(`[OUT] [${context.trackingId}] ${this.getTasks.name}`);
|
||||
this.logger.log(
|
||||
`[OUT] [${context.getTrackingId()}] ${this.getTasks.name}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -172,7 +181,9 @@ export class TasksService {
|
||||
fileId: number,
|
||||
): Promise<number | undefined> {
|
||||
this.logger.log(
|
||||
`[IN] [${context.trackingId}] ${this.getNextTask.name} | params: { externalId: ${externalId}, fileId: ${fileId} };`,
|
||||
`[IN] [${context.getTrackingId()}] ${
|
||||
this.getNextTask.name
|
||||
} | params: { externalId: ${externalId}, fileId: ${fileId} };`,
|
||||
);
|
||||
|
||||
try {
|
||||
@ -211,7 +222,7 @@ export class TasksService {
|
||||
? undefined
|
||||
: nextTask.audio_file_id;
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
if (e instanceof Error) {
|
||||
switch (e.constructor) {
|
||||
case TasksNotFoundError:
|
||||
@ -231,7 +242,9 @@ export class TasksService {
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
} finally {
|
||||
this.logger.log(`[OUT] [${context.trackingId}] ${this.getNextTask.name}`);
|
||||
this.logger.log(
|
||||
`[OUT] [${context.getTrackingId()}] ${this.getNextTask.name}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -250,7 +263,9 @@ export class TasksService {
|
||||
): Promise<void> {
|
||||
try {
|
||||
this.logger.log(
|
||||
`[IN] [${context.trackingId}] ${this.checkout.name} | params: { audioFileId: ${audioFileId}, roles: ${roles}, externalId: ${externalId} };`,
|
||||
`[IN] [${context.getTrackingId()}] ${
|
||||
this.checkout.name
|
||||
} | params: { audioFileId: ${audioFileId}, roles: ${roles}, externalId: ${externalId} };`,
|
||||
);
|
||||
|
||||
const { id, account_id, author_id } =
|
||||
@ -279,7 +294,7 @@ export class TasksService {
|
||||
|
||||
throw new InvalidRoleError(`invalid roles: ${roles.join(',')}`);
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
if (e instanceof Error) {
|
||||
switch (e.constructor) {
|
||||
case CheckoutPermissionNotFoundError:
|
||||
@ -296,6 +311,7 @@ export class TasksService {
|
||||
);
|
||||
case AccountNotMatchError:
|
||||
case StatusNotMatchError:
|
||||
case AlreadyHasInProgressTaskError:
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E010601'),
|
||||
HttpStatus.BAD_REQUEST,
|
||||
@ -312,7 +328,9 @@ export class TasksService {
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
} finally {
|
||||
this.logger.log(`[OUT] [${context.trackingId}] ${this.checkout.name}`);
|
||||
this.logger.log(
|
||||
`[OUT] [${context.getTrackingId()}] ${this.checkout.name}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -329,7 +347,9 @@ export class TasksService {
|
||||
): Promise<void> {
|
||||
try {
|
||||
this.logger.log(
|
||||
`[IN] [${context.trackingId}] ${this.checkin.name} | params: { audioFileId: ${audioFileId}, externalId: ${externalId} };`,
|
||||
`[IN] [${context.getTrackingId()}] ${
|
||||
this.checkin.name
|
||||
} | params: { audioFileId: ${audioFileId}, externalId: ${externalId} };`,
|
||||
);
|
||||
const { id } = await this.usersRepository.findUserByExternalId(
|
||||
externalId,
|
||||
@ -341,7 +361,7 @@ export class TasksService {
|
||||
TASK_STATUS.IN_PROGRESS,
|
||||
);
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
if (e instanceof Error) {
|
||||
switch (e.constructor) {
|
||||
case TasksNotFoundError:
|
||||
@ -367,7 +387,9 @@ export class TasksService {
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
} finally {
|
||||
this.logger.log(`[OUT] [${context.trackingId}] ${this.checkin.name}`);
|
||||
this.logger.log(
|
||||
`[OUT] [${context.getTrackingId()}] ${this.checkin.name}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
/**
|
||||
@ -384,15 +406,17 @@ export class TasksService {
|
||||
role: Roles[],
|
||||
): Promise<void> {
|
||||
this.logger.log(
|
||||
`[IN] [${context.trackingId}] ${this.cancel.name} | params: { audioFileId: ${audioFileId}, externalId: ${externalId}, role: ${role} };`,
|
||||
`[IN] [${context.getTrackingId()}] ${
|
||||
this.cancel.name
|
||||
} | params: { audioFileId: ${audioFileId}, externalId: ${externalId}, role: ${role} };`,
|
||||
);
|
||||
let user: User;
|
||||
try {
|
||||
// ユーザー取得
|
||||
user = await this.usersRepository.findUserByExternalId(externalId);
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
this.logger.log(`[OUT] [${context.trackingId}] ${this.cancel.name}`);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
this.logger.log(`[OUT] [${context.getTrackingId()}] ${this.cancel.name}`);
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
@ -408,7 +432,7 @@ export class TasksService {
|
||||
role.includes(ADMIN_ROLES.ADMIN) ? undefined : user.id,
|
||||
);
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
if (e instanceof Error) {
|
||||
switch (e.constructor) {
|
||||
case TasksNotFoundError:
|
||||
@ -444,38 +468,22 @@ export class TasksService {
|
||||
user.author_id ?? undefined,
|
||||
);
|
||||
|
||||
const groupMembers =
|
||||
await this.userGroupsRepositoryService.getGroupMembersFromGroupIds(
|
||||
typistGroupIds,
|
||||
);
|
||||
|
||||
// 重複のない割り当て候補ユーザーID一覧を取得する
|
||||
const distinctUserIds = [
|
||||
...new Set([...typistIds, ...groupMembers.map((x) => x.user_id)]),
|
||||
];
|
||||
|
||||
// 割り当てられたユーザーがいない場合は通知不要
|
||||
if (distinctUserIds.length === 0) {
|
||||
this.logger.log('No user assigned.');
|
||||
return;
|
||||
}
|
||||
|
||||
// タグを生成
|
||||
const tags = distinctUserIds.map((x) => `user_${x}`);
|
||||
this.logger.log(`tags: ${tags}`);
|
||||
|
||||
// タグ対象に通知送信
|
||||
await this.notificationhubService.notify(
|
||||
// 通知を送信する
|
||||
await this.sendNotify(
|
||||
context,
|
||||
tags,
|
||||
makeNotifyMessage('M000101'),
|
||||
typistIds,
|
||||
typistGroupIds,
|
||||
audioFileId,
|
||||
user.account_id,
|
||||
);
|
||||
} catch (e) {
|
||||
// 処理の本筋はタスクキャンセルのため自動ルーティングに失敗してもエラーにしない
|
||||
this.logger.error(`Automatic routing or notification failed.`);
|
||||
this.logger.error(`error=${e}`);
|
||||
this.logger.error(
|
||||
`[${context.getTrackingId()}] Automatic routing or notification failed.`,
|
||||
);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
} finally {
|
||||
this.logger.log(`[OUT] [${context.trackingId}] ${this.cancel.name}`);
|
||||
this.logger.log(`[OUT] [${context.getTrackingId()}] ${this.cancel.name}`);
|
||||
}
|
||||
}
|
||||
|
||||
@ -492,7 +500,9 @@ export class TasksService {
|
||||
): Promise<void> {
|
||||
try {
|
||||
this.logger.log(
|
||||
`[IN] [${context.trackingId}] ${this.suspend.name} | params: { audioFileId: ${audioFileId}, externalId: ${externalId} };`,
|
||||
`[IN] [${context.getTrackingId()}] ${
|
||||
this.suspend.name
|
||||
} | params: { audioFileId: ${audioFileId}, externalId: ${externalId} };`,
|
||||
);
|
||||
const { id } = await this.usersRepository.findUserByExternalId(
|
||||
externalId,
|
||||
@ -504,7 +514,7 @@ export class TasksService {
|
||||
TASK_STATUS.IN_PROGRESS,
|
||||
);
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
if (e instanceof Error) {
|
||||
switch (e.constructor) {
|
||||
case TasksNotFoundError:
|
||||
@ -530,7 +540,9 @@ export class TasksService {
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
} finally {
|
||||
this.logger.log(`[OUT] [${context.trackingId}] ${this.suspend.name}`);
|
||||
this.logger.log(
|
||||
`[OUT] [${context.getTrackingId()}] ${this.suspend.name}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -539,6 +551,11 @@ export class TasksService {
|
||||
tasks: TaskEntity[],
|
||||
permissions: CheckoutPermission[],
|
||||
): Promise<AdB2cUser[]> {
|
||||
this.logger.log(
|
||||
`[IN] [${context.getTrackingId()}] ${
|
||||
this.getB2cUsers.name
|
||||
} | params: { tasks: ${tasks}, permissions: ${permissions} };`,
|
||||
);
|
||||
// 割り当て候補の外部IDを列挙
|
||||
const assigneesExternalIds = permissions.flatMap((permission) =>
|
||||
permission.user ? [permission.user.external_id] : [],
|
||||
@ -571,7 +588,9 @@ export class TasksService {
|
||||
): Promise<void> {
|
||||
try {
|
||||
this.logger.log(
|
||||
`[IN] [${context.trackingId}] ${this.changeCheckoutPermission.name} | params: { audioFileId: ${audioFileId}, assignees: ${assignees}, externalId: ${externalId}, role: ${role} };`,
|
||||
`[IN] [${context.getTrackingId()}] ${
|
||||
this.changeCheckoutPermission.name
|
||||
} | params: { audioFileId: ${audioFileId}, assignees: ${assignees}, externalId: ${externalId}, role: ${role} };`,
|
||||
);
|
||||
const { author_id, account_id } =
|
||||
await this.usersRepository.findUserByExternalId(externalId);
|
||||
@ -600,38 +619,16 @@ export class TasksService {
|
||||
.flatMap((assignee) =>
|
||||
assignee.typistUserId ? [assignee.typistUserId] : [],
|
||||
);
|
||||
|
||||
const groupMembers =
|
||||
await this.userGroupsRepositoryService.getGroupMembersFromGroupIds(
|
||||
assigneesGroupIds,
|
||||
);
|
||||
|
||||
// 重複のない割り当て候補ユーザーID一覧を取得する
|
||||
const distinctUserIds = [
|
||||
...new Set([
|
||||
...assigneesUserIds,
|
||||
...groupMembers.map((x) => x.user_id),
|
||||
]),
|
||||
];
|
||||
|
||||
// 割り当てられたユーザーがいない場合は通知不要
|
||||
if (distinctUserIds.length === 0) {
|
||||
this.logger.log('No user assigned.');
|
||||
return;
|
||||
}
|
||||
|
||||
// タグを生成
|
||||
const tags = distinctUserIds.map((x) => `user_${x}`);
|
||||
this.logger.log(`tags: ${tags}`);
|
||||
|
||||
// タグ対象に通知送信
|
||||
await this.notificationhubService.notify(
|
||||
// 通知を送信する
|
||||
await this.sendNotify(
|
||||
context,
|
||||
tags,
|
||||
makeNotifyMessage('M000101'),
|
||||
assigneesUserIds,
|
||||
assigneesGroupIds,
|
||||
audioFileId,
|
||||
account_id,
|
||||
);
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
if (e instanceof Error) {
|
||||
switch (e.constructor) {
|
||||
case TypistUserNotFoundError:
|
||||
@ -658,8 +655,64 @@ export class TasksService {
|
||||
);
|
||||
} finally {
|
||||
this.logger.log(
|
||||
`[OUT] [${context.trackingId}] ${this.changeCheckoutPermission.name}`,
|
||||
`[OUT] [${context.getTrackingId()}] ${
|
||||
this.changeCheckoutPermission.name
|
||||
}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// 通知を送信するプライベートメソッド
|
||||
private async sendNotify(
|
||||
context: Context,
|
||||
typistUserIds: number[],
|
||||
typistGroupIds: number[],
|
||||
audioFileId: number,
|
||||
accountId: number,
|
||||
): Promise<void> {
|
||||
this.logger.log(
|
||||
`[IN] [${context.getTrackingId()}] ${this.sendNotify.name} | params: { ` +
|
||||
`typistUserIds: ${typistUserIds}, ` +
|
||||
`typistGroupIds: ${typistGroupIds}, ` +
|
||||
`audioFileId: ${audioFileId}, ` +
|
||||
`accountId: ${accountId} };`,
|
||||
);
|
||||
const groupMembers =
|
||||
await this.userGroupsRepositoryService.getGroupMembersFromGroupIds(
|
||||
typistGroupIds,
|
||||
);
|
||||
|
||||
// 重複のない割り当て候補ユーザーID一覧を取得する
|
||||
const distinctUserIds = [
|
||||
...new Set([...typistUserIds, ...groupMembers.map((x) => x.user_id)]),
|
||||
];
|
||||
|
||||
// 割り当てられたユーザーがいない場合は通知不要
|
||||
if (distinctUserIds.length === 0) {
|
||||
this.logger.log(`[${context.getTrackingId()}] No user assigned.`);
|
||||
return;
|
||||
}
|
||||
|
||||
// タグを生成
|
||||
const tags = distinctUserIds.map((x) => `user_${x}`);
|
||||
this.logger.log(`[${context.getTrackingId()}] tags: ${tags}`);
|
||||
|
||||
// 通知内容に含む音声ファイル情報を取得
|
||||
const { file } = await this.taskRepository.getTaskAndAudioFile(
|
||||
audioFileId,
|
||||
accountId,
|
||||
[TASK_STATUS.UPLOADED],
|
||||
);
|
||||
if (!file) {
|
||||
throw new Error('audio file not found');
|
||||
}
|
||||
|
||||
// タグ対象に通知送信
|
||||
await this.notificationhubService.notify(context, tags, {
|
||||
authorId: file.author_id,
|
||||
filename: file.file_name.replace('.zip', ''),
|
||||
priority: file.priority === '00' ? 'Normal' : 'High',
|
||||
uploadedAt: file.uploaded_at.toISOString(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -207,6 +207,9 @@ export const getTask = async (
|
||||
task_id: number,
|
||||
): Promise<Task | null> => {
|
||||
const task = await datasource.getRepository(Task).findOne({
|
||||
relations: {
|
||||
file: true,
|
||||
},
|
||||
where: {
|
||||
id: task_id,
|
||||
},
|
||||
|
||||
@ -24,7 +24,9 @@ export class TemplatesService {
|
||||
externalId: string,
|
||||
): Promise<TemplateFile[]> {
|
||||
this.logger.log(
|
||||
`[IN] [${context.trackingId}] ${this.getTemplates.name} | params: { externalId: ${externalId} };`,
|
||||
`[IN] [${context.getTrackingId()}] ${
|
||||
this.getTemplates.name
|
||||
} | params: { externalId: ${externalId} };`,
|
||||
);
|
||||
|
||||
try {
|
||||
@ -42,14 +44,14 @@ export class TemplatesService {
|
||||
|
||||
return resTemplates;
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
} finally {
|
||||
this.logger.log(
|
||||
`[OUT] [${context.trackingId}] ${this.getTemplates.name}`,
|
||||
`[OUT] [${context.getTrackingId()}] ${this.getTemplates.name}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,8 +3,8 @@ import { ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';
|
||||
import { TermsService } from '../terms/terms.service';
|
||||
import { ErrorResponse } from '../../common/error/types/types';
|
||||
import { makeContext } from '../../common/log';
|
||||
import { GetTermsInfoResponse } from './types/types';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import { GetTermsInfoResponse, TermInfo } from './types/types';
|
||||
|
||||
@ApiTags('terms')
|
||||
@Controller('terms')
|
||||
|
||||
@ -15,7 +15,9 @@ export class TermsService {
|
||||
* return termsInfo
|
||||
*/
|
||||
async getTermsInfo(context: Context): Promise<TermInfo[]> {
|
||||
this.logger.log(`[IN] [${context.trackingId}] ${this.getTermsInfo.name}`);
|
||||
this.logger.log(
|
||||
`[IN] [${context.getTrackingId()}] ${this.getTermsInfo.name}`,
|
||||
);
|
||||
try {
|
||||
const { eulaVersion, dpaVersion } =
|
||||
await this.termsRepository.getLatestTermsInfo();
|
||||
@ -30,14 +32,14 @@ export class TermsService {
|
||||
},
|
||||
];
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
} finally {
|
||||
this.logger.log(
|
||||
`[OUT] [${context.trackingId}] ${this.getTermsInfo.name}`,
|
||||
`[OUT] [${context.getTrackingId()}] ${this.getTermsInfo.name}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -144,9 +144,11 @@ export class OptionItemList {
|
||||
|
||||
export class GetRelationsResponse {
|
||||
@ApiProperty({
|
||||
description: 'ログインしたユーザーのAuthorID(Authorでない場合は空文字)',
|
||||
required: false,
|
||||
description:
|
||||
'ログインしたユーザーのAuthorID(Authorでない場合はundefined)',
|
||||
})
|
||||
authorId: string;
|
||||
authorId?: string;
|
||||
@ApiProperty({ description: '属しているアカウントのAuthorID List(全て)' })
|
||||
authorIdList: string[];
|
||||
@ApiProperty({
|
||||
|
||||
@ -81,7 +81,9 @@ export class UsersController {
|
||||
@ApiOperation({ operationId: 'confirmUser' })
|
||||
@Post('confirm')
|
||||
async confirmUser(@Body() body: ConfirmRequest): Promise<ConfirmResponse> {
|
||||
await this.usersService.confirmUser(body.token);
|
||||
const context = makeContext(uuidv4());
|
||||
|
||||
await this.usersService.confirmUser(context, body.token);
|
||||
return {};
|
||||
}
|
||||
|
||||
@ -148,8 +150,9 @@ export class UsersController {
|
||||
);
|
||||
}
|
||||
const { userId } = decodedAccessToken as AccessToken;
|
||||
const context = makeContext(userId);
|
||||
|
||||
const users = await this.usersService.getUsers(userId);
|
||||
const users = await this.usersService.getUsers(context, userId);
|
||||
return { users };
|
||||
}
|
||||
|
||||
@ -325,6 +328,7 @@ export class UsersController {
|
||||
);
|
||||
}
|
||||
const { userId } = decodedAccessToken as AccessToken;
|
||||
const context = makeContext(userId);
|
||||
|
||||
//型チェック
|
||||
if (
|
||||
@ -336,7 +340,12 @@ export class UsersController {
|
||||
HttpStatus.BAD_REQUEST,
|
||||
);
|
||||
}
|
||||
await this.usersService.updateSortCriteria(paramName, direction, userId);
|
||||
await this.usersService.updateSortCriteria(
|
||||
context,
|
||||
paramName,
|
||||
direction,
|
||||
userId,
|
||||
);
|
||||
return {};
|
||||
}
|
||||
|
||||
@ -383,8 +392,10 @@ export class UsersController {
|
||||
);
|
||||
}
|
||||
const { userId } = decodedAccessToken as AccessToken;
|
||||
const context = makeContext(userId);
|
||||
|
||||
const { direction, paramName } = await this.usersService.getSortCriteria(
|
||||
context,
|
||||
userId,
|
||||
);
|
||||
return { direction, paramName };
|
||||
@ -618,10 +629,17 @@ export class UsersController {
|
||||
): Promise<UpdateAcceptedVersionResponse> {
|
||||
const { idToken, acceptedEULAVersion, acceptedDPAVersion } = body;
|
||||
|
||||
const verifiedIdToken = await this.authService.getVerifiedIdToken(idToken);
|
||||
const context = makeContext(verifiedIdToken.sub);
|
||||
const context = makeContext(uuidv4());
|
||||
|
||||
const isVerified = await this.authService.isVerifiedUser(verifiedIdToken);
|
||||
const verifiedIdToken = await this.authService.getVerifiedIdToken(
|
||||
context,
|
||||
idToken,
|
||||
);
|
||||
|
||||
const isVerified = await this.authService.isVerifiedUser(
|
||||
context,
|
||||
verifiedIdToken,
|
||||
);
|
||||
if (!isVerified) {
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E010201'),
|
||||
|
||||
@ -22,6 +22,7 @@ import {
|
||||
LICENSE_ALLOCATED_STATUS,
|
||||
LICENSE_EXPIRATION_THRESHOLD_DAYS,
|
||||
LICENSE_TYPE,
|
||||
USER_AUDIO_FORMAT,
|
||||
USER_LICENSE_STATUS,
|
||||
USER_ROLES,
|
||||
} from '../../constants';
|
||||
@ -44,6 +45,8 @@ import {
|
||||
makeTestUser,
|
||||
} from '../../common/test/utility';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import { createOptionItems, createWorktype } from '../accounts/test/utility';
|
||||
import { createWorkflow, getWorkflows } from '../workflows/test/utility';
|
||||
|
||||
describe('UsersService.confirmUser', () => {
|
||||
let source: DataSource | null = null;
|
||||
@ -94,7 +97,8 @@ describe('UsersService.confirmUser', () => {
|
||||
// account id:1, user id: 2のトークン
|
||||
const token =
|
||||
'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhY2NvdW50SWQiOjEsInVzZXJJZCI6MiwiZW1haWwiOiJ4eHhAeHh4Lnh4eCIsImlhdCI6MTAwMDAwMDAwMCwiZXhwIjo5MDAwMDAwMDAwfQ.26L6BdNg-3TbyKT62PswlJ6RPMkcTtHzlDXW2Uo9XbMPVSrl2ObcuS6EcXjFFN2DEfNTKbqX_zevIWMpHOAdLNgGhk528nLrBrNvPASqtTjvW9muxMXpjUdjRVkmVbOylBHWW3YpWL9JEbJQ7rAzWDfaIdPhMovdaxumnZt_UwnlnrdaVPLACW7tkH_laEcAU507iSiM4mqxxG8FuTs34t6PEdwRuzZAQPN2IOPYNSvGNdJYryPacSeSNZ_z1xeBYXLOLQfOBZzyTReYDOhXdikhrNUbxjgnZQlSXBCVMlZ9PH42bHfp-LJIeJzW0yqnF6oLklvJP-fo8eW0k5iDOw';
|
||||
await service.confirmUser(token);
|
||||
const context = makeContext(`uuidv4`);
|
||||
await service.confirmUser(context, token);
|
||||
//result
|
||||
const resultUser = await getUser(source, userId);
|
||||
const resultLicenses = await getLicenses(source, accountId);
|
||||
@ -137,7 +141,8 @@ describe('UsersService.confirmUser', () => {
|
||||
if (!module) fail();
|
||||
const token = 'invalid.id.token';
|
||||
const service = module.get<UsersService>(UsersService);
|
||||
await expect(service.confirmUser(token)).rejects.toEqual(
|
||||
const context = makeContext(`uuidv4`);
|
||||
await expect(service.confirmUser(context, token)).rejects.toEqual(
|
||||
new HttpException(makeErrorResponse('E000101'), HttpStatus.BAD_REQUEST),
|
||||
);
|
||||
});
|
||||
@ -172,7 +177,8 @@ describe('UsersService.confirmUser', () => {
|
||||
const service = module.get<UsersService>(UsersService);
|
||||
const token =
|
||||
'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhY2NvdW50SWQiOjEsInVzZXJJZCI6MiwiZW1haWwiOiJ4eHhAeHh4Lnh4eCIsImlhdCI6MTAwMDAwMDAwMCwiZXhwIjo5MDAwMDAwMDAwfQ.26L6BdNg-3TbyKT62PswlJ6RPMkcTtHzlDXW2Uo9XbMPVSrl2ObcuS6EcXjFFN2DEfNTKbqX_zevIWMpHOAdLNgGhk528nLrBrNvPASqtTjvW9muxMXpjUdjRVkmVbOylBHWW3YpWL9JEbJQ7rAzWDfaIdPhMovdaxumnZt_UwnlnrdaVPLACW7tkH_laEcAU507iSiM4mqxxG8FuTs34t6PEdwRuzZAQPN2IOPYNSvGNdJYryPacSeSNZ_z1xeBYXLOLQfOBZzyTReYDOhXdikhrNUbxjgnZQlSXBCVMlZ9PH42bHfp-LJIeJzW0yqnF6oLklvJP-fo8eW0k5iDOw';
|
||||
await expect(service.confirmUser(token)).rejects.toEqual(
|
||||
const context = makeContext(`uuidv4`);
|
||||
await expect(service.confirmUser(context, token)).rejects.toEqual(
|
||||
new HttpException(makeErrorResponse('E010202'), HttpStatus.BAD_REQUEST),
|
||||
);
|
||||
});
|
||||
@ -183,7 +189,8 @@ describe('UsersService.confirmUser', () => {
|
||||
const service = module.get<UsersService>(UsersService);
|
||||
const token =
|
||||
'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhY2NvdW50SWQiOjEsInVzZXJJZCI6MiwiZW1haWwiOiJ4eHhAeHh4Lnh4eCIsImlhdCI6MTAwMDAwMDAwMCwiZXhwIjo5MDAwMDAwMDAwfQ.26L6BdNg-3TbyKT62PswlJ6RPMkcTtHzlDXW2Uo9XbMPVSrl2ObcuS6EcXjFFN2DEfNTKbqX_zevIWMpHOAdLNgGhk528nLrBrNvPASqtTjvW9muxMXpjUdjRVkmVbOylBHWW3YpWL9JEbJQ7rAzWDfaIdPhMovdaxumnZt_UwnlnrdaVPLACW7tkH_laEcAU507iSiM4mqxxG8FuTs34t6PEdwRuzZAQPN2IOPYNSvGNdJYryPacSeSNZ_z1xeBYXLOLQfOBZzyTReYDOhXdikhrNUbxjgnZQlSXBCVMlZ9PH42bHfp-LJIeJzW0yqnF6oLklvJP-fo8eW0k5iDOw';
|
||||
await expect(service.confirmUser(token)).rejects.toEqual(
|
||||
const context = makeContext(`uuidv4`);
|
||||
await expect(service.confirmUser(context, token)).rejects.toEqual(
|
||||
new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
@ -1623,7 +1630,10 @@ describe('UsersService.getUsers', () => {
|
||||
},
|
||||
];
|
||||
|
||||
expect(await service.getUsers(externalId_author)).toEqual(expectedUsers);
|
||||
const context = makeContext(`uuidv4`);
|
||||
expect(await service.getUsers(context, externalId_author)).toEqual(
|
||||
expectedUsers,
|
||||
);
|
||||
});
|
||||
|
||||
it('ユーザーの一覧を取得できること(ライセンス割当済み)', async () => {
|
||||
@ -1739,7 +1749,10 @@ describe('UsersService.getUsers', () => {
|
||||
},
|
||||
];
|
||||
|
||||
expect(await service.getUsers(external_id1)).toEqual(expectedUsers);
|
||||
const context = makeContext(`uuidv4`);
|
||||
expect(await service.getUsers(context, external_id1)).toEqual(
|
||||
expectedUsers,
|
||||
);
|
||||
});
|
||||
|
||||
it('DBからのユーザーの取得に失敗した場合、エラーとなる', async () => {
|
||||
@ -1760,8 +1773,11 @@ describe('UsersService.getUsers', () => {
|
||||
prompt: false,
|
||||
});
|
||||
|
||||
const context = makeContext(`uuidv4`);
|
||||
const service = module.get<UsersService>(UsersService);
|
||||
await expect(service.getUsers('externalId_failed')).rejects.toEqual(
|
||||
await expect(
|
||||
service.getUsers(context, 'externalId_failed'),
|
||||
).rejects.toEqual(
|
||||
new HttpException(makeErrorResponse('E009999'), HttpStatus.NOT_FOUND),
|
||||
);
|
||||
});
|
||||
@ -1785,8 +1801,9 @@ describe('UsersService.getUsers', () => {
|
||||
prompt: false,
|
||||
});
|
||||
|
||||
const context = makeContext(`uuidv4`);
|
||||
const service = module.get<UsersService>(UsersService);
|
||||
await expect(service.getUsers(externalId_author)).rejects.toEqual(
|
||||
await expect(service.getUsers(context, externalId_author)).rejects.toEqual(
|
||||
new HttpException(makeErrorResponse('E009999'), HttpStatus.NOT_FOUND),
|
||||
);
|
||||
});
|
||||
@ -1809,9 +1826,15 @@ describe('UsersService.updateSortCriteria', () => {
|
||||
configMockValue,
|
||||
sortCriteriaRepositoryMockValue,
|
||||
);
|
||||
const context = makeContext(`uuidv4`);
|
||||
|
||||
expect(
|
||||
await service.updateSortCriteria('AUTHOR_ID', 'ASC', 'external_id'),
|
||||
await service.updateSortCriteria(
|
||||
context,
|
||||
'AUTHOR_ID',
|
||||
'ASC',
|
||||
'external_id',
|
||||
),
|
||||
).toEqual(undefined);
|
||||
});
|
||||
|
||||
@ -1834,9 +1857,10 @@ describe('UsersService.updateSortCriteria', () => {
|
||||
configMockValue,
|
||||
sortCriteriaRepositoryMockValue,
|
||||
);
|
||||
const context = makeContext(`uuidv4`);
|
||||
|
||||
await expect(
|
||||
service.updateSortCriteria('AUTHOR_ID', 'ASC', 'external_id'),
|
||||
service.updateSortCriteria(context, 'AUTHOR_ID', 'ASC', 'external_id'),
|
||||
).rejects.toEqual(
|
||||
new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
@ -1865,9 +1889,10 @@ describe('UsersService.updateSortCriteria', () => {
|
||||
configMockValue,
|
||||
sortCriteriaRepositoryMockValue,
|
||||
);
|
||||
const context = makeContext(`uuidv4`);
|
||||
|
||||
await expect(
|
||||
service.updateSortCriteria('AUTHOR_ID', 'ASC', 'external_id'),
|
||||
service.updateSortCriteria(context, 'AUTHOR_ID', 'ASC', 'external_id'),
|
||||
).rejects.toEqual(
|
||||
new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
@ -1894,8 +1919,9 @@ describe('UsersService.getSortCriteria', () => {
|
||||
configMockValue,
|
||||
sortCriteriaRepositoryMockValue,
|
||||
);
|
||||
const context = makeContext(`uuidv4`);
|
||||
|
||||
expect(await service.getSortCriteria('external_id')).toEqual({
|
||||
expect(await service.getSortCriteria(context, 'external_id')).toEqual({
|
||||
direction: 'ASC',
|
||||
paramName: 'JOB_NUMBER',
|
||||
});
|
||||
@ -1922,8 +1948,11 @@ describe('UsersService.getSortCriteria', () => {
|
||||
configMockValue,
|
||||
sortCriteriaRepositoryMockValue,
|
||||
);
|
||||
const context = makeContext(`uuidv4`);
|
||||
|
||||
await expect(service.getSortCriteria('external_id')).rejects.toEqual(
|
||||
await expect(
|
||||
service.getSortCriteria(context, 'external_id'),
|
||||
).rejects.toEqual(
|
||||
new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
@ -1954,8 +1983,11 @@ describe('UsersService.getSortCriteria', () => {
|
||||
configMockValue,
|
||||
sortCriteriaRepositoryMockValue,
|
||||
);
|
||||
const context = makeContext(`uuidv4`);
|
||||
|
||||
await expect(service.getSortCriteria('external_id')).rejects.toEqual(
|
||||
await expect(
|
||||
service.getSortCriteria(context, 'external_id'),
|
||||
).rejects.toEqual(
|
||||
new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
@ -2011,10 +2043,11 @@ describe('UsersService.updateUser', () => {
|
||||
});
|
||||
|
||||
const service = module.get<UsersService>(UsersService);
|
||||
const context = makeContext(`uuidv4`);
|
||||
|
||||
expect(
|
||||
await service.updateUser(
|
||||
{ trackingId: 'trackingId' },
|
||||
context,
|
||||
external_id,
|
||||
user1,
|
||||
USER_ROLES.NONE,
|
||||
@ -2069,10 +2102,11 @@ describe('UsersService.updateUser', () => {
|
||||
});
|
||||
|
||||
const service = module.get<UsersService>(UsersService);
|
||||
const context = makeContext(`uuidv4`);
|
||||
|
||||
expect(
|
||||
await service.updateUser(
|
||||
{ trackingId: 'trackingId' },
|
||||
context,
|
||||
external_id,
|
||||
user1,
|
||||
USER_ROLES.TYPIST,
|
||||
@ -2127,10 +2161,11 @@ describe('UsersService.updateUser', () => {
|
||||
});
|
||||
|
||||
const service = module.get<UsersService>(UsersService);
|
||||
const context = makeContext(`uuidv4`);
|
||||
|
||||
expect(
|
||||
await service.updateUser(
|
||||
{ trackingId: 'trackingId' },
|
||||
context,
|
||||
external_id,
|
||||
user1,
|
||||
USER_ROLES.AUTHOR,
|
||||
@ -2185,10 +2220,11 @@ describe('UsersService.updateUser', () => {
|
||||
});
|
||||
|
||||
const service = module.get<UsersService>(UsersService);
|
||||
const context = makeContext(`uuidv4`);
|
||||
|
||||
expect(
|
||||
await service.updateUser(
|
||||
{ trackingId: 'trackingId' },
|
||||
context,
|
||||
external_id,
|
||||
user1,
|
||||
USER_ROLES.TYPIST,
|
||||
@ -2243,10 +2279,11 @@ describe('UsersService.updateUser', () => {
|
||||
});
|
||||
|
||||
const service = module.get<UsersService>(UsersService);
|
||||
const context = makeContext(`uuidv4`);
|
||||
|
||||
expect(
|
||||
await service.updateUser(
|
||||
{ trackingId: 'trackingId' },
|
||||
context,
|
||||
external_id,
|
||||
user1,
|
||||
USER_ROLES.AUTHOR,
|
||||
@ -2301,10 +2338,11 @@ describe('UsersService.updateUser', () => {
|
||||
});
|
||||
|
||||
const service = module.get<UsersService>(UsersService);
|
||||
const context = makeContext(`uuidv4`);
|
||||
|
||||
await expect(
|
||||
service.updateUser(
|
||||
{ trackingId: 'trackingId' },
|
||||
context,
|
||||
external_id,
|
||||
user1,
|
||||
USER_ROLES.NONE,
|
||||
@ -2349,10 +2387,11 @@ describe('UsersService.updateUser', () => {
|
||||
});
|
||||
|
||||
const service = module.get<UsersService>(UsersService);
|
||||
const context = makeContext(`uuidv4`);
|
||||
|
||||
expect(
|
||||
await service.updateUser(
|
||||
{ trackingId: 'trackingId' },
|
||||
context,
|
||||
external_id,
|
||||
user1,
|
||||
USER_ROLES.AUTHOR,
|
||||
@ -2407,10 +2446,11 @@ describe('UsersService.updateUser', () => {
|
||||
});
|
||||
|
||||
const service = module.get<UsersService>(UsersService);
|
||||
const context = makeContext(`uuidv4`);
|
||||
|
||||
expect(
|
||||
await service.updateUser(
|
||||
{ trackingId: 'trackingId' },
|
||||
context,
|
||||
external_id,
|
||||
user1,
|
||||
USER_ROLES.AUTHOR,
|
||||
@ -2465,10 +2505,11 @@ describe('UsersService.updateUser', () => {
|
||||
});
|
||||
|
||||
const service = module.get<UsersService>(UsersService);
|
||||
const context = makeContext(`uuidv4`);
|
||||
|
||||
await expect(
|
||||
service.updateUser(
|
||||
{ trackingId: 'trackingId' },
|
||||
context,
|
||||
external_id,
|
||||
user1,
|
||||
USER_ROLES.AUTHOR,
|
||||
@ -2524,10 +2565,11 @@ describe('UsersService.updateUser', () => {
|
||||
});
|
||||
|
||||
const service = module.get<UsersService>(UsersService);
|
||||
const context = makeContext(`uuidv4`);
|
||||
|
||||
await expect(
|
||||
service.updateUser(
|
||||
{ trackingId: 'trackingId' },
|
||||
context,
|
||||
external_id,
|
||||
user1,
|
||||
USER_ROLES.AUTHOR,
|
||||
@ -2666,3 +2708,187 @@ describe('UsersService.getUserName', () => {
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('UsersService.getRelations', () => {
|
||||
let source: DataSource | null = null;
|
||||
|
||||
beforeEach(async () => {
|
||||
source = new DataSource({
|
||||
type: 'sqlite',
|
||||
database: ':memory:',
|
||||
logging: false,
|
||||
entities: [__dirname + '/../../**/*.entity{.ts,.js}'],
|
||||
synchronize: true,
|
||||
});
|
||||
return source.initialize();
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
if (!source) return;
|
||||
await source.destroy();
|
||||
source = null;
|
||||
});
|
||||
|
||||
it('ユーザー関連情報を取得できる(Author)', async () => {
|
||||
if (!source) fail();
|
||||
const module = await makeTestingModule(source);
|
||||
if (!module) fail();
|
||||
|
||||
const { account } = await makeTestAccount(source, {
|
||||
tier: 5,
|
||||
});
|
||||
const { id: user1, external_id } = await makeTestUser(source, {
|
||||
account_id: account.id,
|
||||
role: USER_ROLES.AUTHOR,
|
||||
author_id: 'AUTHOR_1',
|
||||
encryption: true,
|
||||
encryption_password: 'password',
|
||||
prompt: true,
|
||||
});
|
||||
const { id: user2 } = await makeTestUser(source, {
|
||||
account_id: account.id,
|
||||
role: USER_ROLES.AUTHOR,
|
||||
author_id: 'AUTHOR_2',
|
||||
});
|
||||
await makeTestUser(source, {
|
||||
account_id: account.id,
|
||||
role: USER_ROLES.AUTHOR,
|
||||
author_id: 'AUTHOR_3',
|
||||
email_verified: false,
|
||||
});
|
||||
|
||||
const worktype1 = await createWorktype(
|
||||
source,
|
||||
account.id,
|
||||
'worktype1',
|
||||
undefined,
|
||||
true,
|
||||
);
|
||||
await createOptionItems(source, worktype1.id);
|
||||
|
||||
const worktype2 = await createWorktype(source, account.id, 'worktype2');
|
||||
await createOptionItems(source, worktype2.id);
|
||||
|
||||
await createWorkflow(source, account.id, user1, worktype1.id);
|
||||
await createWorkflow(source, account.id, user1, worktype2.id);
|
||||
await createWorkflow(source, account.id, user1);
|
||||
await createWorkflow(source, account.id, user2, worktype1.id);
|
||||
|
||||
// 作成したデータを確認
|
||||
{
|
||||
const workflows = await getWorkflows(source, account.id);
|
||||
expect(workflows.length).toBe(4);
|
||||
expect(workflows[0].worktype_id).toBe(worktype1.id);
|
||||
expect(workflows[0].author_id).toBe(user1);
|
||||
expect(workflows[1].worktype_id).toBe(worktype2.id);
|
||||
expect(workflows[1].author_id).toBe(user1);
|
||||
expect(workflows[2].worktype_id).toBe(null);
|
||||
expect(workflows[2].author_id).toBe(user1);
|
||||
expect(workflows[3].worktype_id).toBe(worktype1.id);
|
||||
expect(workflows[3].author_id).toBe(user2);
|
||||
}
|
||||
|
||||
const context = makeContext(external_id);
|
||||
|
||||
const service = module.get<UsersService>(UsersService);
|
||||
const relations = await service.getRelations(context, external_id);
|
||||
|
||||
// レスポンスを確認
|
||||
{
|
||||
expect(relations.authorId).toBe('AUTHOR_1');
|
||||
expect(relations.authorIdList.length).toBe(2);
|
||||
expect(relations.authorIdList[0]).toBe('AUTHOR_1');
|
||||
expect(relations.authorIdList[1]).toBe('AUTHOR_2');
|
||||
|
||||
const workTypeList = relations.workTypeList;
|
||||
expect(relations.workTypeList.length).toBe(2);
|
||||
expect(workTypeList[0].workTypeId).toBe(worktype1.custom_worktype_id);
|
||||
expect(workTypeList[0].optionItemList.length).toBe(10);
|
||||
expect(workTypeList[0].optionItemList[0].label).toBe('');
|
||||
expect(workTypeList[0].optionItemList[0].initialValueType).toBe(2);
|
||||
expect(workTypeList[0].optionItemList[0].defaultValue).toBe('');
|
||||
expect(workTypeList[1].workTypeId).toBe(worktype2.custom_worktype_id);
|
||||
expect(workTypeList[1].optionItemList.length).toBe(10);
|
||||
|
||||
expect(relations.isEncrypted).toBe(true);
|
||||
expect(relations.encryptionPassword).toBe('password');
|
||||
expect(relations.activeWorktype).toBe(worktype1.custom_worktype_id);
|
||||
expect(relations.audioFormat).toBe(USER_AUDIO_FORMAT);
|
||||
expect(relations.prompt).toBe(true);
|
||||
}
|
||||
});
|
||||
|
||||
it('ユーザー関連情報を取得できる(Author以外)', async () => {
|
||||
if (!source) fail();
|
||||
const module = await makeTestingModule(source);
|
||||
if (!module) fail();
|
||||
|
||||
const { account } = await makeTestAccount(source, {
|
||||
tier: 5,
|
||||
});
|
||||
const { external_id } = await makeTestUser(source, {
|
||||
account_id: account.id,
|
||||
role: USER_ROLES.TYPIST,
|
||||
encryption: false,
|
||||
prompt: false,
|
||||
});
|
||||
const { id: user2 } = await makeTestUser(source, {
|
||||
account_id: account.id,
|
||||
role: USER_ROLES.AUTHOR,
|
||||
author_id: 'AUTHOR_2',
|
||||
});
|
||||
|
||||
const worktype1 = await createWorktype(source, account.id, 'worktype1');
|
||||
await createOptionItems(source, worktype1.id);
|
||||
|
||||
await createWorkflow(source, account.id, user2, worktype1.id);
|
||||
|
||||
// 作成したデータを確認
|
||||
{
|
||||
const workflows = await getWorkflows(source, account.id);
|
||||
expect(workflows.length).toBe(1);
|
||||
expect(workflows[0].worktype_id).toBe(worktype1.id);
|
||||
expect(workflows[0].author_id).toBe(user2);
|
||||
}
|
||||
|
||||
const context = makeContext(external_id);
|
||||
|
||||
const service = module.get<UsersService>(UsersService);
|
||||
const relations = await service.getRelations(context, external_id);
|
||||
|
||||
// レスポンスを確認
|
||||
{
|
||||
expect(relations.authorId).toBe(undefined);
|
||||
expect(relations.authorIdList.length).toBe(1);
|
||||
expect(relations.authorIdList[0]).toBe('AUTHOR_2');
|
||||
expect(relations.workTypeList.length).toBe(0);
|
||||
|
||||
expect(relations.isEncrypted).toBe(false);
|
||||
expect(relations.encryptionPassword).toBe(undefined);
|
||||
expect(relations.activeWorktype).toBe('');
|
||||
expect(relations.audioFormat).toBe(USER_AUDIO_FORMAT);
|
||||
expect(relations.prompt).toBe(false);
|
||||
}
|
||||
});
|
||||
|
||||
it('ユーザーが存在しない場合は、ユーザー未存在エラー', async () => {
|
||||
if (!source) fail();
|
||||
|
||||
try {
|
||||
const module = await makeTestingModule(source);
|
||||
if (!module) fail();
|
||||
const context = makeContext(uuidv4());
|
||||
|
||||
const service = module.get<UsersService>(UsersService);
|
||||
await service.getRelations(context, 'external_id');
|
||||
fail();
|
||||
} catch (e) {
|
||||
if (e instanceof HttpException) {
|
||||
expect(e.getStatus()).toEqual(HttpStatus.BAD_REQUEST);
|
||||
expect(e.getResponse()).toEqual(makeErrorResponse('E010204'));
|
||||
} else {
|
||||
fail();
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@ -36,6 +36,8 @@ import {
|
||||
ADB2C_SIGN_IN_TYPE,
|
||||
LICENSE_EXPIRATION_THRESHOLD_DAYS,
|
||||
MANUAL_RECOVERY_REQUIRED,
|
||||
OPTION_ITEM_VALUE_TYPE_NUMBER,
|
||||
USER_AUDIO_FORMAT,
|
||||
USER_LICENSE_STATUS,
|
||||
USER_ROLES,
|
||||
} from '../../constants';
|
||||
@ -70,8 +72,10 @@ export class UsersService {
|
||||
* Confirms user
|
||||
* @param token ユーザ仮登録時に払いだされるトークン
|
||||
*/
|
||||
async confirmUser(token: string): Promise<void> {
|
||||
this.logger.log(`[IN] ${this.confirmUser.name}`);
|
||||
async confirmUser(context: Context, token: string): Promise<void> {
|
||||
this.logger.log(
|
||||
`[IN] [${context.getTrackingId()}] ${this.confirmUser.name}`,
|
||||
);
|
||||
const pubKey = getPublicKey(this.configService);
|
||||
|
||||
const decodedToken = verify<{
|
||||
@ -93,7 +97,7 @@ export class UsersService {
|
||||
userId,
|
||||
);
|
||||
} catch (e) {
|
||||
this.logger.error(e);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
if (e instanceof Error) {
|
||||
switch (e.constructor) {
|
||||
case EmailAlreadyVerifiedError:
|
||||
@ -145,14 +149,23 @@ export class UsersService {
|
||||
encryptionPassword?: string | undefined,
|
||||
prompt?: boolean | undefined,
|
||||
): Promise<void> {
|
||||
this.logger.log(`[IN] [${context.trackingId}] ${this.createUser.name}`);
|
||||
|
||||
this.logger.log(
|
||||
`[IN] [${context.getTrackingId()}] ${this.createUser.name} | params: { ` +
|
||||
`externalId: ${externalId}, ` +
|
||||
`role: ${role}, ` +
|
||||
`autoRenew: ${autoRenew}, ` +
|
||||
`licenseAlert: ${licenseAlert}, ` +
|
||||
`notification: ${notification}, ` +
|
||||
`authorId: ${authorId}, ` +
|
||||
`encryption: ${encryption}, ` +
|
||||
`prompt: ${prompt} };`,
|
||||
);
|
||||
//DBよりアクセス者の所属するアカウントIDを取得する
|
||||
let adminUser: EntityUser;
|
||||
try {
|
||||
adminUser = await this.usersRepository.findUserByExternalId(externalId);
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
@ -170,7 +183,7 @@ export class UsersService {
|
||||
authorId,
|
||||
);
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
@ -198,8 +211,10 @@ export class UsersService {
|
||||
name,
|
||||
);
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
this.logger.error('create externalUser failed');
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
this.logger.error(
|
||||
`[${context.getTrackingId()}] create externalUser failed`,
|
||||
);
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
@ -220,6 +235,7 @@ export class UsersService {
|
||||
try {
|
||||
//roleに応じてユーザー情報を作成する
|
||||
const newUserInfo = this.createNewUserInfo(
|
||||
context,
|
||||
role,
|
||||
accountId,
|
||||
externalUser.sub,
|
||||
@ -234,8 +250,8 @@ export class UsersService {
|
||||
// ユーザ作成
|
||||
newUser = await this.usersRepository.createNormalUser(newUserInfo);
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
this.logger.error('create user failed');
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
this.logger.error(`[${context.getTrackingId()}]create user failed`);
|
||||
//リカバリー処理
|
||||
//Azure AD B2Cに登録したユーザー情報を削除する
|
||||
await this.deleteB2cUser(externalUser.sub, context);
|
||||
@ -260,6 +276,7 @@ export class UsersService {
|
||||
// メールの内容を構成
|
||||
const { subject, text, html } =
|
||||
await this.sendgridService.createMailContentFromEmailConfirmForNormalUser(
|
||||
context,
|
||||
accountId,
|
||||
newUser.id,
|
||||
email,
|
||||
@ -275,8 +292,8 @@ export class UsersService {
|
||||
html,
|
||||
);
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
this.logger.error('create user failed');
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
this.logger.error(`[${context.getTrackingId()}] create user failed`);
|
||||
//リカバリー処理
|
||||
//Azure AD B2Cに登録したユーザー情報を削除する
|
||||
await this.deleteB2cUser(externalUser.sub, context);
|
||||
@ -287,7 +304,9 @@ export class UsersService {
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
this.logger.log(`[OUT] ${this.createUser.name}`);
|
||||
this.logger.log(
|
||||
`[OUT] [${context.getTrackingId()}] ${this.createUser.name}`,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -297,12 +316,12 @@ export class UsersService {
|
||||
try {
|
||||
await this.adB2cService.deleteUser(externalUserId, context);
|
||||
this.logger.log(
|
||||
`[${context.trackingId}] delete externalUser: ${externalUserId}`,
|
||||
`[${context.getTrackingId()}] delete externalUser: ${externalUserId}`,
|
||||
);
|
||||
} catch (error) {
|
||||
this.logger.error(`error=${error}`);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${error}`);
|
||||
this.logger.error(
|
||||
`${MANUAL_RECOVERY_REQUIRED} [${context.trackingId}] Failed to delete externalUser: ${externalUserId}`,
|
||||
`${MANUAL_RECOVERY_REQUIRED} [${context.getTrackingId()}] Failed to delete externalUser: ${externalUserId}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -311,17 +330,18 @@ export class UsersService {
|
||||
private async deleteUser(userId: number, context: Context) {
|
||||
try {
|
||||
await this.usersRepository.deleteNormalUser(userId);
|
||||
this.logger.log(`[${context.trackingId}] delete user: ${userId}`);
|
||||
this.logger.log(`[${context.getTrackingId()}] delete user: ${userId}`);
|
||||
} catch (error) {
|
||||
this.logger.error(`error=${error}`);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${error}`);
|
||||
this.logger.error(
|
||||
`${MANUAL_RECOVERY_REQUIRED} [${context.trackingId}] Failed to delete user: ${userId}`,
|
||||
`${MANUAL_RECOVERY_REQUIRED} [${context.getTrackingId()}] Failed to delete user: ${userId}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// roleを受け取って、roleに応じたnewUserを作成して返却する
|
||||
private createNewUserInfo(
|
||||
context: Context,
|
||||
role: UserRoles,
|
||||
accountId: number,
|
||||
externalId: string,
|
||||
@ -333,6 +353,21 @@ export class UsersService {
|
||||
encryptionPassword?: string | undefined,
|
||||
prompt?: boolean | undefined,
|
||||
): newUser {
|
||||
this.logger.log(
|
||||
`[IN] [${context.getTrackingId()}] ${
|
||||
this.createNewUserInfo.name
|
||||
} | params: { ` +
|
||||
`role: ${role}, ` +
|
||||
`accountId: ${accountId}, ` +
|
||||
`authorId: ${authorId}, ` +
|
||||
`externalId: ${externalId}, ` +
|
||||
`autoRenew: ${autoRenew}, ` +
|
||||
`licenseAlert: ${licenseAlert}, ` +
|
||||
`notification: ${notification}, ` +
|
||||
`authorId: ${authorId}, ` +
|
||||
`encryption: ${encryption}, ` +
|
||||
`prompt: ${prompt} };`,
|
||||
);
|
||||
switch (role) {
|
||||
case USER_ROLES.NONE:
|
||||
case USER_ROLES.TYPIST:
|
||||
@ -367,7 +402,9 @@ export class UsersService {
|
||||
};
|
||||
default:
|
||||
//不正なroleが指定された場合はログを出力してエラーを返す
|
||||
this.logger.error(`[NOT IMPLEMENT] [RECOVER] role: ${role}`);
|
||||
this.logger.error(
|
||||
`[${context.getTrackingId()}] [NOT IMPLEMENT] [RECOVER] role: ${role}`,
|
||||
);
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
@ -384,7 +421,9 @@ export class UsersService {
|
||||
token: string,
|
||||
): Promise<void> {
|
||||
this.logger.log(
|
||||
`[IN] [${context.trackingId}] ${this.confirmUserAndInitPassword.name}`,
|
||||
`[IN] [${context.getTrackingId()}] ${
|
||||
this.confirmUserAndInitPassword.name
|
||||
}`,
|
||||
);
|
||||
|
||||
const pubKey = getPublicKey(this.configService);
|
||||
@ -410,7 +449,11 @@ export class UsersService {
|
||||
const user = await this.usersRepository.findUserById(userId);
|
||||
const extarnalId = user.external_id;
|
||||
// パスワードを変更する
|
||||
await this.adB2cService.changePassword(extarnalId, ramdomPassword);
|
||||
await this.adB2cService.changePassword(
|
||||
context,
|
||||
extarnalId,
|
||||
ramdomPassword,
|
||||
);
|
||||
// ユーザを認証済みにする
|
||||
await this.usersRepository.updateUserVerified(userId);
|
||||
// TODO [Task2163] ODMS側が正式にメッセージを決めるまで仮のメール内容とする
|
||||
@ -428,7 +471,7 @@ export class UsersService {
|
||||
html,
|
||||
);
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
if (e instanceof Error) {
|
||||
switch (e.constructor) {
|
||||
case EmailAlreadyVerifiedError:
|
||||
@ -451,8 +494,8 @@ export class UsersService {
|
||||
* @param accessToken
|
||||
* @returns users
|
||||
*/
|
||||
async getUsers(externalId: string): Promise<User[]> {
|
||||
this.logger.log(`[IN] ${this.getUsers.name}`);
|
||||
async getUsers(context: Context, externalId: string): Promise<User[]> {
|
||||
this.logger.log(`[IN] [${context.getTrackingId()}] ${this.getUsers.name}`);
|
||||
|
||||
try {
|
||||
// DBから同一アカウントのユーザ一覧を取得する
|
||||
@ -462,9 +505,10 @@ export class UsersService {
|
||||
|
||||
// DBから取得したユーザーの外部IDをもとにADB2Cからユーザーを取得する
|
||||
const externalIds = dbUsers.map((x) => x.external_id);
|
||||
const trackingId = new Context(context.trackingId);
|
||||
const adb2cUsers = await this.adB2cService.getUsers(
|
||||
// TODO: 外部連携以外のログ強化時に、ContollerからContextを取得するように修正する
|
||||
{ trackingId: 'dummy' },
|
||||
trackingId,
|
||||
externalIds,
|
||||
);
|
||||
|
||||
@ -552,13 +596,15 @@ export class UsersService {
|
||||
|
||||
return users;
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
HttpStatus.NOT_FOUND,
|
||||
);
|
||||
} finally {
|
||||
this.logger.log(`[OUT] ${this.getUsers.name}`);
|
||||
this.logger.log(
|
||||
`[OUT] [${context.getTrackingId()}] ${this.getUsers.name}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
/**
|
||||
@ -569,17 +615,22 @@ export class UsersService {
|
||||
* @returns sort criteria
|
||||
*/
|
||||
async updateSortCriteria(
|
||||
context: Context,
|
||||
paramName: TaskListSortableAttribute,
|
||||
direction: SortDirection,
|
||||
externalId: string,
|
||||
): Promise<void> {
|
||||
this.logger.log(`[IN] ${this.updateSortCriteria.name}`);
|
||||
this.logger.log(
|
||||
`[IN] [${context.getTrackingId()}] ${
|
||||
this.updateSortCriteria.name
|
||||
} | params: { paramName: ${paramName}, direction: ${direction}, externalId: ${externalId} };`,
|
||||
);
|
||||
let user: EntityUser;
|
||||
try {
|
||||
// ユーザー情報を取得
|
||||
user = await this.usersRepository.findUserByExternalId(externalId);
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
@ -595,13 +646,15 @@ export class UsersService {
|
||||
direction,
|
||||
);
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
} finally {
|
||||
this.logger.log(`[OUT] ${this.updateSortCriteria.name}`);
|
||||
this.logger.log(
|
||||
`[OUT] [${context.getTrackingId()}] ${this.updateSortCriteria.name}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
/**
|
||||
@ -609,17 +662,24 @@ export class UsersService {
|
||||
* @param token
|
||||
* @returns sort criteria
|
||||
*/
|
||||
async getSortCriteria(externalId: string): Promise<{
|
||||
async getSortCriteria(
|
||||
context: Context,
|
||||
externalId: string,
|
||||
): Promise<{
|
||||
paramName: TaskListSortableAttribute;
|
||||
direction: SortDirection;
|
||||
}> {
|
||||
this.logger.log(`[IN] ${this.getSortCriteria.name}`);
|
||||
this.logger.log(
|
||||
`[IN] [${context.getTrackingId()}] ${
|
||||
this.getSortCriteria.name
|
||||
} | params: { externalId: ${externalId} };`,
|
||||
);
|
||||
let user: EntityUser;
|
||||
try {
|
||||
// ユーザー情報を取得
|
||||
user = await this.usersRepository.findUserByExternalId(externalId);
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
@ -642,13 +702,15 @@ export class UsersService {
|
||||
}
|
||||
return { direction, paramName: parameter };
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
} finally {
|
||||
this.logger.log(`[OUT] ${this.getSortCriteria.name}`);
|
||||
this.logger.log(
|
||||
`[OUT] [${context.getTrackingId()}] ${this.getSortCriteria.name}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -661,134 +723,73 @@ export class UsersService {
|
||||
context: Context,
|
||||
userId: string,
|
||||
): Promise<GetRelationsResponse> {
|
||||
this.logger.log(`[IN] [${context.trackingId}] ${this.getRelations.name}`);
|
||||
this.logger.log(
|
||||
`[IN] [${context.getTrackingId()}] ${
|
||||
this.getRelations.name
|
||||
} | params: { userId: ${userId} };`,
|
||||
);
|
||||
try {
|
||||
const user = await this.usersRepository.findUserByExternalId(userId);
|
||||
const { id } = await this.usersRepository.findUserByExternalId(userId);
|
||||
|
||||
// ユーザー関連情報を取得
|
||||
const { user, authors, worktypes, activeWorktype } =
|
||||
await this.usersRepository.getUserRelations(id);
|
||||
|
||||
// AuthorIDのリストを作成
|
||||
const authorIds = authors.flatMap((author) =>
|
||||
author.author_id ? [author.author_id] : [],
|
||||
);
|
||||
|
||||
const workTypeList = worktypes?.map((worktype) => {
|
||||
return {
|
||||
workTypeId: worktype.custom_worktype_id,
|
||||
optionItemList: worktype.option_items.map((optionItem) => {
|
||||
const initialValueType = OPTION_ITEM_VALUE_TYPE_NUMBER.find(
|
||||
(x) => x.type === optionItem.default_value_type,
|
||||
)?.value;
|
||||
|
||||
if (!initialValueType) {
|
||||
throw new Error(
|
||||
`invalid default_value_type ${optionItem.default_value_type}`,
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
label: optionItem.item_label,
|
||||
initialValueType,
|
||||
defaultValue: optionItem.initial_value,
|
||||
};
|
||||
}),
|
||||
};
|
||||
});
|
||||
|
||||
// TODO: PBI2105 本実装時に修正すること
|
||||
return {
|
||||
authorId: user.author_id ?? '',
|
||||
authorIdList: [user.author_id ?? '', 'XXX'],
|
||||
isEncrypted: true,
|
||||
encryptionPassword: 'abcd@123?dcba',
|
||||
audioFormat: 'DS2(QP)',
|
||||
prompt: true,
|
||||
workTypeList: [
|
||||
{
|
||||
workTypeId: 'workType1',
|
||||
optionItemList: [
|
||||
{
|
||||
label: 'optionItem11',
|
||||
initialValueType: 2,
|
||||
defaultValue: 'default11',
|
||||
},
|
||||
{
|
||||
label: 'optionItem12',
|
||||
initialValueType: 2,
|
||||
defaultValue: 'default12',
|
||||
},
|
||||
{
|
||||
label: 'optionItem13',
|
||||
initialValueType: 2,
|
||||
defaultValue: 'default13',
|
||||
},
|
||||
{
|
||||
label: 'optionItem14',
|
||||
initialValueType: 2,
|
||||
defaultValue: 'default14',
|
||||
},
|
||||
{
|
||||
label: 'optionItem15',
|
||||
initialValueType: 2,
|
||||
defaultValue: 'default15',
|
||||
},
|
||||
{
|
||||
label: 'optionItem16',
|
||||
initialValueType: 2,
|
||||
defaultValue: 'default16',
|
||||
},
|
||||
{
|
||||
label: 'optionItem17',
|
||||
initialValueType: 2,
|
||||
defaultValue: 'default17',
|
||||
},
|
||||
{
|
||||
label: 'optionItem18',
|
||||
initialValueType: 2,
|
||||
defaultValue: 'default18',
|
||||
},
|
||||
{
|
||||
label: 'optionItem19',
|
||||
initialValueType: 1,
|
||||
defaultValue: '',
|
||||
},
|
||||
{
|
||||
label: 'optionItem110',
|
||||
initialValueType: 3,
|
||||
defaultValue: '',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
workTypeId: 'workType2',
|
||||
optionItemList: [
|
||||
{
|
||||
label: 'optionItem21',
|
||||
initialValueType: 2,
|
||||
defaultValue: 'default21',
|
||||
},
|
||||
{
|
||||
label: 'optionItem22',
|
||||
initialValueType: 2,
|
||||
defaultValue: 'default22',
|
||||
},
|
||||
{
|
||||
label: 'optionItem23',
|
||||
initialValueType: 2,
|
||||
defaultValue: 'defaul23',
|
||||
},
|
||||
{
|
||||
label: 'optionItem24',
|
||||
initialValueType: 2,
|
||||
defaultValue: 'default24',
|
||||
},
|
||||
{
|
||||
label: 'optionItem25',
|
||||
initialValueType: 2,
|
||||
defaultValue: 'default25',
|
||||
},
|
||||
{
|
||||
label: 'optionItem26',
|
||||
initialValueType: 2,
|
||||
defaultValue: 'default26',
|
||||
},
|
||||
{
|
||||
label: 'optionItem27',
|
||||
initialValueType: 2,
|
||||
defaultValue: 'default27',
|
||||
},
|
||||
{
|
||||
label: 'optionItem28',
|
||||
initialValueType: 2,
|
||||
defaultValue: 'default28',
|
||||
},
|
||||
{
|
||||
label: 'optionItem29',
|
||||
initialValueType: 1,
|
||||
defaultValue: '',
|
||||
},
|
||||
{
|
||||
label: 'optionItem210',
|
||||
initialValueType: 3,
|
||||
defaultValue: '',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
activeWorktype: 'workType1',
|
||||
authorId: user.author_id ?? undefined,
|
||||
authorIdList: authorIds,
|
||||
workTypeList,
|
||||
isEncrypted: user.encryption,
|
||||
encryptionPassword: user.encryption_password ?? undefined,
|
||||
activeWorktype: activeWorktype?.custom_worktype_id ?? '',
|
||||
audioFormat: USER_AUDIO_FORMAT,
|
||||
prompt: user.prompt,
|
||||
};
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
|
||||
if (e instanceof Error) {
|
||||
switch (e.constructor) {
|
||||
case UserNotFoundError:
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E010204'),
|
||||
HttpStatus.BAD_REQUEST,
|
||||
);
|
||||
default:
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
@ -796,7 +797,7 @@ export class UsersService {
|
||||
);
|
||||
} finally {
|
||||
this.logger.log(
|
||||
`[OUT] [${context.trackingId}] ${this.getRelations.name}`,
|
||||
`[OUT] [${context.getTrackingId()}] ${this.getRelations.name}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -831,14 +832,17 @@ export class UsersService {
|
||||
): Promise<void> {
|
||||
try {
|
||||
this.logger.log(
|
||||
`[IN] [${context.trackingId}] ${this.updateUser.name} | params: { ` +
|
||||
`[IN] [${context.getTrackingId()}] ${
|
||||
this.updateUser.name
|
||||
} | params: { ` +
|
||||
`extarnalId: ${extarnalId}, ` +
|
||||
`id: ${id}, ` +
|
||||
`role: ${role}, ` +
|
||||
`authorId: ${authorId}, ` +
|
||||
`autoRenew: ${autoRenew}, ` +
|
||||
`licenseAlart: ${licenseAlart}, ` +
|
||||
`notification: ${notification}, ` +
|
||||
`encryption: ${encryption}, ` +
|
||||
`encryptionPassword: ********, ` +
|
||||
`prompt: ${prompt} }`,
|
||||
);
|
||||
|
||||
@ -861,7 +865,7 @@ export class UsersService {
|
||||
prompt,
|
||||
);
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
if (e instanceof Error) {
|
||||
switch (e.constructor) {
|
||||
case UserNotFoundError:
|
||||
@ -896,7 +900,9 @@ export class UsersService {
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
} finally {
|
||||
this.logger.log(`[OUT] [${context.trackingId}] ${this.updateUser.name}`);
|
||||
this.logger.log(
|
||||
`[OUT] [${context.getTrackingId()}] ${this.updateUser.name}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -912,7 +918,9 @@ export class UsersService {
|
||||
newLicenseId: number,
|
||||
): Promise<void> {
|
||||
this.logger.log(
|
||||
`[IN] [${context.trackingId}] ${this.allocateLicense.name} | params: { ` +
|
||||
`[IN] [${context.getTrackingId()}] ${
|
||||
this.allocateLicense.name
|
||||
} | params: { ` +
|
||||
`userId: ${userId}, ` +
|
||||
`newLicenseId: ${newLicenseId}, };`,
|
||||
);
|
||||
@ -927,7 +935,7 @@ export class UsersService {
|
||||
accountId,
|
||||
);
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
if (e instanceof Error) {
|
||||
switch (e.constructor) {
|
||||
case LicenseExpiredError:
|
||||
@ -949,7 +957,7 @@ export class UsersService {
|
||||
}
|
||||
} finally {
|
||||
this.logger.log(
|
||||
`[OUT] [${context.trackingId}] ${this.allocateLicense.name}`,
|
||||
`[OUT] [${context.getTrackingId()}] ${this.allocateLicense.name}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -961,8 +969,9 @@ export class UsersService {
|
||||
*/
|
||||
async deallocateLicense(context: Context, userId: number): Promise<void> {
|
||||
this.logger.log(
|
||||
`[IN] [${context.trackingId}] ${this.deallocateLicense.name} | params: { ` +
|
||||
`userId: ${userId}, };`,
|
||||
`[IN] [${context.getTrackingId()}] ${
|
||||
this.deallocateLicense.name
|
||||
} | params: { ` + `userId: ${userId}, };`,
|
||||
);
|
||||
|
||||
try {
|
||||
@ -971,7 +980,7 @@ export class UsersService {
|
||||
|
||||
await this.licensesRepository.deallocateLicense(userId, accountId);
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
if (e instanceof Error) {
|
||||
switch (e.constructor) {
|
||||
case LicenseAlreadyDeallocatedError:
|
||||
@ -988,7 +997,7 @@ export class UsersService {
|
||||
}
|
||||
} finally {
|
||||
this.logger.log(
|
||||
`[OUT] [${context.trackingId}] ${this.deallocateLicense.name}`,
|
||||
`[OUT] [${context.getTrackingId()}] ${this.deallocateLicense.name}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -1007,7 +1016,9 @@ export class UsersService {
|
||||
dpaVersion?: string,
|
||||
): Promise<void> {
|
||||
this.logger.log(
|
||||
`[IN] [${context.trackingId}] ${this.updateAcceptedVersion.name} | params: { ` +
|
||||
`[IN] [${context.getTrackingId()}] ${
|
||||
this.updateAcceptedVersion.name
|
||||
} | params: { ` +
|
||||
`externalId: ${externalId}, ` +
|
||||
`eulaVersion: ${eulaVersion}, ` +
|
||||
`dpaVersion: ${dpaVersion}, };`,
|
||||
@ -1020,7 +1031,7 @@ export class UsersService {
|
||||
dpaVersion,
|
||||
);
|
||||
} catch (e) {
|
||||
this.logger.error(`[${context.trackingId}] error=${e}`);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
if (e instanceof Error) {
|
||||
switch (e.constructor) {
|
||||
case UserNotFoundError:
|
||||
@ -1047,7 +1058,7 @@ export class UsersService {
|
||||
}
|
||||
} finally {
|
||||
this.logger.log(
|
||||
`[OUT] [${context.trackingId}] ${this.updateAcceptedVersion.name}`,
|
||||
`[OUT] [${context.getTrackingId()}] ${this.updateAcceptedVersion.name}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -1057,16 +1068,20 @@ export class UsersService {
|
||||
* @param externalId
|
||||
*/
|
||||
async getUserName(context: Context, externalId: string): Promise<string> {
|
||||
this.logger.log(`[IN] [${context.trackingId}] ${this.getUserName.name}`);
|
||||
this.logger.log(
|
||||
`[IN] [${context.getTrackingId()}] ${
|
||||
this.getUserName.name
|
||||
} | params: { externalId: ${externalId} };`,
|
||||
);
|
||||
|
||||
try {
|
||||
// extarnalIdの存在チェックを行う
|
||||
await this.usersRepository.findUserByExternalId(externalId);
|
||||
// ADB2Cからユーザー名を取得する
|
||||
const adb2cUser = await this.adB2cService.getUser(externalId);
|
||||
const adb2cUser = await this.adB2cService.getUser(context, externalId);
|
||||
return adb2cUser.displayName;
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
if (e instanceof Error) {
|
||||
switch (e.constructor) {
|
||||
case UserNotFoundError:
|
||||
@ -1086,7 +1101,9 @@ export class UsersService {
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
} finally {
|
||||
this.logger.log(`[OUT] [${context.trackingId}] ${this.getUserName.name}`);
|
||||
this.logger.log(
|
||||
`[OUT] [${context.getTrackingId()}] ${this.getUserName.name}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -588,6 +588,56 @@ describe('createWorkflows', () => {
|
||||
}
|
||||
});
|
||||
|
||||
it('Authorがメール未認証の場合、400エラーとなること', async () => {
|
||||
if (!source) fail();
|
||||
const module = await makeTestingModule(source);
|
||||
if (!module) fail();
|
||||
// 第五階層のアカウント作成
|
||||
const { account, admin } = await makeTestAccount(source, { tier: 5 });
|
||||
const { id: authorId } = await makeTestUser(source, {
|
||||
external_id: 'author1',
|
||||
author_id: 'AUTHOR1',
|
||||
account_id: account.id,
|
||||
role: USER_ROLES.AUTHOR,
|
||||
email_verified: false,
|
||||
});
|
||||
const { id: typistId } = await makeTestUser(source, {
|
||||
external_id: 'typist1',
|
||||
account_id: account.id,
|
||||
role: USER_ROLES.TYPIST,
|
||||
});
|
||||
|
||||
//作成したデータを確認
|
||||
{
|
||||
const workflows = await getWorkflows(source, account.id);
|
||||
const workflowTypists = await getAllWorkflowTypists(source);
|
||||
expect(workflows.length).toBe(0);
|
||||
expect(workflowTypists.length).toBe(0);
|
||||
}
|
||||
|
||||
const service = module.get<WorkflowsService>(WorkflowsService);
|
||||
const context = makeContext(admin.external_id);
|
||||
//実行結果を確認
|
||||
try {
|
||||
await service.createWorkflow(
|
||||
context,
|
||||
admin.external_id,
|
||||
authorId,
|
||||
[{ typistId: typistId }],
|
||||
undefined,
|
||||
undefined,
|
||||
);
|
||||
fail();
|
||||
} catch (e) {
|
||||
if (e instanceof HttpException) {
|
||||
expect(e.getStatus()).toEqual(HttpStatus.BAD_REQUEST);
|
||||
expect(e.getResponse()).toEqual(makeErrorResponse('E010204'));
|
||||
} else {
|
||||
fail();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it('DBにAuthorが存在しない場合、400エラーとなること', async () => {
|
||||
if (!source) fail();
|
||||
const module = await makeTestingModule(source);
|
||||
@ -639,6 +689,7 @@ describe('createWorkflows', () => {
|
||||
worktypeId,
|
||||
templateId,
|
||||
);
|
||||
fail();
|
||||
} catch (e) {
|
||||
if (e instanceof HttpException) {
|
||||
expect(e.getStatus()).toEqual(HttpStatus.BAD_REQUEST);
|
||||
@ -699,6 +750,7 @@ describe('createWorkflows', () => {
|
||||
9999,
|
||||
templateId,
|
||||
);
|
||||
fail();
|
||||
} catch (e) {
|
||||
if (e instanceof HttpException) {
|
||||
expect(e.getStatus()).toEqual(HttpStatus.BAD_REQUEST);
|
||||
@ -758,6 +810,7 @@ describe('createWorkflows', () => {
|
||||
worktypeId,
|
||||
9999,
|
||||
);
|
||||
fail();
|
||||
} catch (e) {
|
||||
if (e instanceof HttpException) {
|
||||
expect(e.getStatus()).toEqual(HttpStatus.BAD_REQUEST);
|
||||
@ -819,6 +872,75 @@ describe('createWorkflows', () => {
|
||||
worktypeId,
|
||||
templateId,
|
||||
);
|
||||
fail();
|
||||
} catch (e) {
|
||||
if (e instanceof HttpException) {
|
||||
expect(e.getStatus()).toEqual(HttpStatus.BAD_REQUEST);
|
||||
expect(e.getResponse()).toEqual(makeErrorResponse('E010204'));
|
||||
} else {
|
||||
fail();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it('ルーティング候補ユーザーがメール未認証の場合、400エラーとなること', async () => {
|
||||
if (!source) fail();
|
||||
const module = await makeTestingModule(source);
|
||||
if (!module) fail();
|
||||
// 第五階層のアカウント作成
|
||||
const { account, admin } = await makeTestAccount(source, { tier: 5 });
|
||||
const { id: authorId } = await makeTestUser(source, {
|
||||
external_id: 'author1',
|
||||
author_id: 'AUTHOR1',
|
||||
account_id: account.id,
|
||||
role: USER_ROLES.AUTHOR,
|
||||
});
|
||||
const { id: typistId } = await makeTestUser(source, {
|
||||
external_id: 'typist1',
|
||||
account_id: account.id,
|
||||
role: USER_ROLES.TYPIST,
|
||||
email_verified: false,
|
||||
});
|
||||
|
||||
const { id: worktypeId } = await createWorktype(
|
||||
source,
|
||||
account.id,
|
||||
'worktype1',
|
||||
);
|
||||
|
||||
const { id: templateId } = await createTemplateFile(
|
||||
source,
|
||||
account.id,
|
||||
'fileName1',
|
||||
'url1',
|
||||
);
|
||||
|
||||
//作成したデータを確認
|
||||
{
|
||||
const workflows = await getWorkflows(source, account.id);
|
||||
const workflowTypists = await getAllWorkflowTypists(source);
|
||||
expect(workflows.length).toBe(0);
|
||||
expect(workflowTypists.length).toBe(0);
|
||||
}
|
||||
|
||||
const service = module.get<WorkflowsService>(WorkflowsService);
|
||||
const context = makeContext(admin.external_id);
|
||||
|
||||
//実行結果を確認
|
||||
try {
|
||||
await service.createWorkflow(
|
||||
context,
|
||||
admin.external_id,
|
||||
authorId,
|
||||
[
|
||||
{
|
||||
typistId: typistId,
|
||||
},
|
||||
],
|
||||
worktypeId,
|
||||
templateId,
|
||||
);
|
||||
fail();
|
||||
} catch (e) {
|
||||
if (e instanceof HttpException) {
|
||||
expect(e.getStatus()).toEqual(HttpStatus.BAD_REQUEST);
|
||||
@ -880,6 +1002,7 @@ describe('createWorkflows', () => {
|
||||
worktypeId,
|
||||
templateId,
|
||||
);
|
||||
fail();
|
||||
} catch (e) {
|
||||
if (e instanceof HttpException) {
|
||||
expect(e.getStatus()).toEqual(HttpStatus.BAD_REQUEST);
|
||||
@ -950,6 +1073,7 @@ describe('createWorkflows', () => {
|
||||
worktypeId,
|
||||
templateId,
|
||||
);
|
||||
fail();
|
||||
} catch (e) {
|
||||
if (e instanceof HttpException) {
|
||||
expect(e.getStatus()).toEqual(HttpStatus.BAD_REQUEST);
|
||||
@ -1024,6 +1148,7 @@ describe('createWorkflows', () => {
|
||||
worktypeId,
|
||||
templateId,
|
||||
);
|
||||
fail();
|
||||
} catch (e) {
|
||||
if (e instanceof HttpException) {
|
||||
expect(e.getStatus()).toEqual(HttpStatus.INTERNAL_SERVER_ERROR);
|
||||
@ -1514,6 +1639,78 @@ describe('updateWorkflow', () => {
|
||||
}
|
||||
});
|
||||
|
||||
it('Authorがメール未認証の場合、400エラーとなること', async () => {
|
||||
if (!source) fail();
|
||||
const module = await makeTestingModule(source);
|
||||
if (!module) fail();
|
||||
// 第五階層のアカウント作成
|
||||
const { account, admin } = await makeTestAccount(source, { tier: 5 });
|
||||
const { id: authorId1 } = await makeTestUser(source, {
|
||||
external_id: 'author1',
|
||||
author_id: 'AUTHOR1',
|
||||
account_id: account.id,
|
||||
role: USER_ROLES.AUTHOR,
|
||||
});
|
||||
const { id: authorId2 } = await makeTestUser(source, {
|
||||
external_id: 'author2',
|
||||
author_id: 'AUTHOR2',
|
||||
account_id: account.id,
|
||||
role: USER_ROLES.AUTHOR,
|
||||
email_verified: false,
|
||||
});
|
||||
const { id: typistId1 } = await makeTestUser(source, {
|
||||
external_id: 'typist1',
|
||||
account_id: account.id,
|
||||
role: USER_ROLES.TYPIST,
|
||||
});
|
||||
|
||||
const preWorkflow = await createWorkflow(
|
||||
source,
|
||||
account.id,
|
||||
authorId1,
|
||||
undefined,
|
||||
undefined,
|
||||
);
|
||||
await createWorkflowTypist(source, preWorkflow.id, typistId1);
|
||||
|
||||
//作成したデータを確認
|
||||
{
|
||||
const workflows = await getWorkflows(source, account.id);
|
||||
const workflowTypists = await getAllWorkflowTypists(source);
|
||||
expect(workflows.length).toBe(1);
|
||||
expect(workflows[0].id).toBe(preWorkflow.id);
|
||||
expect(workflows[0].account_id).toBe(account.id);
|
||||
expect(workflows[0].author_id).toBe(authorId1);
|
||||
expect(workflows[0].worktype_id).toBe(null);
|
||||
expect(workflows[0].template_id).toBe(null);
|
||||
expect(workflowTypists.length).toBe(1);
|
||||
}
|
||||
|
||||
const service = module.get<WorkflowsService>(WorkflowsService);
|
||||
const context = makeContext(admin.external_id);
|
||||
|
||||
//実行結果を確認
|
||||
try {
|
||||
await service.updateWorkflow(
|
||||
context,
|
||||
admin.external_id,
|
||||
preWorkflow.id,
|
||||
authorId2,
|
||||
[{ typistId: typistId1 }],
|
||||
undefined,
|
||||
undefined,
|
||||
);
|
||||
fail();
|
||||
} catch (e) {
|
||||
if (e instanceof HttpException) {
|
||||
expect(e.getStatus()).toEqual(HttpStatus.BAD_REQUEST);
|
||||
expect(e.getResponse()).toEqual(makeErrorResponse('E010204'));
|
||||
} else {
|
||||
fail();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it('DBにWorkflowが存在しない場合、400エラーとなること', async () => {
|
||||
if (!source) fail();
|
||||
const module = await makeTestingModule(source);
|
||||
@ -1550,6 +1747,7 @@ describe('updateWorkflow', () => {
|
||||
undefined,
|
||||
undefined,
|
||||
);
|
||||
fail();
|
||||
} catch (e) {
|
||||
if (e instanceof HttpException) {
|
||||
expect(e.getStatus()).toEqual(HttpStatus.BAD_REQUEST);
|
||||
@ -1623,6 +1821,7 @@ describe('updateWorkflow', () => {
|
||||
worktypeId,
|
||||
templateId,
|
||||
);
|
||||
fail();
|
||||
} catch (e) {
|
||||
if (e instanceof HttpException) {
|
||||
expect(e.getStatus()).toEqual(HttpStatus.BAD_REQUEST);
|
||||
@ -1691,6 +1890,7 @@ describe('updateWorkflow', () => {
|
||||
9999,
|
||||
templateId,
|
||||
);
|
||||
fail();
|
||||
} catch (e) {
|
||||
if (e instanceof HttpException) {
|
||||
expect(e.getStatus()).toEqual(HttpStatus.BAD_REQUEST);
|
||||
@ -1758,6 +1958,7 @@ describe('updateWorkflow', () => {
|
||||
worktypeId,
|
||||
9999,
|
||||
);
|
||||
fail();
|
||||
} catch (e) {
|
||||
if (e instanceof HttpException) {
|
||||
expect(e.getStatus()).toEqual(HttpStatus.BAD_REQUEST);
|
||||
@ -1832,6 +2033,88 @@ describe('updateWorkflow', () => {
|
||||
worktypeId,
|
||||
templateId,
|
||||
);
|
||||
fail();
|
||||
} catch (e) {
|
||||
if (e instanceof HttpException) {
|
||||
expect(e.getStatus()).toEqual(HttpStatus.BAD_REQUEST);
|
||||
expect(e.getResponse()).toEqual(makeErrorResponse('E010204'));
|
||||
} else {
|
||||
fail();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it('Dルーティング候補ユーザーがメール未認証の場合、400エラーとなること', async () => {
|
||||
if (!source) fail();
|
||||
const module = await makeTestingModule(source);
|
||||
if (!module) fail();
|
||||
// 第五階層のアカウント作成
|
||||
const { account, admin } = await makeTestAccount(source, { tier: 5 });
|
||||
const { id: authorId1 } = await makeTestUser(source, {
|
||||
external_id: 'author1',
|
||||
author_id: 'AUTHOR1',
|
||||
account_id: account.id,
|
||||
role: USER_ROLES.AUTHOR,
|
||||
});
|
||||
const { id: typistId1 } = await makeTestUser(source, {
|
||||
external_id: 'typist1',
|
||||
account_id: account.id,
|
||||
role: USER_ROLES.TYPIST,
|
||||
});
|
||||
const { id: typistId2 } = await makeTestUser(source, {
|
||||
external_id: 'typist2',
|
||||
account_id: account.id,
|
||||
role: USER_ROLES.TYPIST,
|
||||
email_verified: false,
|
||||
});
|
||||
|
||||
const { id: worktypeId } = await createWorktype(
|
||||
source,
|
||||
account.id,
|
||||
'worktype1',
|
||||
);
|
||||
|
||||
const { id: templateId } = await createTemplateFile(
|
||||
source,
|
||||
account.id,
|
||||
'fileName1',
|
||||
'url1',
|
||||
);
|
||||
|
||||
const preWorkflow = await createWorkflow(
|
||||
source,
|
||||
account.id,
|
||||
authorId1,
|
||||
undefined,
|
||||
undefined,
|
||||
);
|
||||
await createWorkflowTypist(source, preWorkflow.id, typistId1);
|
||||
|
||||
//作成したデータを確認
|
||||
{
|
||||
const workflows = await getWorkflows(source, account.id);
|
||||
expect(workflows.length).toBe(1);
|
||||
}
|
||||
|
||||
const service = module.get<WorkflowsService>(WorkflowsService);
|
||||
const context = makeContext(admin.external_id);
|
||||
|
||||
//実行結果を確認
|
||||
try {
|
||||
await service.updateWorkflow(
|
||||
context,
|
||||
admin.external_id,
|
||||
preWorkflow.id,
|
||||
authorId1,
|
||||
[
|
||||
{
|
||||
typistId: typistId2,
|
||||
},
|
||||
],
|
||||
worktypeId,
|
||||
templateId,
|
||||
);
|
||||
fail();
|
||||
} catch (e) {
|
||||
if (e instanceof HttpException) {
|
||||
expect(e.getStatus()).toEqual(HttpStatus.BAD_REQUEST);
|
||||
@ -1906,6 +2189,7 @@ describe('updateWorkflow', () => {
|
||||
worktypeId,
|
||||
templateId,
|
||||
);
|
||||
fail();
|
||||
} catch (e) {
|
||||
if (e instanceof HttpException) {
|
||||
expect(e.getStatus()).toEqual(HttpStatus.BAD_REQUEST);
|
||||
@ -1974,6 +2258,7 @@ describe('updateWorkflow', () => {
|
||||
worktypeId1,
|
||||
undefined,
|
||||
);
|
||||
fail();
|
||||
} catch (e) {
|
||||
if (e instanceof HttpException) {
|
||||
expect(e.getStatus()).toEqual(HttpStatus.BAD_REQUEST);
|
||||
@ -2050,6 +2335,7 @@ describe('updateWorkflow', () => {
|
||||
undefined,
|
||||
undefined,
|
||||
);
|
||||
fail();
|
||||
} catch (e) {
|
||||
if (e instanceof HttpException) {
|
||||
expect(e.getStatus()).toEqual(HttpStatus.INTERNAL_SERVER_ERROR);
|
||||
|
||||
@ -35,7 +35,9 @@ export class WorkflowsService {
|
||||
externalId: string,
|
||||
): Promise<Workflow[]> {
|
||||
this.logger.log(
|
||||
`[IN] [${context.trackingId}] ${this.getWorkflows.name} | params: { externalId: ${externalId} };`,
|
||||
`[IN] [${context.getTrackingId()}] ${
|
||||
this.getWorkflows.name
|
||||
} | params: { externalId: ${externalId} };`,
|
||||
);
|
||||
try {
|
||||
const { account_id: accountId } =
|
||||
@ -121,14 +123,14 @@ export class WorkflowsService {
|
||||
|
||||
return workflows;
|
||||
} catch (e) {
|
||||
this.logger.error(`[${context.trackingId}] error=${e}`);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
} finally {
|
||||
this.logger.log(
|
||||
`[OUT] [${context.trackingId}] ${this.getWorkflows.name}`,
|
||||
`[OUT] [${context.getTrackingId()}] ${this.getWorkflows.name}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -152,7 +154,9 @@ export class WorkflowsService {
|
||||
templateId?: number | undefined,
|
||||
): Promise<void> {
|
||||
this.logger.log(
|
||||
`[IN] [${context.trackingId}] ${this.createWorkflow.name} | | params: { ` +
|
||||
`[IN] [${context.getTrackingId()}] ${
|
||||
this.createWorkflow.name
|
||||
} | params: { ` +
|
||||
`externalId: ${externalId}, ` +
|
||||
`authorId: ${authorId}, ` +
|
||||
`worktypeId: ${worktypeId}, ` +
|
||||
@ -171,7 +175,7 @@ export class WorkflowsService {
|
||||
templateId,
|
||||
);
|
||||
} catch (e) {
|
||||
this.logger.error(`[${context.trackingId}] error=${e}`);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
if (e instanceof Error) {
|
||||
switch (e.constructor) {
|
||||
case UserNotFoundError:
|
||||
@ -212,7 +216,7 @@ export class WorkflowsService {
|
||||
);
|
||||
} finally {
|
||||
this.logger.log(
|
||||
`[OUT] [${context.trackingId}] ${this.createWorkflow.name}`,
|
||||
`[OUT] [${context.getTrackingId()}] ${this.createWorkflow.name}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -237,7 +241,9 @@ export class WorkflowsService {
|
||||
templateId?: number | undefined,
|
||||
): Promise<void> {
|
||||
this.logger.log(
|
||||
`[IN] [${context.trackingId}] ${this.updateWorkflow.name} | params: { ` +
|
||||
`[IN] [${context.getTrackingId()}] ${
|
||||
this.updateWorkflow.name
|
||||
} | params: { ` +
|
||||
`externalId: ${externalId}, ` +
|
||||
`workflowId: ${workflowId}, ` +
|
||||
`authorId: ${authorId}, ` +
|
||||
@ -258,7 +264,7 @@ export class WorkflowsService {
|
||||
templateId,
|
||||
);
|
||||
} catch (e) {
|
||||
this.logger.error(`[${context.trackingId}] error=${e}`);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
if (e instanceof Error) {
|
||||
switch (e.constructor) {
|
||||
case WorkflowNotFoundError:
|
||||
@ -304,7 +310,7 @@ export class WorkflowsService {
|
||||
);
|
||||
} finally {
|
||||
this.logger.log(
|
||||
`[OUT] [${context.trackingId}] ${this.updateWorkflow.name}`,
|
||||
`[OUT] [${context.getTrackingId()}] ${this.updateWorkflow.name}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -322,7 +328,9 @@ export class WorkflowsService {
|
||||
workflowId: number,
|
||||
): Promise<void> {
|
||||
this.logger.log(
|
||||
`[IN] [${context.trackingId}] ${this.deleteWorkflow.name} | | params: { ` +
|
||||
`[IN] [${context.getTrackingId()}] ${
|
||||
this.deleteWorkflow.name
|
||||
} | params: { ` +
|
||||
`externalId: ${externalId}, ` +
|
||||
`workflowId: ${workflowId} };`,
|
||||
);
|
||||
@ -339,7 +347,7 @@ export class WorkflowsService {
|
||||
|
||||
await this.workflowsRepository.deleteWorkflow(account.id, workflowId);
|
||||
} catch (e) {
|
||||
this.logger.error(`[${context.trackingId}] error=${e}`);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
if (e instanceof Error) {
|
||||
switch (e.constructor) {
|
||||
case UserNotFoundError:
|
||||
@ -370,7 +378,7 @@ export class WorkflowsService {
|
||||
);
|
||||
} finally {
|
||||
this.logger.log(
|
||||
`[OUT] [${context.trackingId}] ${this.deleteWorkflow.name}`,
|
||||
`[OUT] [${context.getTrackingId()}] ${this.deleteWorkflow.name}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { ClientSecretCredential } from '@azure/identity';
|
||||
import { Client } from '@microsoft/microsoft-graph-client';
|
||||
import { TokenCredentialAuthenticationProvider } from '@microsoft/microsoft-graph-client/authProviders/azureTokenCredentials';
|
||||
import { CACHE_MANAGER, Inject, Injectable, Logger } from '@nestjs/common';
|
||||
import { Injectable, Logger } from '@nestjs/common';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import axios from 'axios';
|
||||
import { B2cMetadata, JwkSignKey } from '../../common/token';
|
||||
@ -71,7 +71,9 @@ export class AdB2cService {
|
||||
password: string,
|
||||
username: string,
|
||||
): Promise<{ sub: string } | ConflictError> {
|
||||
this.logger.log(`[IN] [${context.trackingId}] ${this.createUser.name}`);
|
||||
this.logger.log(
|
||||
`[IN] [${context.getTrackingId()}] ${this.createUser.name}`,
|
||||
);
|
||||
try {
|
||||
// ユーザをADB2Cに登録
|
||||
const newUser = await this.graphClient.api('users/').post({
|
||||
@ -92,7 +94,7 @@ export class AdB2cService {
|
||||
});
|
||||
return { sub: newUser.id };
|
||||
} catch (e) {
|
||||
this.logger.error(e);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
if (e?.statusCode === 400 && e?.body) {
|
||||
const error = JSON.parse(e.body);
|
||||
|
||||
@ -104,7 +106,9 @@ export class AdB2cService {
|
||||
|
||||
throw e;
|
||||
} finally {
|
||||
this.logger.log(`[OUT] [${context.trackingId}] ${this.createUser.name}`);
|
||||
this.logger.log(
|
||||
`[OUT] [${context.getTrackingId()}] ${this.createUser.name}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -112,8 +116,10 @@ export class AdB2cService {
|
||||
* ADB2Cのメタデータを取得する
|
||||
* @returns meta data
|
||||
*/
|
||||
async getMetaData(): Promise<B2cMetadata> {
|
||||
this.logger.log(`[IN] ${this.getMetaData.name}`);
|
||||
async getMetaData(context: Context): Promise<B2cMetadata> {
|
||||
this.logger.log(
|
||||
`[IN] [${context.getTrackingId()}] ${this.getMetaData.name}`,
|
||||
);
|
||||
try {
|
||||
// Azure AD B2Cのメタデータを取得する。 以下のURLから取得できる。
|
||||
// https://<テナント名>.b2clogin.com/<テナント名>.onmicrosoft.com/<ユーザーフロー名>/v2.0/.well-known/openid-configuration
|
||||
@ -125,10 +131,12 @@ export class AdB2cService {
|
||||
|
||||
return metaData;
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
throw e;
|
||||
} finally {
|
||||
this.logger.log(`[OUT] ${this.getMetaData.name}`);
|
||||
this.logger.log(
|
||||
`[OUT] [${context.getTrackingId()}] ${this.getMetaData.name}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -136,8 +144,10 @@ export class AdB2cService {
|
||||
* IDトークンの署名キーセットを取得する
|
||||
* @returns sign key sets
|
||||
*/
|
||||
async getSignKeySets(): Promise<JwkSignKey[]> {
|
||||
this.logger.log(`[IN] ${this.getSignKeySets.name}`);
|
||||
async getSignKeySets(context: Context): Promise<JwkSignKey[]> {
|
||||
this.logger.log(
|
||||
`[IN] [${context.getTrackingId()}] ${this.getSignKeySets.name}`,
|
||||
);
|
||||
try {
|
||||
// 署名キーのキーセット配列を取得する。 以下のURLから取得できる。
|
||||
const keySets = await axios
|
||||
@ -148,10 +158,12 @@ export class AdB2cService {
|
||||
|
||||
return keySets;
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
throw e;
|
||||
} finally {
|
||||
this.logger.log(`[OUT] ${this.getSignKeySets.name}`);
|
||||
this.logger.log(
|
||||
`[OUT] [${context.getTrackingId()}] ${this.getSignKeySets.name}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -160,8 +172,16 @@ export class AdB2cService {
|
||||
* @param externalId ユーザ情報
|
||||
* @param password パスワード
|
||||
*/
|
||||
async changePassword(externalId: string, password: string): Promise<void> {
|
||||
this.logger.log(`[IN] ${this.changePassword.name}`);
|
||||
async changePassword(
|
||||
context: Context,
|
||||
externalId: string,
|
||||
password: string,
|
||||
): Promise<void> {
|
||||
this.logger.log(
|
||||
`[IN] [${context.getTrackingId()}] ${
|
||||
this.changePassword.name
|
||||
} | params: { ` + `externalId: ${externalId}, };`,
|
||||
);
|
||||
try {
|
||||
// ADB2Cのユーザのパスワードを変更する
|
||||
await this.graphClient.api(`/users/${externalId}`).patch({
|
||||
@ -171,10 +191,12 @@ export class AdB2cService {
|
||||
},
|
||||
});
|
||||
} catch (e) {
|
||||
this.logger.error(e);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
throw e;
|
||||
} finally {
|
||||
this.logger.log(`[OUT] ${this.changePassword.name}`);
|
||||
this.logger.log(
|
||||
`[OUT] [${context.getTrackingId()}] ${this.changePassword.name}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -183,16 +205,21 @@ export class AdB2cService {
|
||||
* @param externalId 外部ユーザーID
|
||||
* @returns ユーザ情報
|
||||
*/
|
||||
async getUser(externalId: string): Promise<AdB2cUser> {
|
||||
this.logger.log(`[IN] ${this.getUser.name}`);
|
||||
async getUser(context: Context, externalId: string): Promise<AdB2cUser> {
|
||||
this.logger.log(
|
||||
`[IN] [${context.getTrackingId()}] ${this.getUser.name} | params: { ` +
|
||||
`externalId: ${externalId} };`,
|
||||
);
|
||||
|
||||
try {
|
||||
const key = makeADB2CKey(externalId);
|
||||
|
||||
// キャッシュ上に存在していれば、キャッシュから取得する
|
||||
const cachedUser = await this.redisService.get<AdB2cUser>(key);
|
||||
const cachedUser = await this.redisService.get<AdB2cUser>(context, key);
|
||||
if (cachedUser) {
|
||||
this.logger.log(`[CACHE HIT] id: ${externalId}`);
|
||||
this.logger.log(
|
||||
`[${context.getTrackingId()}] [CACHE HIT] id: ${externalId}`,
|
||||
);
|
||||
return cachedUser;
|
||||
}
|
||||
|
||||
@ -201,15 +228,19 @@ export class AdB2cService {
|
||||
.api(`users/${externalId}`)
|
||||
.select(['id', 'displayName', 'identities'])
|
||||
.get();
|
||||
await this.redisService.set(key, user, this.ttl);
|
||||
this.logger.log(`[ADB2C GET] externalId: ${externalId}`);
|
||||
await this.redisService.set(context, key, user, this.ttl);
|
||||
this.logger.log(
|
||||
`[${context.getTrackingId()}] [ADB2C GET] externalId: ${externalId}`,
|
||||
);
|
||||
|
||||
return user;
|
||||
} catch (e) {
|
||||
this.logger.error(e);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
throw e;
|
||||
} finally {
|
||||
this.logger.log(`[OUT] ${this.getUser.name}`);
|
||||
this.logger.log(
|
||||
`[OUT] [${context.getTrackingId()}] ${this.getUser.name}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
/**
|
||||
@ -222,19 +253,21 @@ export class AdB2cService {
|
||||
externalIds: string[],
|
||||
): Promise<AdB2cUser[]> {
|
||||
this.logger.log(
|
||||
`[IN] [${context.trackingId}] ${
|
||||
`[IN] [${context.getTrackingId()}] ${
|
||||
this.getUsers.name
|
||||
} | params: { externalIds:[${externalIds.join(',')}] };`,
|
||||
);
|
||||
|
||||
const keys = externalIds.map((externalId) => makeADB2CKey(externalId));
|
||||
const cache = await this.redisService.mget<AdB2cUser>(keys);
|
||||
const cache = await this.redisService.mget<AdB2cUser>(context, keys);
|
||||
|
||||
// キャッシュ上に存在していれば、キャッシュから取得する
|
||||
const cachedUsers = cache.flatMap((x) => (x.value ? [x.value] : []));
|
||||
if (cachedUsers.length > 0) {
|
||||
this.logger.log(
|
||||
`[CACHE HIT] ids: ${cachedUsers.map((x) => x.id).join(',')}`,
|
||||
`[${context.getTrackingId()}] [CACHE HIT] ids: ${cachedUsers
|
||||
.map((x) => x.id)
|
||||
.join(',')}`,
|
||||
);
|
||||
}
|
||||
|
||||
@ -265,15 +298,17 @@ export class AdB2cService {
|
||||
value: user,
|
||||
};
|
||||
});
|
||||
await this.redisService.mset(users, this.ttl);
|
||||
await this.redisService.mset(context, users, this.ttl);
|
||||
this.logger.log(
|
||||
`[ADB2C GET] externalIds: ${res.value?.map((x) => x.id).join(',')}`,
|
||||
`[${context.getTrackingId()}] [ADB2C GET] externalIds: ${res.value
|
||||
?.map((x) => x.id)
|
||||
.join(',')}`,
|
||||
);
|
||||
}
|
||||
|
||||
return [...cachedUsers, ...b2cUsers];
|
||||
} catch (e) {
|
||||
this.logger.error(e);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
const { statusCode } = e;
|
||||
if (statusCode === 429) {
|
||||
throw new Adb2cTooManyRequestsError();
|
||||
@ -281,7 +316,9 @@ export class AdB2cService {
|
||||
|
||||
throw e;
|
||||
} finally {
|
||||
this.logger.log(`[OUT] [${context.trackingId}] ${this.getUsers.name}`);
|
||||
this.logger.log(
|
||||
`[OUT] [${context.getTrackingId()}] ${this.getUsers.name}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
/**
|
||||
@ -291,26 +328,32 @@ export class AdB2cService {
|
||||
*/
|
||||
async deleteUser(externalId: string, context: Context): Promise<void> {
|
||||
this.logger.log(
|
||||
`[IN] [${context.trackingId}] ${this.deleteUser.name} | params: { externalId: ${externalId} };`,
|
||||
`[IN] [${context.getTrackingId()}] ${
|
||||
this.deleteUser.name
|
||||
} | params: { externalId: ${externalId} };`,
|
||||
);
|
||||
|
||||
try {
|
||||
// https://learn.microsoft.com/en-us/graph/api/user-delete?view=graph-rest-1.0&tabs=javascript#example
|
||||
await this.graphClient.api(`users/${externalId}`).delete();
|
||||
this.logger.log(`[ADB2C DELETE] externalId: ${externalId}`);
|
||||
this.logger.log(
|
||||
`[${context.getTrackingId()}] [ADB2C DELETE] externalId: ${externalId}`,
|
||||
);
|
||||
|
||||
// キャッシュからも削除する
|
||||
try {
|
||||
await this.redisService.del(makeADB2CKey(externalId));
|
||||
await this.redisService.del(context, makeADB2CKey(externalId));
|
||||
} catch (e) {
|
||||
// キャッシュからの削除に失敗しても、ADB2Cからの削除は成功しているため例外はスローしない
|
||||
this.logger.error(`error=${e}`);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
}
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
throw e;
|
||||
} finally {
|
||||
this.logger.log(`[OUT] [${context.trackingId}] ${this.deleteUser.name}`);
|
||||
this.logger.log(
|
||||
`[OUT] [${context.getTrackingId()}] ${this.deleteUser.name}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -321,7 +364,9 @@ export class AdB2cService {
|
||||
*/
|
||||
async deleteUsers(externalIds: string[], context: Context): Promise<void> {
|
||||
this.logger.log(
|
||||
`[IN] [${context.trackingId}] ${this.deleteUsers.name} | params: { externalIds: ${externalIds} };`,
|
||||
`[IN] [${context.getTrackingId()}] ${
|
||||
this.deleteUsers.name
|
||||
} | params: { externalIds: ${externalIds} };`,
|
||||
);
|
||||
|
||||
try {
|
||||
@ -329,14 +374,16 @@ export class AdB2cService {
|
||||
const results = await Promise.allSettled(
|
||||
externalIds.map(async (externalId) => {
|
||||
await this.graphClient.api(`users/${externalId}`).delete();
|
||||
this.logger.log(`[ADB2C DELETE] externalId: ${externalId}`);
|
||||
this.logger.log(
|
||||
`[${context.getTrackingId()}] [ADB2C DELETE] externalId: ${externalId}`,
|
||||
);
|
||||
|
||||
// キャッシュからも削除する
|
||||
try {
|
||||
await this.redisService.del(makeADB2CKey(externalId));
|
||||
await this.redisService.del(context, makeADB2CKey(externalId));
|
||||
} catch (e) {
|
||||
// キャッシュからの削除に失敗しても、ADB2Cからの削除は成功しているため例外はスローしない
|
||||
this.logger.error(`error=${e}`);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
}
|
||||
}),
|
||||
);
|
||||
@ -353,19 +400,21 @@ export class AdB2cService {
|
||||
const error = result.reason.toString();
|
||||
|
||||
this.logger.error(
|
||||
`${MANUAL_RECOVERY_REQUIRED}[${context.trackingId}] Failed to delete user ${failedId}: ${error}`,
|
||||
`${MANUAL_RECOVERY_REQUIRED} [${context.getTrackingId()}] Failed to delete user ${failedId}: ${error}`,
|
||||
);
|
||||
} else {
|
||||
this.logger.error(
|
||||
`${MANUAL_RECOVERY_REQUIRED}[${context.trackingId}] Failed to delete user ${failedId}`,
|
||||
`${MANUAL_RECOVERY_REQUIRED} [${context.getTrackingId()}] Failed to delete user ${failedId}`,
|
||||
);
|
||||
}
|
||||
});
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
throw e;
|
||||
} finally {
|
||||
this.logger.log(`[OUT] [${context.trackingId}] ${this.deleteUsers.name}`);
|
||||
this.logger.log(
|
||||
`[OUT] [${context.getTrackingId()}] ${this.deleteUsers.name}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -69,21 +69,27 @@ export class BlobstorageService {
|
||||
country: string,
|
||||
): Promise<void> {
|
||||
this.logger.log(
|
||||
`[IN] [${context.trackingId}] ${this.createContainer.name}`,
|
||||
`[IN] [${context.getTrackingId()}] ${
|
||||
this.createContainer.name
|
||||
} | params: { ` + `accountId: ${accountId} };`,
|
||||
);
|
||||
|
||||
// 国に応じたリージョンでコンテナ名を指定してClientを取得
|
||||
const containerClient = this.getContainerClient(accountId, country);
|
||||
const containerClient = this.getContainerClient(
|
||||
context,
|
||||
accountId,
|
||||
country,
|
||||
);
|
||||
|
||||
try {
|
||||
// コンテナ作成
|
||||
await containerClient.create();
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
throw e;
|
||||
} finally {
|
||||
this.logger.log(
|
||||
`[OUT] [${context.trackingId}] ${this.createContainer.name}`,
|
||||
`[OUT] [${context.getTrackingId()}] ${this.createContainer.name}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -100,16 +106,22 @@ export class BlobstorageService {
|
||||
country: string,
|
||||
): Promise<void> {
|
||||
this.logger.log(
|
||||
`[IN] [${context.trackingId}] ${this.deleteContainer.name}`,
|
||||
`[IN] [${context.getTrackingId()}] ${
|
||||
this.deleteContainer.name
|
||||
} | params: { ` + `accountId: ${accountId} };`,
|
||||
);
|
||||
|
||||
try {
|
||||
// 国に応じたリージョンでコンテナ名を指定してClientを取得
|
||||
const containerClient = this.getContainerClient(accountId, country);
|
||||
const containerClient = this.getContainerClient(
|
||||
context,
|
||||
accountId,
|
||||
country,
|
||||
);
|
||||
const { succeeded, errorCode, date } =
|
||||
await containerClient.deleteIfExists();
|
||||
this.logger.log(
|
||||
`succeeded: ${succeeded}, errorCode: ${errorCode}, date: ${date}`,
|
||||
`[${context.getTrackingId()}] succeeded: ${succeeded}, errorCode: ${errorCode}, date: ${date}`,
|
||||
);
|
||||
|
||||
// 失敗時、コンテナが存在しない場合以外はエラーとして例外をスローする
|
||||
@ -121,11 +133,11 @@ export class BlobstorageService {
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
throw e;
|
||||
} finally {
|
||||
this.logger.log(
|
||||
`[OUT] [${context.trackingId}] ${this.deleteContainer.name}`,
|
||||
`[OUT] [${context.getTrackingId()}] ${this.deleteContainer.name}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -142,14 +154,20 @@ export class BlobstorageService {
|
||||
country: string,
|
||||
): Promise<boolean> {
|
||||
this.logger.log(
|
||||
`[IN] [${context.trackingId}] ${this.containerExists.name}`,
|
||||
`[IN] [${context.getTrackingId()}] ${
|
||||
this.containerExists.name
|
||||
} | params: { ` + `accountId: ${accountId} };`,
|
||||
);
|
||||
// 国に応じたリージョンでコンテナ名を指定してClientを取得
|
||||
const containerClient = this.getContainerClient(accountId, country);
|
||||
const containerClient = this.getContainerClient(
|
||||
context,
|
||||
accountId,
|
||||
country,
|
||||
);
|
||||
const exists = await containerClient.exists();
|
||||
|
||||
this.logger.log(
|
||||
`[OUT] [${context.trackingId}] ${this.containerExists.name}`,
|
||||
`[OUT] [${context.getTrackingId()}] ${this.containerExists.name}`,
|
||||
);
|
||||
return exists;
|
||||
}
|
||||
@ -169,13 +187,23 @@ export class BlobstorageService {
|
||||
country: string,
|
||||
filePath: string,
|
||||
): Promise<boolean> {
|
||||
this.logger.log(`[IN] [${context.trackingId}] ${this.fileExists.name}`);
|
||||
this.logger.log(
|
||||
`[IN] [${context.getTrackingId()}] ${this.fileExists.name} | params: { ` +
|
||||
`accountId: ${accountId},` +
|
||||
`filePath: ${filePath} };`,
|
||||
);
|
||||
|
||||
const containerClient = this.getContainerClient(accountId, country);
|
||||
const containerClient = this.getContainerClient(
|
||||
context,
|
||||
accountId,
|
||||
country,
|
||||
);
|
||||
const blob = containerClient.getBlobClient(`${filePath}`);
|
||||
const exists = await blob.exists();
|
||||
|
||||
this.logger.log(`[OUT] [${context.trackingId}] ${this.fileExists.name}`);
|
||||
this.logger.log(
|
||||
`[OUT] [${context.getTrackingId()}] ${this.fileExists.name}`,
|
||||
);
|
||||
return exists;
|
||||
}
|
||||
|
||||
@ -191,19 +219,21 @@ export class BlobstorageService {
|
||||
country: string,
|
||||
): Promise<string> {
|
||||
this.logger.log(
|
||||
`[IN] [${context.trackingId}] ${this.publishUploadSas.name}`,
|
||||
`[IN] [${context.getTrackingId()}] ${
|
||||
this.publishUploadSas.name
|
||||
} | params: { ` + `accountId: ${accountId} };`,
|
||||
);
|
||||
let containerClient: ContainerClient;
|
||||
let sharedKeyCredential: StorageSharedKeyCredential;
|
||||
try {
|
||||
// コンテナ名を指定してClientを取得
|
||||
containerClient = this.getContainerClient(accountId, country);
|
||||
containerClient = this.getContainerClient(context, accountId, country);
|
||||
// 国に対応したリージョンの接続情報を取得する
|
||||
sharedKeyCredential = this.getSharedKeyCredential(country);
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
this.logger.log(
|
||||
`[OUT] [${context.trackingId}] ${this.publishUploadSas.name}`,
|
||||
`[OUT] [${context.getTrackingId()}] ${this.publishUploadSas.name}`,
|
||||
);
|
||||
throw e;
|
||||
}
|
||||
@ -231,7 +261,7 @@ export class BlobstorageService {
|
||||
url.search = `${sasToken}`;
|
||||
|
||||
this.logger.log(
|
||||
`[OUT] [${context.trackingId}] ${
|
||||
`[OUT] [${context.getTrackingId()}] ${
|
||||
this.publishUploadSas.name
|
||||
} url=${url.toString()}`,
|
||||
);
|
||||
@ -250,12 +280,18 @@ export class BlobstorageService {
|
||||
country: string,
|
||||
): Promise<string> {
|
||||
this.logger.log(
|
||||
`[IN] [${context.trackingId}] ${this.publishTemplateUploadSas.name}`,
|
||||
`[IN] [${context.getTrackingId()}] ${
|
||||
this.publishTemplateUploadSas.name
|
||||
} | params: { ` + `accountId: ${accountId} };`,
|
||||
);
|
||||
|
||||
try {
|
||||
// コンテナ名を指定してClientを取得
|
||||
const containerClient = this.getContainerClient(accountId, country);
|
||||
const containerClient = this.getContainerClient(
|
||||
context,
|
||||
accountId,
|
||||
country,
|
||||
);
|
||||
// 国に対応したリージョンの接続情報を取得する
|
||||
const sharedKeyCredential = this.getSharedKeyCredential(country);
|
||||
//SASの有効期限を設定
|
||||
@ -282,11 +318,13 @@ export class BlobstorageService {
|
||||
|
||||
return url.toString();
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
throw e;
|
||||
} finally {
|
||||
this.logger.log(
|
||||
`[OUT] [${context.trackingId}] ${this.publishTemplateUploadSas.name}`,
|
||||
`[OUT] [${context.getTrackingId()}] ${
|
||||
this.publishTemplateUploadSas.name
|
||||
}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -306,22 +344,26 @@ export class BlobstorageService {
|
||||
filePath: string,
|
||||
): Promise<string> {
|
||||
this.logger.log(
|
||||
`[IN] [${context.trackingId}] ${this.publishDownloadSas.name}`,
|
||||
`[IN] [${context.getTrackingId()}] ${
|
||||
this.publishDownloadSas.name
|
||||
}| params: { ` +
|
||||
`accountId: ${accountId},` +
|
||||
`filePath: ${filePath} };`,
|
||||
);
|
||||
let containerClient: ContainerClient;
|
||||
let blobClient: BlobClient;
|
||||
let sharedKeyCredential: StorageSharedKeyCredential;
|
||||
try {
|
||||
// コンテナ名を指定してClientを取得
|
||||
containerClient = this.getContainerClient(accountId, country);
|
||||
containerClient = this.getContainerClient(context, accountId, country);
|
||||
// コンテナ内のBlobパス名を指定してClientを取得
|
||||
blobClient = containerClient.getBlobClient(`${filePath}`);
|
||||
// 国に対応したリージョンの接続情報を取得する
|
||||
sharedKeyCredential = this.getSharedKeyCredential(country);
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
this.logger.log(
|
||||
`[OUT] [${context.trackingId}] ${this.publishDownloadSas.name}`,
|
||||
`[OUT] [${context.getTrackingId()}] ${this.publishDownloadSas.name}`,
|
||||
);
|
||||
throw e;
|
||||
}
|
||||
@ -350,7 +392,7 @@ export class BlobstorageService {
|
||||
url.search = `${sasToken}`;
|
||||
|
||||
this.logger.log(
|
||||
`[OUT] [${context.trackingId}] ${
|
||||
`[OUT] [${context.getTrackingId()}] ${
|
||||
this.publishDownloadSas.name
|
||||
}, url=${url.toString()}`,
|
||||
);
|
||||
@ -363,9 +405,16 @@ export class BlobstorageService {
|
||||
* @returns container client
|
||||
*/
|
||||
private getContainerClient(
|
||||
context: Context,
|
||||
accountId: number,
|
||||
country: string,
|
||||
): ContainerClient {
|
||||
this.logger.log(
|
||||
`[IN] [${context.getTrackingId()}] ${
|
||||
this.getContainerClient.name
|
||||
} | params: { ` + `accountId: ${accountId} };`,
|
||||
);
|
||||
|
||||
const containerName = `account-${accountId}`;
|
||||
if (BLOB_STORAGE_REGION_US.includes(country)) {
|
||||
return this.blobServiceClientUS.getContainerClient(containerName);
|
||||
|
||||
@ -5,13 +5,15 @@ import {
|
||||
createAppleNotificationBody,
|
||||
createAppleNotification,
|
||||
createTagExpression,
|
||||
createWindowsToastNotification,
|
||||
createWindowsInstallation,
|
||||
createAppleInstallation,
|
||||
createWindowsRawNotification,
|
||||
} from '@azure/notification-hubs';
|
||||
import { TAG_MAX_COUNT } from '../../constants';
|
||||
import { PNS } from '../../constants';
|
||||
import { Context } from '../../common/log';
|
||||
import { NotificationBody } from '../../common/notify/types/types';
|
||||
|
||||
@Injectable()
|
||||
export class NotificationhubService {
|
||||
private readonly logger = new Logger(NotificationhubService.name);
|
||||
@ -37,7 +39,9 @@ export class NotificationhubService {
|
||||
installationId: string,
|
||||
): Promise<void> {
|
||||
this.logger.log(
|
||||
`[IN] [${context.trackingId}] ${this.register.name} | params: { userId: ${userId}, pns: ${pns}, pnsHandler: ${pnsHandler}, installationId: ${installationId} }`,
|
||||
`[IN] [${context.getTrackingId()}] ${
|
||||
this.register.name
|
||||
} | params: { userId: ${userId}, pns: ${pns}, pnsHandler: ${pnsHandler}, installationId: ${installationId} }`,
|
||||
);
|
||||
|
||||
const tag = `user_${userId}`;
|
||||
@ -67,26 +71,33 @@ export class NotificationhubService {
|
||||
throw new Error('invalid pns');
|
||||
}
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e.message}`);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e.message}`);
|
||||
throw e;
|
||||
} finally {
|
||||
this.logger.log(`[OUT] [${context.trackingId}] ${this.register.name}`);
|
||||
this.logger.log(
|
||||
`[OUT] [${context.getTrackingId()}] ${this.register.name}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定したタグのユーザーに通知を送信する
|
||||
* @param context
|
||||
* @param tags
|
||||
* @param message
|
||||
* @param bodyContent
|
||||
* @returns notify
|
||||
*/
|
||||
async notify(
|
||||
context: Context,
|
||||
tags: string[],
|
||||
message: string,
|
||||
bodyContent: NotificationBody,
|
||||
): Promise<void> {
|
||||
this.logger.log(
|
||||
`[IN] [${context.trackingId}] ${this.notify.name} | params: { tags: ${tags}, message: ${message} }`,
|
||||
`[IN] [${context.getTrackingId()}] ${
|
||||
this.notify.name
|
||||
} | params: { tags: ${tags}, bodyContent: ${JSON.stringify(
|
||||
bodyContent,
|
||||
)} }`,
|
||||
);
|
||||
|
||||
try {
|
||||
@ -99,31 +110,43 @@ export class NotificationhubService {
|
||||
|
||||
// Windows
|
||||
try {
|
||||
const body = `<toast><visual><binding template="ToastText01"><text id="1">${message}</text></binding></visual></toast>`;
|
||||
const notification = createWindowsToastNotification({ body });
|
||||
const body = {
|
||||
wns: {
|
||||
alert: '',
|
||||
},
|
||||
newDictation: bodyContent,
|
||||
};
|
||||
const notification = createWindowsRawNotification({
|
||||
body: JSON.stringify(body),
|
||||
});
|
||||
const result = await this.client.sendNotification(notification, {
|
||||
tagExpression,
|
||||
});
|
||||
this.logger.log(result);
|
||||
this.logger.log(`[${context.getTrackingId()}] ${result}`);
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
}
|
||||
// Apple
|
||||
try {
|
||||
const body = createAppleNotificationBody({ aps: { alert: message } });
|
||||
const body = createAppleNotificationBody({
|
||||
aps: {
|
||||
alert: '',
|
||||
},
|
||||
newDictation: bodyContent,
|
||||
});
|
||||
const notification = createAppleNotification({ body });
|
||||
const result = await this.client.sendNotification(notification, {
|
||||
tagExpression,
|
||||
});
|
||||
this.logger.log(result);
|
||||
this.logger.log(`[${context.getTrackingId()}] ${result}`);
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
throw e;
|
||||
} finally {
|
||||
this.logger.log(`[OUT] ${this.notify.name}`);
|
||||
this.logger.log(`[OUT] [${context.getTrackingId()}] ${this.notify.name}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,11 +1,6 @@
|
||||
import {
|
||||
CACHE_MANAGER,
|
||||
Inject,
|
||||
Injectable,
|
||||
InternalServerErrorException,
|
||||
Logger,
|
||||
} from '@nestjs/common';
|
||||
import { CACHE_MANAGER, Inject, Injectable, Logger } from '@nestjs/common';
|
||||
import { Cache } from 'cache-manager';
|
||||
import { Context } from '../../common/log';
|
||||
|
||||
@Injectable()
|
||||
export class RedisService {
|
||||
@ -20,10 +15,17 @@ export class RedisService {
|
||||
* @param ttl 有効期限(秒)
|
||||
*/
|
||||
async set(
|
||||
context: Context,
|
||||
key: string,
|
||||
value: unknown,
|
||||
ttl?: number | undefined,
|
||||
): Promise<void> {
|
||||
this.logger.log(
|
||||
`[IN] [${context.getTrackingId()}] ${this.set.name} | params: { ` +
|
||||
`ttl: ${ttl}
|
||||
};`,
|
||||
);
|
||||
|
||||
try {
|
||||
// cache-manager-redis-store がcache-managerのset形式と不一致な値の渡し方を採用しているため、
|
||||
// @types/cache-managerのset形式を使用すると、redisに値が保存されない。
|
||||
@ -31,7 +33,7 @@ export class RedisService {
|
||||
// https://www.npmjs.com/package/cache-manager
|
||||
await this.cacheManager.set(key, value, { ttl: ttl } as any);
|
||||
} catch (error) {
|
||||
this.logger.error(error);
|
||||
this.logger.error(`[${context.getTrackingId()}] ${error}`);
|
||||
}
|
||||
}
|
||||
|
||||
@ -42,17 +44,24 @@ export class RedisService {
|
||||
* @param ttl 有効期限(秒)
|
||||
*/
|
||||
async mset<T>(
|
||||
context: Context,
|
||||
records: { key: string; value: T }[],
|
||||
ttl?: number | undefined,
|
||||
): Promise<void> {
|
||||
this.logger.log(
|
||||
`[IN] [${context.getTrackingId()}] ${this.mset.name} | params: { ` +
|
||||
`ttl: ${ttl}
|
||||
};`,
|
||||
);
|
||||
|
||||
try {
|
||||
// cache-manager-redis-store のmsetが壊れており、利用できないため、
|
||||
// 一つずつsetする。
|
||||
for await (const record of records) {
|
||||
await this.set(record.key, record.value, ttl);
|
||||
await this.set(context, record.key, record.value, ttl);
|
||||
}
|
||||
} catch (error) {
|
||||
this.logger.error(error);
|
||||
this.logger.error(`[${context.getTrackingId()}] ${error}`);
|
||||
}
|
||||
}
|
||||
|
||||
@ -62,12 +71,14 @@ export class RedisService {
|
||||
* @param key キー
|
||||
* @returns キーに対応する値
|
||||
*/
|
||||
async get<T>(key: string): Promise<T | undefined> {
|
||||
async get<T>(context: Context, key: string): Promise<T | undefined> {
|
||||
this.logger.log(`[IN] [${context.getTrackingId()}] ${this.get.name};`);
|
||||
|
||||
try {
|
||||
const value = await this.cacheManager.get<T>(key);
|
||||
return value;
|
||||
} catch (error) {
|
||||
this.logger.error(error);
|
||||
this.logger.error(`[${context.getTrackingId()}] ${error}`);
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
@ -78,7 +89,12 @@ export class RedisService {
|
||||
* @param keys キーの配列
|
||||
* @returns キーとそのキーに対応する値のペアの配列
|
||||
*/
|
||||
async mget<T>(keys: string[]): Promise<{ key: string; value: T | null }[]> {
|
||||
async mget<T>(
|
||||
context: Context,
|
||||
keys: string[],
|
||||
): Promise<{ key: string; value: T | null }[]> {
|
||||
this.logger.log(`[IN] [${context.getTrackingId()}] ${this.mget.name};`);
|
||||
|
||||
if (keys.length === 0) return []; // mget操作は0件の時エラーとなるため、0件は特別扱いする
|
||||
|
||||
try {
|
||||
@ -91,7 +107,7 @@ export class RedisService {
|
||||
};
|
||||
});
|
||||
} catch (error) {
|
||||
this.logger.error(error);
|
||||
this.logger.error(`[${context.getTrackingId()}] ${error}`);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@ -100,11 +116,13 @@ export class RedisService {
|
||||
* キーに対応する値を削除する。
|
||||
* @param key キー
|
||||
*/
|
||||
async del(key: string): Promise<void> {
|
||||
async del(context: Context, key: string): Promise<void> {
|
||||
this.logger.log(`[IN] [${context.getTrackingId()}] ${this.del.name};`);
|
||||
|
||||
try {
|
||||
await this.cacheManager.del(key);
|
||||
} catch (error) {
|
||||
this.logger.error(error);
|
||||
this.logger.error(`[${context.getTrackingId()}] ${error}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -23,7 +23,7 @@ export class SendGridService {
|
||||
* Email認証用のメールコンテンツを作成する
|
||||
* @param accountId 認証対象のユーザーが所属するアカウントのID
|
||||
* @param userId 認証対象のユーザーのID
|
||||
* @param email 認証対象のユーザーのメールアドレス
|
||||
* @param email 認証対象のユーザーのメールアドレス
|
||||
* @returns メールのサブジェクトとコンテンツ
|
||||
*/
|
||||
async createMailContentFromEmailConfirm(
|
||||
@ -33,7 +33,11 @@ export class SendGridService {
|
||||
email: string,
|
||||
): Promise<{ subject: string; text: string; html: string }> {
|
||||
this.logger.log(
|
||||
`[IN] [${context.trackingId}] ${this.createMailContentFromEmailConfirm.name}`,
|
||||
`[IN] [${context.getTrackingId()}] ${
|
||||
this.createMailContentFromEmailConfirm.name
|
||||
} | params: { ` +
|
||||
`accountId: ${accountId},` +
|
||||
`userId: ${userId} };`,
|
||||
);
|
||||
|
||||
const privateKey = getPrivateKey(this.configService);
|
||||
@ -49,7 +53,9 @@ export class SendGridService {
|
||||
const path = 'mail-confirm/';
|
||||
|
||||
this.logger.log(
|
||||
`[OUT] [${context.trackingId}] ${this.createMailContentFromEmailConfirm.name}`,
|
||||
`[OUT] [${context.getTrackingId()}] ${
|
||||
this.createMailContentFromEmailConfirm.name
|
||||
}`,
|
||||
);
|
||||
return {
|
||||
subject: 'Verify your new account',
|
||||
@ -62,15 +68,23 @@ export class SendGridService {
|
||||
* Email認証用のメールコンテンツを作成する(一般ユーザ向け)
|
||||
* @param accountId 認証対象のユーザーが所属するアカウントのID
|
||||
* @param userId 認証対象のユーザーのID
|
||||
* @param email 認証対象のユーザーのメールアドレス
|
||||
* @param email 認証対象のユーザーのメールアドレス
|
||||
* @returns メールのサブジェクトとコンテンツ
|
||||
*/
|
||||
//TODO [Task2163] 中身が管理ユーザ向けのままなので、修正の必要あり
|
||||
async createMailContentFromEmailConfirmForNormalUser(
|
||||
context: Context,
|
||||
accountId: number,
|
||||
userId: number,
|
||||
email: string,
|
||||
): Promise<{ subject: string; text: string; html: string }> {
|
||||
this.logger.log(
|
||||
`[IN] [${context.getTrackingId()}] ${
|
||||
this.createMailContentFromEmailConfirmForNormalUser.name
|
||||
} | params: { ` +
|
||||
`accountId: ${accountId},` +
|
||||
`userId: ${userId} };`,
|
||||
);
|
||||
const privateKey = getPrivateKey(this.configService);
|
||||
|
||||
const token = sign<{ accountId: number; userId: number; email: string }>(
|
||||
@ -109,7 +123,7 @@ export class SendGridService {
|
||||
text: string,
|
||||
html: string,
|
||||
): Promise<void> {
|
||||
this.logger.log(`[IN] [${context.trackingId}] ${this.sendMail.name}`);
|
||||
this.logger.log(`[IN] [${context.getTrackingId()}] ${this.sendMail.name}`);
|
||||
try {
|
||||
const res = await sendgrid
|
||||
.send({
|
||||
@ -125,13 +139,17 @@ export class SendGridService {
|
||||
})
|
||||
.then((v) => v[0]);
|
||||
this.logger.log(
|
||||
`status code: ${res.statusCode} body: ${JSON.stringify(res.body)}`,
|
||||
`[${context.getTrackingId()}] status code: ${
|
||||
res.statusCode
|
||||
} body: ${JSON.stringify(res.body)}`,
|
||||
);
|
||||
} catch (e) {
|
||||
this.logger.error(e);
|
||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||
throw e;
|
||||
} finally {
|
||||
this.logger.log(`[OUT] [${context.trackingId}] ${this.sendMail.name}`);
|
||||
this.logger.log(
|
||||
`[OUT] [${context.getTrackingId()}] ${this.sendMail.name}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,3 +4,5 @@ export class AccountNotFoundError extends Error {}
|
||||
export class DealerAccountNotFoundError extends Error {}
|
||||
// 管理者ユーザ未存在エラー
|
||||
export class AdminUserNotFoundError extends Error {}
|
||||
// アカウントロックエラー
|
||||
export class AccountLockedError extends Error {}
|
||||
|
||||
@ -33,3 +33,6 @@ export class CancellationPeriodExpiredError extends Error {}
|
||||
|
||||
// ライセンス発行キャンセル不可エラー(発行したライセンスが割り当てされている場合)
|
||||
export class AlreadyLicenseAllocatedError extends Error {}
|
||||
|
||||
// ライセンス未割当エラー
|
||||
export class LicenseNotAllocatedError extends Error {}
|
||||
|
||||
@ -14,3 +14,5 @@ export class StatusNotMatchError extends Error {}
|
||||
export class TypistUserNotMatchError extends Error {}
|
||||
// Account不一致エラー
|
||||
export class AccountNotMatchError extends Error {}
|
||||
// タスクチェックアウト済みエラー
|
||||
export class AlreadyHasInProgressTaskError extends Error {}
|
||||
|
||||
@ -6,6 +6,7 @@ import {
|
||||
FindOptionsOrderValue,
|
||||
In,
|
||||
IsNull,
|
||||
Not,
|
||||
Repository,
|
||||
} from 'typeorm';
|
||||
import { Task } from './entity/task.entity';
|
||||
@ -26,6 +27,7 @@ import { UserGroup } from '../user_groups/entity/user_group.entity';
|
||||
import { User } from '../users/entity/user.entity';
|
||||
import {
|
||||
AccountNotMatchError,
|
||||
AlreadyHasInProgressTaskError,
|
||||
CheckoutPermissionNotFoundError,
|
||||
StatusNotMatchError,
|
||||
TaskAuthorIdNotMatchError,
|
||||
@ -163,6 +165,24 @@ export class TasksRepositoryService {
|
||||
`task not found. audio_file_id:${audio_file_id}`,
|
||||
);
|
||||
}
|
||||
|
||||
// 指定したタスク以外に実行ユーザー担当のInprogressのタスクが存在する場合はエラー
|
||||
const tasks = await taskRepo.find({
|
||||
where: {
|
||||
audio_file_id: Not(audio_file_id),
|
||||
status: TASK_STATUS.IN_PROGRESS,
|
||||
typist_user_id: user_id,
|
||||
},
|
||||
});
|
||||
|
||||
if (tasks.length > 0) {
|
||||
throw new AlreadyHasInProgressTaskError(
|
||||
`checkout task already exists. task:${tasks.map(
|
||||
(x) => x.audio_file_id,
|
||||
)}`,
|
||||
);
|
||||
}
|
||||
|
||||
// アカウントチェック
|
||||
if (task.account_id !== account_id) {
|
||||
throw new AccountNotMatchError(
|
||||
@ -804,13 +824,14 @@ export class TasksRepositoryService {
|
||||
id: In(typistUserIds),
|
||||
account_id: account_id,
|
||||
role: USER_ROLES.TYPIST,
|
||||
email_verified: true,
|
||||
deleted_at: IsNull(),
|
||||
},
|
||||
});
|
||||
// idはユニークであるため取得件数の一致でユーザーの存在を確認
|
||||
if (typistUserIds.length !== userRecords.length) {
|
||||
throw new TypistUserNotFoundError(
|
||||
`User not exists Error. reqUserId:${typistUserIds}; resUserId:${userRecords.map(
|
||||
`User not exists or email not verified Error. reqUserId:${typistUserIds}; resUserId:${userRecords.map(
|
||||
(x) => x.id,
|
||||
)}`,
|
||||
);
|
||||
|
||||
@ -102,11 +102,12 @@ export class UserGroupsRepositoryService {
|
||||
id: In(typistIds),
|
||||
account_id: accountId,
|
||||
role: USER_ROLES.TYPIST,
|
||||
email_verified: true,
|
||||
},
|
||||
});
|
||||
if (userRecords.length !== typistIds.length) {
|
||||
throw new TypistIdInvalidError(
|
||||
`Typist user not exists Error. typistIds:${typistIds}; typistIds(DB):${userRecords.map(
|
||||
`Typist user not exists or email not verified Error. typistIds:${typistIds}; typistIds(DB):${userRecords.map(
|
||||
(x) => x.id,
|
||||
)}`,
|
||||
);
|
||||
@ -153,11 +154,12 @@ export class UserGroupsRepositoryService {
|
||||
id: In(typistIds),
|
||||
account_id: accountId,
|
||||
role: USER_ROLES.TYPIST,
|
||||
email_verified: true,
|
||||
},
|
||||
});
|
||||
if (userRecords.length !== typistIds.length) {
|
||||
throw new TypistIdInvalidError(
|
||||
`Typist user not exists Error. typistIds:${typistIds}; typistIds(DB):${userRecords.map(
|
||||
`Typist user not exists or email not verified Error. typistIds:${typistIds}; typistIds(DB):${userRecords.map(
|
||||
(x) => x.id,
|
||||
)}`,
|
||||
);
|
||||
|
||||
@ -33,6 +33,8 @@ import {
|
||||
AdminUserNotFoundError,
|
||||
} from '../accounts/errors/types';
|
||||
import { Account } from '../accounts/entity/account.entity';
|
||||
import { Workflow } from '../workflows/entity/workflow.entity';
|
||||
import { Worktype } from '../worktypes/entity/worktype.entity';
|
||||
|
||||
@Injectable()
|
||||
export class UsersRepositoryService {
|
||||
@ -358,13 +360,13 @@ export class UsersRepositoryService {
|
||||
},
|
||||
where: { account_id: accountId },
|
||||
});
|
||||
|
||||
|
||||
return dbUsers;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* アカウント内のタイピストユーザーを取得する
|
||||
* アカウント内のメール認証済みのタイピストユーザーを取得する
|
||||
* @param sub
|
||||
* @returns typist users
|
||||
*/
|
||||
@ -387,6 +389,7 @@ export class UsersRepositoryService {
|
||||
where: {
|
||||
account_id: user.account_id,
|
||||
role: USER_ROLES.TYPIST,
|
||||
email_verified: true,
|
||||
deleted_at: IsNull(),
|
||||
},
|
||||
});
|
||||
@ -396,7 +399,7 @@ export class UsersRepositoryService {
|
||||
}
|
||||
|
||||
/**
|
||||
* アカウント内のAuthorユーザーを取得する
|
||||
* アカウント内のEmail認証済みのAuthorユーザーを取得する
|
||||
* @param accountId
|
||||
* @returns author users
|
||||
*/
|
||||
@ -407,6 +410,7 @@ export class UsersRepositoryService {
|
||||
where: {
|
||||
account_id: accountId,
|
||||
role: USER_ROLES.AUTHOR,
|
||||
email_verified: true,
|
||||
deleted_at: IsNull(),
|
||||
},
|
||||
});
|
||||
@ -644,4 +648,100 @@ export class UsersRepositoryService {
|
||||
return originAccount.delegation_permission;
|
||||
});
|
||||
}
|
||||
/**
|
||||
* ユーザーに割り当てられているライセンスを取得する
|
||||
* @param userId ユーザーID
|
||||
* @returns License
|
||||
*/
|
||||
async findLicenseByUserId(userId: number): Promise<License | null> {
|
||||
const allocatedLicense = await this.dataSource
|
||||
.getRepository(License)
|
||||
.findOne({
|
||||
where: {
|
||||
allocated_user_id: userId,
|
||||
status: LICENSE_ALLOCATED_STATUS.ALLOCATED,
|
||||
},
|
||||
});
|
||||
|
||||
return allocatedLicense;
|
||||
}
|
||||
|
||||
/**
|
||||
* ユーザーに紐づく各種情報を取得する
|
||||
* @param userId
|
||||
* @returns user relations
|
||||
*/
|
||||
async getUserRelations(userId: number): Promise<{
|
||||
user: User;
|
||||
authors: User[];
|
||||
worktypes: Worktype[];
|
||||
activeWorktype: Worktype | undefined;
|
||||
}> {
|
||||
return await this.dataSource.transaction(async (entityManager) => {
|
||||
const userRepo = entityManager.getRepository(User);
|
||||
|
||||
const user = await userRepo.findOne({
|
||||
where: { id: userId },
|
||||
relations: { account: true },
|
||||
});
|
||||
|
||||
if (!user) {
|
||||
throw new UserNotFoundError(`User is Not Found. id: ${userId}`);
|
||||
}
|
||||
|
||||
// 運用上、アカウントがいないことはあり得ないが、プログラム上発生しうるのでエラーとして処理
|
||||
if (!user.account) {
|
||||
throw new AccountNotFoundError(
|
||||
`Account is Not Found. user.id: ${userId}`,
|
||||
);
|
||||
}
|
||||
|
||||
// ユーザーの所属するアカウント内のすべてのメール認証済みAuthorユーザーを取得する
|
||||
const authors = await userRepo.find({
|
||||
where: {
|
||||
account_id: user.account_id,
|
||||
role: USER_ROLES.AUTHOR,
|
||||
email_verified: true,
|
||||
},
|
||||
});
|
||||
|
||||
// ユーザーの所属するアカウント内のアクティブワークタイプを取得する
|
||||
const worktypeRepo = entityManager.getRepository(Worktype);
|
||||
let activeWorktype: Worktype | undefined = undefined;
|
||||
const activeWorktypeId = user.account.active_worktype_id;
|
||||
if (activeWorktypeId !== null) {
|
||||
activeWorktype =
|
||||
(await worktypeRepo.findOne({
|
||||
where: {
|
||||
account_id: user.account_id,
|
||||
id: activeWorktypeId,
|
||||
},
|
||||
})) ?? undefined;
|
||||
}
|
||||
|
||||
let worktypes: Worktype[] = [];
|
||||
// ユーザーのロールがAuthorの場合はルーティングルールに紐づいたワークタイプを取得する
|
||||
if (user.role === USER_ROLES.AUTHOR) {
|
||||
const workflowRepo = entityManager.getRepository(Workflow);
|
||||
const workflows = await workflowRepo.find({
|
||||
where: {
|
||||
account_id: user.account_id,
|
||||
author_id: user.id,
|
||||
worktype_id: Not(IsNull()),
|
||||
},
|
||||
relations: {
|
||||
worktype: {
|
||||
option_items: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
worktypes = workflows.flatMap((workflow) =>
|
||||
workflow.worktype ? [workflow.worktype] : [],
|
||||
);
|
||||
}
|
||||
|
||||
return { user, authors, worktypes, activeWorktype };
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -69,10 +69,12 @@ export class WorkflowsRepositoryService {
|
||||
// authorの存在確認
|
||||
const userRepo = entityManager.getRepository(User);
|
||||
const author = await userRepo.findOne({
|
||||
where: { account_id: accountId, id: authorId },
|
||||
where: { account_id: accountId, id: authorId, email_verified: true },
|
||||
});
|
||||
if (!author) {
|
||||
throw new UserNotFoundError(`author not found. id: ${authorId}`);
|
||||
throw new UserNotFoundError(
|
||||
`author not found or email not verified. id: ${authorId}`,
|
||||
);
|
||||
}
|
||||
|
||||
// worktypeの存在確認
|
||||
@ -104,10 +106,16 @@ export class WorkflowsRepositoryService {
|
||||
typist.typistId ? [typist.typistId] : [],
|
||||
);
|
||||
const typistUsers = await userRepo.find({
|
||||
where: { account_id: accountId, id: In(typistIds) },
|
||||
where: {
|
||||
account_id: accountId,
|
||||
id: In(typistIds),
|
||||
email_verified: true,
|
||||
},
|
||||
});
|
||||
if (typistUsers.length !== typistIds.length) {
|
||||
throw new UserNotFoundError(`typist not found. ids: ${typistIds}`);
|
||||
throw new UserNotFoundError(
|
||||
`typist not found or email not verified. ids: ${typistIds}`,
|
||||
);
|
||||
}
|
||||
|
||||
// ルーティング候補ユーザーグループの存在確認
|
||||
@ -198,10 +206,12 @@ export class WorkflowsRepositoryService {
|
||||
// authorの存在確認
|
||||
const userRepo = entityManager.getRepository(User);
|
||||
const author = await userRepo.findOne({
|
||||
where: { account_id: accountId, id: authorId },
|
||||
where: { account_id: accountId, id: authorId, email_verified: true },
|
||||
});
|
||||
if (!author) {
|
||||
throw new UserNotFoundError(`author not found. id: ${authorId}`);
|
||||
throw new UserNotFoundError(
|
||||
`author not found or email not verified. id: ${authorId}`,
|
||||
);
|
||||
}
|
||||
|
||||
// worktypeの存在確認
|
||||
@ -235,10 +245,16 @@ export class WorkflowsRepositoryService {
|
||||
typist.typistId ? [typist.typistId] : [],
|
||||
);
|
||||
const typistUsers = await userRepo.find({
|
||||
where: { account_id: accountId, id: In(typistIds) },
|
||||
where: {
|
||||
account_id: accountId,
|
||||
id: In(typistIds),
|
||||
email_verified: true,
|
||||
},
|
||||
});
|
||||
if (typistUsers.length !== typistIds.length) {
|
||||
throw new UserNotFoundError(`typist not found. ids: ${typistIds}`);
|
||||
throw new UserNotFoundError(
|
||||
`typist not found or email not verified. ids: ${typistIds}`,
|
||||
);
|
||||
}
|
||||
|
||||
// ルーティング候補ユーザーグループの存在確認
|
||||
|
||||
@ -4,7 +4,10 @@ import {
|
||||
PrimaryGeneratedColumn,
|
||||
UpdateDateColumn,
|
||||
CreateDateColumn,
|
||||
ManyToOne,
|
||||
JoinColumn,
|
||||
} from 'typeorm';
|
||||
import { Worktype } from './worktype.entity';
|
||||
|
||||
@Entity({ name: 'option_items' })
|
||||
export class OptionItem {
|
||||
@ -32,4 +35,8 @@ export class OptionItem {
|
||||
type: 'datetime',
|
||||
}) // defaultはSQLite用設定値.本番用は別途migrationで設定
|
||||
updated_at: Date | null;
|
||||
|
||||
@ManyToOne(() => Worktype, (worktype) => worktype.id)
|
||||
@JoinColumn({ name: 'worktype_id' })
|
||||
worktype: Worktype;
|
||||
}
|
||||
|
||||
@ -5,7 +5,9 @@ import {
|
||||
PrimaryGeneratedColumn,
|
||||
CreateDateColumn,
|
||||
UpdateDateColumn,
|
||||
OneToMany,
|
||||
} from 'typeorm';
|
||||
import { OptionItem } from './option_item.entity';
|
||||
|
||||
@Entity({ name: 'worktypes' })
|
||||
export class Worktype {
|
||||
@ -41,4 +43,7 @@ export class Worktype {
|
||||
type: 'datetime',
|
||||
}) // defaultはSQLite用設定値.本番用は別途migrationで設定
|
||||
updated_at: Date;
|
||||
|
||||
@OneToMany(() => OptionItem, (optionItem) => optionItem.worktype)
|
||||
option_items: OptionItem[];
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user