From d83f7d2314d954ac654b37605d977a029fc095ce Mon Sep 17 00:00:00 2001 From: Kesh Ramduny Date: Fri, 12 Jun 2026 12:34:49 +0100 Subject: [PATCH 01/19] Update triggers --- .../deployments_v2/alerting/alerting-build.yml | 2 +- .../deployments_v2/alerting/alerting-pr.yml | 2 +- .../deployments_v2/networking/networking-build.yml | 2 +- .../deployments_v2/networking/networking-pr.yml | 2 +- .../deployments_v2/polaris-triggered-build.yml | 2 +- .../scale-set/deploy-build-agent-pipeline.yml | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/polaris-devops-pipelines/deployments_v2/alerting/alerting-build.yml b/polaris-devops-pipelines/deployments_v2/alerting/alerting-build.yml index c0f49249a..63023762d 100644 --- a/polaris-devops-pipelines/deployments_v2/alerting/alerting-build.yml +++ b/polaris-devops-pipelines/deployments_v2/alerting/alerting-build.yml @@ -5,7 +5,7 @@ trigger: batch: true branches: include: - - main + - development paths: include: - polaris-terraform/alerting-terraform/* diff --git a/polaris-devops-pipelines/deployments_v2/alerting/alerting-pr.yml b/polaris-devops-pipelines/deployments_v2/alerting/alerting-pr.yml index 542de9da9..2279e8b35 100644 --- a/polaris-devops-pipelines/deployments_v2/alerting/alerting-pr.yml +++ b/polaris-devops-pipelines/deployments_v2/alerting/alerting-pr.yml @@ -4,7 +4,7 @@ trigger: none pr: branches: include: - - main + - development paths: include: - polaris-terraform/alerting-terraform/* diff --git a/polaris-devops-pipelines/deployments_v2/networking/networking-build.yml b/polaris-devops-pipelines/deployments_v2/networking/networking-build.yml index c01d0ef02..ecdeebf50 100644 --- a/polaris-devops-pipelines/deployments_v2/networking/networking-build.yml +++ b/polaris-devops-pipelines/deployments_v2/networking/networking-build.yml @@ -5,7 +5,7 @@ trigger: batch: true branches: include: - - main + - development paths: include: - polaris-terraform/networking-terraform/* diff --git a/polaris-devops-pipelines/deployments_v2/networking/networking-pr.yml b/polaris-devops-pipelines/deployments_v2/networking/networking-pr.yml index 72d859a4b..a4cf257b7 100644 --- a/polaris-devops-pipelines/deployments_v2/networking/networking-pr.yml +++ b/polaris-devops-pipelines/deployments_v2/networking/networking-pr.yml @@ -4,7 +4,7 @@ trigger: none pr: branches: include: - - main + - development paths: include: - polaris-terraform/networking-terraform/* diff --git a/polaris-devops-pipelines/deployments_v2/polaris-triggered-build.yml b/polaris-devops-pipelines/deployments_v2/polaris-triggered-build.yml index c8558a8bd..4712536d1 100644 --- a/polaris-devops-pipelines/deployments_v2/polaris-triggered-build.yml +++ b/polaris-devops-pipelines/deployments_v2/polaris-triggered-build.yml @@ -5,7 +5,7 @@ trigger: batch: true branches: include: - - main + - development paths: include: - polaris-terraform/main-terraform/* diff --git a/polaris-devops-pipelines/scale-set/deploy-build-agent-pipeline.yml b/polaris-devops-pipelines/scale-set/deploy-build-agent-pipeline.yml index 796e5b7b1..2f3fcd253 100644 --- a/polaris-devops-pipelines/scale-set/deploy-build-agent-pipeline.yml +++ b/polaris-devops-pipelines/scale-set/deploy-build-agent-pipeline.yml @@ -7,7 +7,7 @@ schedules: displayName: Weekly Sunday night build-agent refresh branches: include: - - main + - development always: true variables: From bf8c774c337ac711e56e9a1a95386b590994c994 Mon Sep 17 00:00:00 2001 From: cpsgopisivanappanvasanthi Date: Tue, 16 Jun 2026 10:16:50 +0100 Subject: [PATCH 02/19] Feature/fct2 9737 nuget upgrade (#2060) * Nuget Packages - Non Microsoft Libraries and some of the testing libraries upgraded to the latest version. This includes, Newtonsoft.json, FluentAssertion, Moq, xUnit, Azure.Core, Identity libraries etcs. We have ignored the Application Inssights and workerservice updates in this upgrade. * Nuget Packages - Non Microsoft Libraries and some of the testing libraries upgraded to the latest version. This includes, Newtonsoft.json, FluentAssertion, Moq, xUnit, Azure.Core, Identity libraries etcs. We have ignored the Application Inssights and workerservice updates in this upgrade. --- .../Cps.Fct.Hk.Ui.Interfaces.csproj | 2 +- .../Cps.Fct.Hk.Ui.Services.Tests.csproj | 8 ++++---- .../Cps.Fct.Hk.Ui.Services.csproj | 6 +++--- DdeiClient/DdeiClient.csproj | 2 +- .../hkui-functions-integration-tests.csproj | 8 ++++---- .../polaris-gateway.tests.csproj | 10 +++++----- polaris-gateway/polaris-gateway.csproj | 8 ++++---- .../Common.tests/Common.tests.csproj | 16 +++++++-------- polaris-pipeline/Common/Common.csproj | 6 +++--- .../DdeiClient.tests/MdsClient.tests.csproj | 12 +++++------ .../coordinator.tests.csproj | 16 +++++++-------- .../coordinator/coordinator.csproj | 12 +++++------ .../pdf-generator.tests.csproj | 16 +++++++-------- .../pdf-generator/pdf-generator.csproj | 6 +++--- .../pdf-redactor.tests.csproj | 16 +++++++-------- .../pdf-redactor/pdf-redactor.csproj | 6 +++--- .../pdf-thumbnail-generator.csproj | 4 ++-- .../text-extractor.tests.csproj | 20 +++++++++---------- 18 files changed, 87 insertions(+), 87 deletions(-) diff --git a/Cps.Fct.Hk.Ui.Interfaces/Cps.Fct.Hk.Ui.Interfaces.csproj b/Cps.Fct.Hk.Ui.Interfaces/Cps.Fct.Hk.Ui.Interfaces.csproj index 18be8d30e..8e80cd8b5 100644 --- a/Cps.Fct.Hk.Ui.Interfaces/Cps.Fct.Hk.Ui.Interfaces.csproj +++ b/Cps.Fct.Hk.Ui.Interfaces/Cps.Fct.Hk.Ui.Interfaces.csproj @@ -24,7 +24,7 @@ - + diff --git a/Cps.Fct.Hk.Ui.Services.Tests/Cps.Fct.Hk.Ui.Services.Tests.csproj b/Cps.Fct.Hk.Ui.Services.Tests/Cps.Fct.Hk.Ui.Services.Tests.csproj index dc30b456e..211459016 100644 --- a/Cps.Fct.Hk.Ui.Services.Tests/Cps.Fct.Hk.Ui.Services.Tests.csproj +++ b/Cps.Fct.Hk.Ui.Services.Tests/Cps.Fct.Hk.Ui.Services.Tests.csproj @@ -16,19 +16,19 @@ - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/Cps.Fct.Hk.Ui.Services/Cps.Fct.Hk.Ui.Services.csproj b/Cps.Fct.Hk.Ui.Services/Cps.Fct.Hk.Ui.Services.csproj index eda5414d7..426d86861 100644 --- a/Cps.Fct.Hk.Ui.Services/Cps.Fct.Hk.Ui.Services.csproj +++ b/Cps.Fct.Hk.Ui.Services/Cps.Fct.Hk.Ui.Services.csproj @@ -16,8 +16,8 @@ - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive @@ -26,7 +26,7 @@ - + diff --git a/DdeiClient/DdeiClient.csproj b/DdeiClient/DdeiClient.csproj index ed08a699a..5d65fc681 100644 --- a/DdeiClient/DdeiClient.csproj +++ b/DdeiClient/DdeiClient.csproj @@ -16,7 +16,7 @@ - + diff --git a/hkui-functions-integration-tests/hkui-functions-integration-tests.csproj b/hkui-functions-integration-tests/hkui-functions-integration-tests.csproj index a5d42ac66..e8632b0dd 100644 --- a/hkui-functions-integration-tests/hkui-functions-integration-tests.csproj +++ b/hkui-functions-integration-tests/hkui-functions-integration-tests.csproj @@ -11,18 +11,18 @@ HkuiFunctionsIntegrationTests - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/polaris-gateway.tests/polaris-gateway.tests.csproj b/polaris-gateway.tests/polaris-gateway.tests.csproj index 0ccd78d6b..751462ef1 100644 --- a/polaris-gateway.tests/polaris-gateway.tests.csproj +++ b/polaris-gateway.tests/polaris-gateway.tests.csproj @@ -19,22 +19,22 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + - + runtime; build; native; contentfiles; analyzers; buildtransitive all - + runtime; build; native; contentfiles; analyzers; buildtransitive all - + diff --git a/polaris-gateway/polaris-gateway.csproj b/polaris-gateway/polaris-gateway.csproj index bc0e7d35a..eec092d5f 100644 --- a/polaris-gateway/polaris-gateway.csproj +++ b/polaris-gateway/polaris-gateway.csproj @@ -18,12 +18,12 @@ - + - - - + + + PreserveNewest diff --git a/polaris-pipeline/Common.tests/Common.tests.csproj b/polaris-pipeline/Common.tests/Common.tests.csproj index fe0ba8f5a..b49475123 100644 --- a/polaris-pipeline/Common.tests/Common.tests.csproj +++ b/polaris-pipeline/Common.tests/Common.tests.csproj @@ -24,24 +24,24 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive - - + + - - - + + + runtime; build; native; contentfiles; analyzers; buildtransitive all - + diff --git a/polaris-pipeline/Common/Common.csproj b/polaris-pipeline/Common/Common.csproj index 6d834e186..779b5f98f 100644 --- a/polaris-pipeline/Common/Common.csproj +++ b/polaris-pipeline/Common/Common.csproj @@ -21,8 +21,8 @@ - - + + @@ -33,7 +33,7 @@ - + diff --git a/polaris-pipeline/DdeiClient.tests/MdsClient.tests.csproj b/polaris-pipeline/DdeiClient.tests/MdsClient.tests.csproj index 4d9c93afa..ae99cdc2c 100644 --- a/polaris-pipeline/DdeiClient.tests/MdsClient.tests.csproj +++ b/polaris-pipeline/DdeiClient.tests/MdsClient.tests.csproj @@ -26,20 +26,20 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + - - - + + + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/polaris-pipeline/coordinator.tests/coordinator.tests.csproj b/polaris-pipeline/coordinator.tests/coordinator.tests.csproj index d944f2a21..e3311b876 100644 --- a/polaris-pipeline/coordinator.tests/coordinator.tests.csproj +++ b/polaris-pipeline/coordinator.tests/coordinator.tests.csproj @@ -30,25 +30,25 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive - - + + - - - + + + runtime; build; native; contentfiles; analyzers; buildtransitive all - + \ No newline at end of file diff --git a/polaris-pipeline/coordinator/coordinator.csproj b/polaris-pipeline/coordinator/coordinator.csproj index 5a2aef124..317f84ed0 100644 --- a/polaris-pipeline/coordinator/coordinator.csproj +++ b/polaris-pipeline/coordinator/coordinator.csproj @@ -16,8 +16,8 @@ - - + + @@ -32,11 +32,11 @@ - - - + + + - + diff --git a/polaris-pipeline/pdf-generator.tests/pdf-generator.tests.csproj b/polaris-pipeline/pdf-generator.tests/pdf-generator.tests.csproj index 22efcf4cf..39cfb2d81 100644 --- a/polaris-pipeline/pdf-generator.tests/pdf-generator.tests.csproj +++ b/polaris-pipeline/pdf-generator.tests/pdf-generator.tests.csproj @@ -37,24 +37,24 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + - - + + runtime; build; native; contentfiles; analyzers; buildtransitive all - - - + + + diff --git a/polaris-pipeline/pdf-generator/pdf-generator.csproj b/polaris-pipeline/pdf-generator/pdf-generator.csproj index 717212ad7..ab1819963 100644 --- a/polaris-pipeline/pdf-generator/pdf-generator.csproj +++ b/polaris-pipeline/pdf-generator/pdf-generator.csproj @@ -12,12 +12,12 @@ - - + + - + diff --git a/polaris-pipeline/pdf-redactor.tests/pdf-redactor.tests.csproj b/polaris-pipeline/pdf-redactor.tests/pdf-redactor.tests.csproj index 26e5817d5..b6e7f391b 100644 --- a/polaris-pipeline/pdf-redactor.tests/pdf-redactor.tests.csproj +++ b/polaris-pipeline/pdf-redactor.tests/pdf-redactor.tests.csproj @@ -35,24 +35,24 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + - - + + runtime; build; native; contentfiles; analyzers; buildtransitive all - - - + + + diff --git a/polaris-pipeline/pdf-redactor/pdf-redactor.csproj b/polaris-pipeline/pdf-redactor/pdf-redactor.csproj index 8cc086a66..2b6fe3253 100644 --- a/polaris-pipeline/pdf-redactor/pdf-redactor.csproj +++ b/polaris-pipeline/pdf-redactor/pdf-redactor.csproj @@ -11,12 +11,12 @@ - - + + - + diff --git a/polaris-pipeline/pdf-thumbnail-generator/pdf-thumbnail-generator.csproj b/polaris-pipeline/pdf-thumbnail-generator/pdf-thumbnail-generator.csproj index 0215b30ba..d7bb0d057 100644 --- a/polaris-pipeline/pdf-thumbnail-generator/pdf-thumbnail-generator.csproj +++ b/polaris-pipeline/pdf-thumbnail-generator/pdf-thumbnail-generator.csproj @@ -16,12 +16,12 @@ - + - + diff --git a/polaris-pipeline/text-extractor.tests/text-extractor.tests.csproj b/polaris-pipeline/text-extractor.tests/text-extractor.tests.csproj index fbf86b6db..2f07cda3f 100644 --- a/polaris-pipeline/text-extractor.tests/text-extractor.tests.csproj +++ b/polaris-pipeline/text-extractor.tests/text-extractor.tests.csproj @@ -1,4 +1,4 @@ - + net10.0 @@ -23,25 +23,25 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive - - - - + + + + runtime; build; native; contentfiles; analyzers; buildtransitive all - - - + + + From c3f62a0c8ee38621cd4a62953b5c3d2c7fde8763 Mon Sep 17 00:00:00 2001 From: kramduny-cps Date: Wed, 17 Jun 2026 09:23:50 +0100 Subject: [PATCH 03/19] #FCT2-19296 - accommodate new style load balancing cookie (#2058) (#2065) Co-authored-by: stef --- polaris-terraform/main-terraform/nginx.conf | 54 +++++++++++++++++++-- polaris-terraform/main-terraform/nginx.js | 19 +++++--- 2 files changed, 63 insertions(+), 10 deletions(-) diff --git a/polaris-terraform/main-terraform/nginx.conf b/polaris-terraform/main-terraform/nginx.conf index 2ad0110f5..6a08322b7 100644 --- a/polaris-terraform/main-terraform/nginx.conf +++ b/polaris-terraform/main-terraform/nginx.conf @@ -415,6 +415,13 @@ http { add_header Set-Cookie "BIGipServer~ent-s221~CPSAFP-LTM-CM-WAN-CIN4-cin4.cps.gov.uk_POOL=deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT"; add_header Set-Cookie "BIGipServer~ent-s221~CPSACP-LTM-CM-WAN-CIN5-cin5.cps.gov.uk_POOL=deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT"; add_header Set-Cookie "BIGipServer~ent-s221~CPSAFP-LTM-CM-WAN-CIN5-cin5.cps.gov.uk_POOL=deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT"; + + add_header Set-Cookie "C-CIN2-LBsessioncookie=deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT"; + add_header Set-Cookie "F-CIN2-LBsessioncookie=deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT"; + add_header Set-Cookie "C-CIN4-LBsessioncookie=deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT"; + add_header Set-Cookie "F-CIN4-LBsessioncookie=deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT"; + add_header Set-Cookie "C-CIN5-LBsessioncookie=deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT"; + add_header Set-Cookie "F-CIN5-LBsessioncookie=deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT"; return 302 "${WEBSITE_SCHEME}://${host}/CMS"; } @@ -438,6 +445,13 @@ http { add_header Set-Cookie "BIGipServer~ent-s221~CPSAFP-LTM-CM-WAN-CIN4-cin4.cps.gov.uk_POOL=deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT"; add_header Set-Cookie "BIGipServer~ent-s221~CPSACP-LTM-CM-WAN-CIN5-cin5.cps.gov.uk_POOL=deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT"; add_header Set-Cookie "BIGipServer~ent-s221~CPSAFP-LTM-CM-WAN-CIN5-cin5.cps.gov.uk_POOL=deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT"; + + add_header Set-Cookie "C-CIN3-LBsessioncookie=deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT"; + add_header Set-Cookie "F-CIN3-LBsessioncookie=deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT"; + add_header Set-Cookie "C-CIN4-LBsessioncookie=deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT"; + add_header Set-Cookie "F-CIN4-LBsessioncookie=deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT"; + add_header Set-Cookie "C-CIN5-LBsessioncookie=deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT"; + add_header Set-Cookie "F-CIN5-LBsessioncookie=deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT"; return 302 "${WEBSITE_SCHEME}://${host}/CMS"; } @@ -461,6 +475,13 @@ http { add_header Set-Cookie "BIGipServer~ent-s221~CPSAFP-LTM-CM-WAN-CIN3-cin3.cps.gov.uk_POOL=deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT"; add_header Set-Cookie "BIGipServer~ent-s221~CPSACP-LTM-CM-WAN-CIN5-cin5.cps.gov.uk_POOL=deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT"; add_header Set-Cookie "BIGipServer~ent-s221~CPSAFP-LTM-CM-WAN-CIN5-cin5.cps.gov.uk_POOL=deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT"; + + add_header Set-Cookie "C-CIN2-LBsessioncookie=deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT"; + add_header Set-Cookie "F-CIN2-LBsessioncookie=deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT"; + add_header Set-Cookie "C-CIN3-LBsessioncookie=deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT"; + add_header Set-Cookie "F-CIN3-LBsessioncookie=deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT"; + add_header Set-Cookie "C-CIN5-LBsessioncookie=deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT"; + add_header Set-Cookie "F-CIN5-LBsessioncookie=deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT"; return 302 "${WEBSITE_SCHEME}://${host}/CMS"; } @@ -484,6 +505,13 @@ http { add_header Set-Cookie "BIGipServer~ent-s221~CPSAFP-LTM-CM-WAN-CIN3-cin3.cps.gov.uk_POOL=deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT"; add_header Set-Cookie "BIGipServer~ent-s221~CPSACP-LTM-CM-WAN-CIN4-cin4.cps.gov.uk_POOL=deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT"; add_header Set-Cookie "BIGipServer~ent-s221~CPSAFP-LTM-CM-WAN-CIN4-cin4.cps.gov.uk_POOL=deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT"; + + add_header Set-Cookie "C-CIN2-LBsessioncookie=deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT"; + add_header Set-Cookie "F-CIN2-LBsessioncookie=deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT"; + add_header Set-Cookie "C-CIN3-LBsessioncookie=deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT"; + add_header Set-Cookie "F-CIN3-LBsessioncookie=deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT"; + add_header Set-Cookie "C-CIN4-LBsessioncookie=deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT"; + add_header Set-Cookie "F-CIN4-LBsessioncookie=deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT"; return 302 "${WEBSITE_SCHEME}://${host}/CMS"; } @@ -715,12 +743,21 @@ http { add_header Set-Cookie "__CMSENV=deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT"; add_header Set-Cookie "BIGipServer~ent-s221~CPSACP-LTM-CM-WAN-CIN2-cin2.cps.gov.uk_POOL=deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT"; add_header Set-Cookie "BIGipServer~ent-s221~CPSAFP-LTM-CM-WAN-CIN2-cin2.cps.gov.uk_POOL=deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT"; - add_header Set-Cookie "BIGipServer~ent-s221~CPSACP-LTM-CM-WAN-CIN4-cin3.cps.gov.uk_POOL=deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT"; - add_header Set-Cookie "BIGipServer~ent-s221~CPSAFP-LTM-CM-WAN-CIN4-cin3.cps.gov.uk_POOL=deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT"; + add_header Set-Cookie "BIGipServer~ent-s221~CPSACP-LTM-CM-WAN-CIN3-cin3.cps.gov.uk_POOL=deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT"; + add_header Set-Cookie "BIGipServer~ent-s221~CPSAFP-LTM-CM-WAN-CIN3-cin3.cps.gov.uk_POOL=deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT"; add_header Set-Cookie "BIGipServer~ent-s221~CPSACP-LTM-CM-WAN-CIN4-cin4.cps.gov.uk_POOL=deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT"; add_header Set-Cookie "BIGipServer~ent-s221~CPSAFP-LTM-CM-WAN-CIN4-cin4.cps.gov.uk_POOL=deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT"; add_header Set-Cookie "BIGipServer~ent-s221~CPSACP-LTM-CM-WAN-CIN5-cin5.cps.gov.uk_POOL=deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT"; add_header Set-Cookie "BIGipServer~ent-s221~CPSAFP-LTM-CM-WAN-CIN5-cin5.cps.gov.uk_POOL=deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT"; + + add_header Set-Cookie "C-CIN2-LBsessioncookie=deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT"; + add_header Set-Cookie "F-CIN2-LBsessioncookie=deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT"; + add_header Set-Cookie "C-CIN3-LBsessioncookie=deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT"; + add_header Set-Cookie "F-CIN3-LBsessioncookie=deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT"; + add_header Set-Cookie "C-CIN4-LBsessioncookie=deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT"; + add_header Set-Cookie "F-CIN4-LBsessioncookie=deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT"; + add_header Set-Cookie "C-CIN5-LBsessioncookie=deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT"; + add_header Set-Cookie "F-CIN5-LBsessioncookie=deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT"; } # Set an environment cookie so the Open Modern link works @@ -737,12 +774,21 @@ http { add_header Set-Cookie "__CMSENV=deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT"; add_header Set-Cookie "BIGipServer~ent-s221~CPSACP-LTM-CM-WAN-CIN2-cin2.cps.gov.uk_POOL=deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT"; add_header Set-Cookie "BIGipServer~ent-s221~CPSAFP-LTM-CM-WAN-CIN2-cin2.cps.gov.uk_POOL=deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT"; - add_header Set-Cookie "BIGipServer~ent-s221~CPSACP-LTM-CM-WAN-CIN4-cin3.cps.gov.uk_POOL=deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT"; - add_header Set-Cookie "BIGipServer~ent-s221~CPSAFP-LTM-CM-WAN-CIN4-cin3.cps.gov.uk_POOL=deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT"; + add_header Set-Cookie "BIGipServer~ent-s221~CPSACP-LTM-CM-WAN-CIN3-cin3.cps.gov.uk_POOL=deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT"; + add_header Set-Cookie "BIGipServer~ent-s221~CPSAFP-LTM-CM-WAN-CIN3-cin3.cps.gov.uk_POOL=deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT"; add_header Set-Cookie "BIGipServer~ent-s221~CPSACP-LTM-CM-WAN-CIN4-cin4.cps.gov.uk_POOL=deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT"; add_header Set-Cookie "BIGipServer~ent-s221~CPSAFP-LTM-CM-WAN-CIN4-cin4.cps.gov.uk_POOL=deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT"; add_header Set-Cookie "BIGipServer~ent-s221~CPSACP-LTM-CM-WAN-CIN5-cin5.cps.gov.uk_POOL=deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT"; add_header Set-Cookie "BIGipServer~ent-s221~CPSAFP-LTM-CM-WAN-CIN5-cin5.cps.gov.uk_POOL=deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT"; + + add_header Set-Cookie "C-CIN2-LBsessioncookie=deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT"; + add_header Set-Cookie "F-CIN2-LBsessioncookie=deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT"; + add_header Set-Cookie "C-CIN3-LBsessioncookie=deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT"; + add_header Set-Cookie "F-CIN3-LBsessioncookie=deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT"; + add_header Set-Cookie "C-CIN4-LBsessioncookie=deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT"; + add_header Set-Cookie "F-CIN4-LBsessioncookie=deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT"; + add_header Set-Cookie "C-CIN5-LBsessioncookie=deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT"; + add_header Set-Cookie "F-CIN5-LBsessioncookie=deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT"; } # Set an environment cookie so the Open Modern link works diff --git a/polaris-terraform/main-terraform/nginx.js b/polaris-terraform/main-terraform/nginx.js index 564b24103..575fd30e9 100644 --- a/polaris-terraform/main-terraform/nginx.js +++ b/polaris-terraform/main-terraform/nginx.js @@ -69,12 +69,19 @@ function setSessionHintCookie(r) { let cookieValue try { const isProxySession = r.args[IS_PROXY_SESSION_PARAM_NAME] === "true" - // Match lowercase subdomain(s) followed by .cps.gov.uk (terminated by _POOL) - // This avoids matching uppercase prefixes like CPSACP-LTM-CM-WAN-CIN3- - const cmsDomains = - r.args["cookie"].match( - /[a-z][a-z0-9]*(?:\.[a-z][a-z0-9]*)*\.cps\.gov\.uk(?=_POOL)/g - ) || [] + const cookie = r.args["cookie"] + // The environment domain (e.g. cin3.cps.gov.uk) can come from either LB cookie style. + // Prefer the load-balancing cookie, named [CF]--LBsessioncookie (e.g. C-CIN3-..., + // F-FOO-...), and derive .cps.gov.uk from the TOKEN. Fall back to the legacy + // BIGipServer* cookie, whose name embeds the domain immediately before _POOL. + const loadBalancingCookies = cookie.match(/(?:^|;\s*)[CF]-[^=;]*-LBsessioncookie/g) || [] + const cmsDomains = loadBalancingCookies.length + ? loadBalancingCookies.map( + (m) => `${m.match(/[CF]-([^=;]*)-LBsessioncookie/)[1].toLowerCase()}.cps.gov.uk` + ) + : // Match lowercase subdomain(s) followed by .cps.gov.uk (terminated by _POOL). + // This avoids matching uppercase prefixes like CPSACP-LTM-CM-WAN-CIN3-. + cookie.match(/[a-z][a-z0-9]*(?:\.[a-z][a-z0-9]*)*\.cps\.gov\.uk(?=_POOL)/g) || [] const handoverEndpoint = isProxySession ? `https://${r.headersIn["Host"]}/polaris` From a668bf97123e3ddf7e23fc3195e567b44b2df4bd Mon Sep 17 00:00:00 2001 From: kramduny-cps Date: Wed, 17 Jun 2026 12:36:03 +0100 Subject: [PATCH 04/19] Fix e2e tests after .net10 upgrade (#2066) --- .../pipelines/stages/jobs/job_prepare-dot-net-tests.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/polaris-e2e/pipelines/stages/jobs/job_prepare-dot-net-tests.yml b/polaris-e2e/pipelines/stages/jobs/job_prepare-dot-net-tests.yml index 141528293..4744777a6 100644 --- a/polaris-e2e/pipelines/stages/jobs/job_prepare-dot-net-tests.yml +++ b/polaris-e2e/pipelines/stages/jobs/job_prepare-dot-net-tests.yml @@ -33,7 +33,7 @@ jobs: - task: FileTransform@2 displayName: "Transform Integration Test Settings" inputs: - folderPath: "$(System.DefaultWorkingDirectory)/polaris-pipeline/pdf-redactor.integration.tests/bin/Release/net8.0" + folderPath: "$(System.DefaultWorkingDirectory)/polaris-pipeline/pdf-redactor.integration.tests/bin/Release/net10.0" jsonTargetFiles: "appSettings.json" xmlTransformationRules: "" # disabled, prevents non-windows-platform error @@ -41,11 +41,11 @@ jobs: inputs: sourceFolder: $(Agent.TempDirectory) contents: Aspose.Total.NET.lic - targetFolder: "$(System.DefaultWorkingDirectory)/polaris-pipeline/pdf-redactor.integration.tests/bin/Release/net8.0" + targetFolder: "$(System.DefaultWorkingDirectory)/polaris-pipeline/pdf-redactor.integration.tests/bin/Release/net10.0" displayName: "Copy Aspose.Total.NET.lic" - task: PublishPipelineArtifact@1 inputs: - targetPath: "$(System.DefaultWorkingDirectory)/polaris-pipeline/pdf-redactor.integration.tests/bin/Release/net8.0" + targetPath: "$(System.DefaultWorkingDirectory)/polaris-pipeline/pdf-redactor.integration.tests/bin/Release/net10.0" artifact: "pdf-redactor-tests-drop" displayName: "Publish PDF Redactor tests artifact" \ No newline at end of file From ac59ab6c854a42a6d17eb0cd05c5a6226b20c294 Mon Sep 17 00:00:00 2001 From: dbarber-cps Date: Thu, 18 Jun 2026 14:16:30 +0100 Subject: [PATCH 05/19] Chore/fix dotnet agents (#2069) * adding dotnet install on agents * dotnet10 install during e2e testing * dotnet10 install --- polaris-devops-pipelines/scale-set/build-agent.sh | 1 + .../pipelines/stages/jobs/job_prepare-dot-net-tests.yml | 8 ++++++++ .../pipelines/stages/jobs/job_run-dot-net-tests.yml | 7 +++++++ 3 files changed, 16 insertions(+) diff --git a/polaris-devops-pipelines/scale-set/build-agent.sh b/polaris-devops-pipelines/scale-set/build-agent.sh index db9579670..9f1ea0fe2 100644 --- a/polaris-devops-pipelines/scale-set/build-agent.sh +++ b/polaris-devops-pipelines/scale-set/build-agent.sh @@ -113,6 +113,7 @@ wget https://dot.net/v1/dotnet-install.sh -O dotnet-install.sh sudo chmod +x ./dotnet-install.sh ./dotnet-install.sh --channel 6.0 --quality GA ./dotnet-install.sh --channel 7.0 --quality GA +./dotnet-install.sh --channel 10.0 --quality GA echo 'export DOTNET_ROOT=$HOME/.dotnet' >> ~/.bashrc echo 'export PATH=$PATH:$DOTNET_ROOT:$DOTNET_ROOT/tools' >> ~/.bashrc diff --git a/polaris-e2e/pipelines/stages/jobs/job_prepare-dot-net-tests.yml b/polaris-e2e/pipelines/stages/jobs/job_prepare-dot-net-tests.yml index 4744777a6..f594d24bb 100644 --- a/polaris-e2e/pipelines/stages/jobs/job_prepare-dot-net-tests.yml +++ b/polaris-e2e/pipelines/stages/jobs/job_prepare-dot-net-tests.yml @@ -8,6 +8,14 @@ jobs: pool: vmImage: 'windows-latest' steps: + + - task: UseDotNet@2 + displayName: Install .NET SDK 10.x + inputs: + packageType: sdk + version: '10.x' + includePreviewVersions: true + - checkout: ${{ parameters.checkoutRef }} clean: true persistCredentials: true diff --git a/polaris-e2e/pipelines/stages/jobs/job_run-dot-net-tests.yml b/polaris-e2e/pipelines/stages/jobs/job_run-dot-net-tests.yml index a614ff5a4..9c120e8a1 100644 --- a/polaris-e2e/pipelines/stages/jobs/job_run-dot-net-tests.yml +++ b/polaris-e2e/pipelines/stages/jobs/job_run-dot-net-tests.yml @@ -6,6 +6,13 @@ jobs: dependsOn: Prepare_DotNet_Tests steps: + - task: UseDotNet@2 + displayName: Install .NET SDK 10.x + inputs: + packageType: sdk + version: '10.x' + includePreviewVersions: true + - task: NuGetAuthenticate@1 displayName: 'Authenticate to NuGet Feed' From be3cce0f3ada7619ba5588fa958f4c1f4556f666 Mon Sep 17 00:00:00 2001 From: TahmeedAhmed-NTT-CPS Date: Thu, 18 Jun 2026 17:06:46 +0100 Subject: [PATCH 06/19] Feature/fct2 18423 generate dac doc for single defendants (#2070) * added change to include dac docs for all defendants --- .../MdsCaseDocumentsOrchestrationService.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/polaris-gateway/Services/MdsOrchestration/MdsCaseDocumentsOrchestrationService.cs b/polaris-gateway/Services/MdsOrchestration/MdsCaseDocumentsOrchestrationService.cs index a5d47e1a1..baad44c1c 100644 --- a/polaris-gateway/Services/MdsOrchestration/MdsCaseDocumentsOrchestrationService.cs +++ b/polaris-gateway/Services/MdsOrchestration/MdsCaseDocumentsOrchestrationService.cs @@ -48,9 +48,11 @@ public async Task> GetCaseDocuments(MdsCaseIdentifiersA return Enumerable.Empty() .Concat(cmsDocuments.Select(MapDocument)) .Concat(pcdRequests.Select(MapPcdRequest)) - .Concat(defendantAndCharges.DefendantsAndCharges.Count() > 1 || defendantAndCharges.DefendantsAndCharges.Any(x => x.Charges.Count() > 1) - ? [MapDefendantAndCharges(defendantAndCharges)] - : [] + .Concat( + defendantAndCharges.DefendantsAndCharges.Any() || + defendantAndCharges.DefendantsAndCharges.Any(x => x.Charges.Any()) + ? [MapDefendantAndCharges(defendantAndCharges)] + : [] ); } From 8ca5d05ffd296120e1e076a4402f908f35802a62 Mon Sep 17 00:00:00 2001 From: kramduny-cps Date: Mon, 22 Jun 2026 14:27:46 +0100 Subject: [PATCH 07/19] Downmerge from Main (#2072) * #FCT2-19296 - accommodate new style load balancing cookie (#2058) * #FCT2-19296 - allow pre-prod environment switching via new style load balancing cookies (#2068) * #FCT2-19296 - allow pre-prod environment switching via new style load balancing cookies * #FCT2-19296 - allow pre-prod environment switching via new style load balancing cookies --------- Co-authored-by: stef --- polaris-terraform/main-terraform/cmsenv.js | 1 + 1 file changed, 1 insertion(+) diff --git a/polaris-terraform/main-terraform/cmsenv.js b/polaris-terraform/main-terraform/cmsenv.js index a07e27f77..8122af0af 100644 --- a/polaris-terraform/main-terraform/cmsenv.js +++ b/polaris-terraform/main-terraform/cmsenv.js @@ -161,6 +161,7 @@ function __getCmsEnvCookieOut(r) { } function __getCmsEnvInternal(cookie) { + cookie = cookie.toLowerCase(); if (cookie.includes("cin3")) return "default"; if (cookie.includes("cin2")) return "cin2"; if (cookie.includes("cin4")) return "cin4"; From da591dcf0733f2fabbb8e9247b42b9348bab540e Mon Sep 17 00:00:00 2001 From: dbarber-cps Date: Mon, 22 Jun 2026 15:19:14 +0100 Subject: [PATCH 08/19] Feature/fct2 19668 branching (#2071) * changes to support branch change to development * changes to handle powershell syntax errors * changes to pr to support both triggers from dev and main * powershell typo updates * resolving single file path string issue * typo fix * adding comments to simulate file changes for PR tests * removing temporary tests * adding comments for stage: Determine_Changes * updating release dev to only run from refs/heads/development --- .../deployments_v2/polaris-pr.yml | 28 +++++++++++++++++-- .../deployments_v2/polaris-release-dev.yml | 2 +- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/polaris-devops-pipelines/deployments_v2/polaris-pr.yml b/polaris-devops-pipelines/deployments_v2/polaris-pr.yml index bebb999e2..57c6cdb6c 100644 --- a/polaris-devops-pipelines/deployments_v2/polaris-pr.yml +++ b/polaris-devops-pipelines/deployments_v2/polaris-pr.yml @@ -4,6 +4,7 @@ trigger: none pr: branches: include: + - development - main paths: include: @@ -37,6 +38,7 @@ stages: parameters: devOpsPatToken: $(System.AccessToken) + #Stage to validate only the parts of Polaris impacted by a pull request, rather than running every validation job on every PR. - stage: Determine_Changes displayName: Determine Changes dependsOn: Wait_For_Running_PRs @@ -45,12 +47,34 @@ stages: pool: name: $(dev-build-agent) steps: + - checkout: self + fetchDepth: 0 + - task: PowerShell@2 inputs: targetType: 'inline' script: | - $files = $(git diff --name-only origin/main) - $temp=$files -split ' ' + $targetBranch = $env:SYSTEM_PULLREQUEST_TARGETBRANCH + $targetBranchOverride = $env:TARGETBRANCHOVERRIDE + + # Optional override to support manual runs. + if ([string]::IsNullOrWhiteSpace($targetBranch) -and -not [string]::IsNullOrWhiteSpace($targetBranchOverride)) + { + $targetBranch = $targetBranchOverride + } + + if ([string]::IsNullOrWhiteSpace($targetBranch)) + { + # Default for non-PR runs when no override is provided. + $targetBranch = "refs/heads/development" + } + + $targetBranchName = $targetBranch -replace '^refs/heads/', '' + echo "Comparing changes against origin/$targetBranchName" + + git fetch origin "+refs/heads/${targetBranchName}:refs/remotes/origin/${targetBranchName}" --depth=200 + + $temp = @(git diff --name-only "origin/$targetBranchName...HEAD" | ForEach-Object { $_.Trim() } | Where-Object { -not [string]::IsNullOrWhiteSpace($_) }) $count=$temp.Length echo "Total changed $count files" diff --git a/polaris-devops-pipelines/deployments_v2/polaris-release-dev.yml b/polaris-devops-pipelines/deployments_v2/polaris-release-dev.yml index 2744a25a2..dcdd7e167 100644 --- a/polaris-devops-pipelines/deployments_v2/polaris-release-dev.yml +++ b/polaris-devops-pipelines/deployments_v2/polaris-release-dev.yml @@ -9,7 +9,7 @@ resources: trigger: branches: include: - - refs/heads/main + - refs/heads/development stages: - Publish_Artifacts From d7e3035280822d673027d03d1842c720bc42d7fb Mon Sep 17 00:00:00 2001 From: cpsgopisivanappanvasanthi Date: Mon, 22 Jun 2026 18:07:00 +0100 Subject: [PATCH 09/19] Bug fix - FCT2-19721 - Upgarded the Aspose PDF Drawing library for hte pdf-redactor azure function alone to fix the issue with the pdf redaction. (#2073) --- polaris-pipeline/pdf-redactor/pdf-redactor.csproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/polaris-pipeline/pdf-redactor/pdf-redactor.csproj b/polaris-pipeline/pdf-redactor/pdf-redactor.csproj index 2b6fe3253..cad31a0ea 100644 --- a/polaris-pipeline/pdf-redactor/pdf-redactor.csproj +++ b/polaris-pipeline/pdf-redactor/pdf-redactor.csproj @@ -10,8 +10,8 @@ - - + + From 508343e5b9b5be0c6a3024db48a06c5b23586211 Mon Sep 17 00:00:00 2001 From: dbarber-cps Date: Thu, 25 Jun 2026 14:14:37 +0100 Subject: [PATCH 10/19] Fct2 19668pipeline triggers (#2074) * pipeline changes to support new branches * removing trigger of QA build pipeline --- .../deployments_v2/polaris-release-dev.yml | 19 ++++++----- ...ld.yml => polaris-triggered-build-dev.yml} | 0 .../polaris-triggered-build-uat.yml | 34 +++++++++++++++++++ 3 files changed, 44 insertions(+), 9 deletions(-) rename polaris-devops-pipelines/deployments_v2/{polaris-triggered-build.yml => polaris-triggered-build-dev.yml} (100%) create mode 100644 polaris-devops-pipelines/deployments_v2/polaris-triggered-build-uat.yml diff --git a/polaris-devops-pipelines/deployments_v2/polaris-release-dev.yml b/polaris-devops-pipelines/deployments_v2/polaris-release-dev.yml index dcdd7e167..c8f5c7e58 100644 --- a/polaris-devops-pipelines/deployments_v2/polaris-release-dev.yml +++ b/polaris-devops-pipelines/deployments_v2/polaris-release-dev.yml @@ -110,12 +110,13 @@ stages: buildDefinitionId: 588 stageDependsOn: Update_GitHub_Tag - - template: stages/stage_schedule-releases.yml - parameters: - targetBuild: PolarisBuild - targetLabel: "DEV" - appInsightsKey: $(innovation-development-app-insights-instrumentation-key) - environments: - - name: QA - targetLabel: 'QA' - buildDefinitionId: '352' \ No newline at end of file +# Task is no longer required as QA/PROD environments are now deployed via separate branch triggers. The following template is commented out to avoid confusion, but is left in place for reference. + # - template: stages/stage_schedule-releases.yml + # parameters: + # targetBuild: PolarisBuild + # targetLabel: "DEV" + # appInsightsKey: $(innovation-development-app-insights-instrumentation-key) + # environments: + # - name: QA + # targetLabel: 'QA' + # buildDefinitionId: '352' \ No newline at end of file diff --git a/polaris-devops-pipelines/deployments_v2/polaris-triggered-build.yml b/polaris-devops-pipelines/deployments_v2/polaris-triggered-build-dev.yml similarity index 100% rename from polaris-devops-pipelines/deployments_v2/polaris-triggered-build.yml rename to polaris-devops-pipelines/deployments_v2/polaris-triggered-build-dev.yml diff --git a/polaris-devops-pipelines/deployments_v2/polaris-triggered-build-uat.yml b/polaris-devops-pipelines/deployments_v2/polaris-triggered-build-uat.yml new file mode 100644 index 000000000..c8558a8bd --- /dev/null +++ b/polaris-devops-pipelines/deployments_v2/polaris-triggered-build-uat.yml @@ -0,0 +1,34 @@ +--- +name: '$(majorMinorVersion).$(Year:yy)$(DayOfYear).$(semanticVersion)-ci' + +trigger: + batch: true + branches: + include: + - main + paths: + include: + - polaris-terraform/main-terraform/* + - polaris-gateway/* + - polaris-maintenance/* + - polaris-pipeline/* + - polaris-ui/* + - polaris-e2e/* + +pr: none + +variables: + - name: buildConfiguration + value: "Release" + - name: majorMinorVersion + value: "1.0" + - name: semanticVersion + value: "$[counter(variables['majorMinorVersion'], 1)]" + +pool: + name: $(build-agent) + +stages: + - template: stages/stage_publish-all-artifacts.yml + parameters: + environment: $(environment) \ No newline at end of file From d4343ddb6a73310aa9e878ef97213d24d09ddee4 Mon Sep 17 00:00:00 2001 From: kramduny-cps Date: Wed, 1 Jul 2026 15:39:49 +0100 Subject: [PATCH 11/19] Sync Dev with Main (#2080) * #FCT2-19296 - accommodate new style load balancing cookie (#2058) * #FCT2-19296 - allow pre-prod environment switching via new style load balancing cookies (#2068) * #FCT2-19296 - allow pre-prod environment switching via new style load balancing cookies * #FCT2-19296 - allow pre-prod environment switching via new style load balancing cookies * fix to remove user groups for hk and case review (#2067) * fix to remove user groups for hk and case review * removed unused references * sonarqube issue fix * FCT2_20202 - Fix Authentication on Materials UI (#2076) * FCT2_20202 - Fix Authentication on Materials UI * Fix HK Unit tests * handle null cookies from unit tests * Make BuildCmsAuthValues static method * Revert "Make BuildCmsAuthValues static method" This reverts commit d07216008e2dac62fc1f8193bf95019c07a3ca35. * new yaml structure for triggered builds from PRs (#2078) --------- Co-authored-by: stef Co-authored-by: TahmeedAhmed-NTT-CPS Co-authored-by: dbarber-cps --- .../BulkSetUnusedServiceTests.cs | 10 +- .../CaseActionPlanServiceTests.cs | 6 +- .../CaseInfoServiceTests.cs | 6 +- .../CaseMaterialServiceTests.cs | 13 +- .../CommunicationServiceTests.cs | 97 +- .../DocumentServiceTests.cs | 8 +- ...sificationOrchestrationServiceUnitTests.cs | 8 +- .../WitnessServiceTests.cs | 14 +- DdeiClient/Clients/MasterDataServiceClient.cs | 2775 ++++++++--------- DdeiClient/Model/MasterDataServiceCookie.cs | 43 - hkui-functions-integration-tests/TestBase.cs | 2 +- .../polaris-triggered-build-qa.yml | 34 + .../CaseDefendantsServiceTests.cs | 6 +- .../CompleteReclassificationTests.cs | 10 +- .../HouseKeeping/DiscardMaterialTests.cs | 28 +- polaris-gateway/Functions/BaseFunction.cs | 62 +- .../Common/Dto/Request/CmsAuthValues.cs | 18 +- .../app/auth/msal/useUserGroupsFeatureFlag.ts | 18 - .../features/cases/domain/CombinedState.ts | 2 - .../features/cases/domain/FeatureFlagData.ts | 4 - .../cases/presentation/case-details/index.tsx | 54 +- 21 files changed, 1463 insertions(+), 1755 deletions(-) delete mode 100644 DdeiClient/Model/MasterDataServiceCookie.cs create mode 100644 polaris-devops-pipelines/deployments_v2/polaris-triggered-build-qa.yml diff --git a/Cps.Fct.Hk.Ui.Services.Tests/BulkSetUnusedServiceTests.cs b/Cps.Fct.Hk.Ui.Services.Tests/BulkSetUnusedServiceTests.cs index c787f345d..e856b82ec 100644 --- a/Cps.Fct.Hk.Ui.Services.Tests/BulkSetUnusedServiceTests.cs +++ b/Cps.Fct.Hk.Ui.Services.Tests/BulkSetUnusedServiceTests.cs @@ -53,7 +53,7 @@ public async Task BulkSetUnusedAsync_AllMaterialsReclassified_ReturnsSuccess() }; // var cmsAuthValues = new CmsAuthValues(); - var cmsAuthValues = new CmsAuthValues("cookies", "token", Guid.NewGuid()); + var cmsAuthValues = new CmsAuthValues("cookies", Guid.NewGuid()); this.mockApiClient.Setup(client => client.ReclassifyCommunicationAsync(It.IsAny(), It.IsAny())) .ReturnsAsync((ReclassifyCommunicationRequest req, CmsAuthValues _) => @@ -91,7 +91,7 @@ public async Task BulkSetUnusedAsync_PartialSuccess_ReturnsPartialSuccess() new BulkSetUnusedRequest { materialId = 2, subject = "Material 2" }, }; - var cmsAuthValues = new CmsAuthValues("cookies", "token", Guid.NewGuid()); + var cmsAuthValues = new CmsAuthValues("cookies", Guid.NewGuid()); #pragma warning disable CS8620 // Argument cannot be used for parameter due to differences in the nullability of reference types. this.mockApiClient.Setup(client => client.ReclassifyCommunicationAsync(It.IsAny(), cmsAuthValues)) @@ -147,7 +147,7 @@ public async Task BulkSetUnusedAsync_AllMaterialsFail_ReturnsFailed() new BulkSetUnusedRequest { materialId = 2, subject = "Material 2" }, }; - var cmsAuthValues = new CmsAuthValues("cookies", "token", Guid.NewGuid()); + var cmsAuthValues = new CmsAuthValues("cookies", Guid.NewGuid()); this.mockApiClient.Setup(client => client.ReclassifyCommunicationAsync(It.IsAny(), It.IsAny())) .ThrowsAsync(new Exception("Reclassification failed")); @@ -184,7 +184,7 @@ public async Task BulkSetUnusedAsync_ApiThrowsException_ThrowsException() new BulkSetUnusedRequest { materialId = 1, subject = "Material 1" }, }; - var cmsAuthValues = new CmsAuthValues("cookies", "token", Guid.NewGuid()); + var cmsAuthValues = new CmsAuthValues("cookies", Guid.NewGuid()); this.mockApiClient.Setup(client => client.ReclassifyCommunicationAsync(It.IsAny(), cmsAuthValues)) .ThrowsAsync(exception); @@ -223,7 +223,7 @@ public async Task BulkSetUnusedAsync_LogsErrorWhenMaterialFails() new BulkSetUnusedRequest { materialId = 1, subject = "Material 1" }, }; - var cmsAuthValues = new CmsAuthValues("cookies", "token", Guid.NewGuid()); + var cmsAuthValues = new CmsAuthValues("cookies", Guid.NewGuid()); this.mockApiClient.Setup(client => client.ReclassifyCommunicationAsync(It.IsAny(), It.IsAny())) .ThrowsAsync(new Exception("Reclassification failed")); diff --git a/Cps.Fct.Hk.Ui.Services.Tests/CaseActionPlanServiceTests.cs b/Cps.Fct.Hk.Ui.Services.Tests/CaseActionPlanServiceTests.cs index c8fe785db..032826ad6 100644 --- a/Cps.Fct.Hk.Ui.Services.Tests/CaseActionPlanServiceTests.cs +++ b/Cps.Fct.Hk.Ui.Services.Tests/CaseActionPlanServiceTests.cs @@ -55,7 +55,7 @@ public async Task AddCaseActionPlanAsync_ReturnsNoContentResult_WhenApiCallIsSuc // Arrange string urn = "1234567890"; int caseId = 123; - var cmsAuthValues = new CmsAuthValues("validCmsToken", "validCmsCookies"); + var cmsAuthValues = new CmsAuthValues("validCmsToken"); AddCaseActionPlanRequest mockAddCaseActionPlanRequest = CreateMockAddCaseActionPlanRequest(); @@ -101,7 +101,7 @@ public async Task AddCaseActionPlanAsync_ThrowsException_WhenApiCallFails() // Arrange string urn = "1234567890"; int caseId = 123; - var cmsAuthValues = new CmsAuthValues("validCmsToken", "validCmsCookies"); + var cmsAuthValues = new CmsAuthValues("validCmsToken"); AddCaseActionPlanRequest mockAddCaseActionPlanRequest = CreateMockAddCaseActionPlanRequest(); @@ -146,7 +146,7 @@ public async Task AddCaseActionPlanAsync_LogsError_WhenCaseLocked() // Arrange string urn = "1234567890"; int caseId = 123; - var cmsAuthValues = new CmsAuthValues("validCmsToken", "validCmsCookies"); + var cmsAuthValues = new CmsAuthValues("validCmsToken"); AddCaseActionPlanRequest mockAddCaseActionPlanRequest = CreateMockAddCaseActionPlanRequest(); diff --git a/Cps.Fct.Hk.Ui.Services.Tests/CaseInfoServiceTests.cs b/Cps.Fct.Hk.Ui.Services.Tests/CaseInfoServiceTests.cs index 0af60ff75..8de17f7ab 100644 --- a/Cps.Fct.Hk.Ui.Services.Tests/CaseInfoServiceTests.cs +++ b/Cps.Fct.Hk.Ui.Services.Tests/CaseInfoServiceTests.cs @@ -46,7 +46,7 @@ public async Task GetCaseInfoAsync_ReturnsCaseSummary_WhenApiCallIsSuccessful() { // Arrange int caseId = 123; - var cmsAuthValues = new CmsAuthValues("validCmsToken", "validCmsCookies"); + var cmsAuthValues = new CmsAuthValues("validCmsToken"); // Setup the expected CaseSummary result var expectedCaseSummary = new CaseSummaryResponse(caseId, "06SC1234572", "Will", "SMITH", 2, "Hull UT"); @@ -82,7 +82,7 @@ public async Task GetCaseInfoAsync_ThrowsInvalidOperationException_WhenCaseSumma { // Arrange int caseId = 123; - var cmsAuthValues = new CmsAuthValues("validCmsToken", "validCmsCookies"); + var cmsAuthValues = new CmsAuthValues("validCmsToken"); // Setup the API client to return null for the case summary this.apiClientMock @@ -113,7 +113,7 @@ public async Task GetCaseInfoAsync_ThrowsException_WhenApiCallFails() { // Arrange int caseId = 123; - var cmsAuthValues = new CmsAuthValues("validCmsToken", "validCmsCookies"); + var cmsAuthValues = new CmsAuthValues("validCmsToken"); // Setup the API client to throw an exception this.apiClientMock diff --git a/Cps.Fct.Hk.Ui.Services.Tests/CaseMaterialServiceTests.cs b/Cps.Fct.Hk.Ui.Services.Tests/CaseMaterialServiceTests.cs index 83668a18c..03f255311 100644 --- a/Cps.Fct.Hk.Ui.Services.Tests/CaseMaterialServiceTests.cs +++ b/Cps.Fct.Hk.Ui.Services.Tests/CaseMaterialServiceTests.cs @@ -127,7 +127,7 @@ public void MapUsedExhibitsToCaseMaterials_ReturnsMappedCaseMaterials() DateTime receivedDate = new DateTime(2025, 04, 01); int caseId = 123; - var cmsAuthValues = new CmsAuthValues("validCmsToken", "validCmsCookies"); + var cmsAuthValues = new CmsAuthValues("validCmsToken"); var usedExhibitsResponse = new UsedExhibitsResponse { @@ -189,7 +189,7 @@ public void MapUsedExhibitsToCaseMaterials_WithNullDocumentType_ReturnsMappedCas // Arrange DateTime receivedDate = new DateTime(2025, 04, 01); int caseId = 123; - var cmsAuthValues = new CmsAuthValues("validCmsToken", "validCmsCookies"); + var cmsAuthValues = new CmsAuthValues("validCmsToken"); var usedExhibitsResponse = new UsedExhibitsResponse { @@ -855,7 +855,6 @@ public async Task Run_ReturnsUnprocessableEntityError_WhenExceptionIsThrownBy_Ge var cmsAuthValues = new CmsAuthValues( "cookies", - "token", Guid.NewGuid()); this.mockCommunicationService @@ -889,7 +888,6 @@ public async Task Run_ReturnsUnprocessableEntityError_WhenExceptionIsThrownBy_Ge var cmsAuthValues = new CmsAuthValues( "cookies", - "token", Guid.NewGuid()); this.mockCommunicationService @@ -923,7 +921,6 @@ public async Task Run_ReturnsUnprocessableEntityError_WhenExceptionIsThrownBy_Ge var cmsAuthValues = new CmsAuthValues( "cookies", - "token", Guid.NewGuid()); this.mockCommunicationService @@ -957,7 +954,6 @@ public async Task Run_ReturnsUnprocessableEntityError_WhenExceptionIsThrownBy_Ge var cmsAuthValues = new CmsAuthValues( "cookies", - "token", Guid.NewGuid()); this.mockCommunicationService @@ -1329,7 +1325,6 @@ public async Task Run_ReturnsUnprocessableEntityError_WhenExceptionIsThrownBy_Ge // Arrange var cmsAuthValues = new CmsAuthValues( "cookies", - "token", Guid.NewGuid()); this.mockCommunicationService @@ -1361,7 +1356,6 @@ public async Task Run_ReturnsUnprocessableEntityError_WhenExceptionIsThrownBy_Ge // Arrange var cmsAuthValues = new CmsAuthValues( "cookies", - "token", Guid.NewGuid()); this.mockCommunicationService @@ -1395,7 +1389,6 @@ public async Task Run_ReturnsUnprocessableEntityError_WhenExceptionIsThrownBy_Ge var cmsAuthValues = new CmsAuthValues( "cookies", - "token", Guid.NewGuid()); ExhibitProducersResponse exhibitProducersResponse = BuildTestExhibitProducers(); @@ -1430,7 +1423,6 @@ public void MapExistingProducerOrWitnessId_ReturnsNull_WhenExhibitProducerIsNotP var cmsAuthValues = new CmsAuthValues( "cookies", - "token", Guid.NewGuid()); ExhibitProducersResponse exhibitProducersResponse = BuildTestExhibitProducers(); @@ -1464,7 +1456,6 @@ public void MapExistingProducerOrWitnessId_ReturnsId_WhenExhibitProducerIsMatche var cmsAuthValues = new CmsAuthValues( "cookies", - "token", Guid.NewGuid()); var exhibitProducers = new ExhibitProducersResponse() diff --git a/Cps.Fct.Hk.Ui.Services.Tests/CommunicationServiceTests.cs b/Cps.Fct.Hk.Ui.Services.Tests/CommunicationServiceTests.cs index dcb573747..19a3b5e2f 100644 --- a/Cps.Fct.Hk.Ui.Services.Tests/CommunicationServiceTests.cs +++ b/Cps.Fct.Hk.Ui.Services.Tests/CommunicationServiceTests.cs @@ -4,29 +4,28 @@ namespace Cps.Fct.Hk.Ui.Services.Tests; +using Common.Constants; +using Common.Dto.Request; +using Common.Dto.Request.HouseKeeping; +using Common.Dto.Response.HouseKeeping; +using Common.Enums; +using Common.Exceptions; using Cps.Fct.Hk.Ui.Interfaces; +using Cps.Fct.Hk.Ui.Services.Tests.TestUtilities; +using DdeiClient.Clients.Interfaces; +using FluentAssertions; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; using Moq; -using Xunit; using System; using System.Collections.Generic; using System.Globalization; using System.Linq; -using System.Threading.Tasks; -using Cps.Fct.Hk.Ui.Services.Tests.TestUtilities; -using Microsoft.AspNetCore.Mvc; -using FluentAssertions; -using Microsoft.AspNetCore.Http; -using DdeiClient.Clients.Interfaces; -using Common.Dto.Response.HouseKeeping; -using Common.Dto.Request; -using Common.Dto.Request.HouseKeeping; -using Common.Constants; -using Common.Exceptions; using System.Threading; - +using System.Threading.Tasks; +using Xunit; using ApiClient = Cps.MasterDataService.Infrastructure.ApiClient; -using Common.Enums; /// /// Unit tests for the class. @@ -78,7 +77,6 @@ public async Task GetCommunicationsAsync_ShouldReturnMappedCommunications_WhenAp var cmsAuthValues = new CmsAuthValues( "cookies", - "token", Guid.NewGuid()); this.apiClientMock @@ -131,7 +129,6 @@ public async Task GetCommunicationsAsync_ShouldLogErrorAndRethrow_WhenApiThrowsE var cmsAuthValues = new CmsAuthValues( "cookies", - "token", Guid.NewGuid()); this.apiClientMock @@ -175,7 +172,6 @@ public async Task GetCommunicationsAsync_ShouldMapDocumentTypeInfo_WhenApiReturn var cmsAuthValues = new CmsAuthValues( "cookies", - "token", Guid.NewGuid()); this.apiClientMock @@ -253,7 +249,6 @@ public async Task GetUsedStatementsAsync_ShouldReturn_WhenApiReturnsUsedStatemen var cmsAuthValues = new CmsAuthValues( "cookies", - "token", Guid.NewGuid()); this.apiClientMock @@ -292,7 +287,6 @@ public async Task GetUsedStatementsAsync_ShouldLogErrorAndRethrow_WhenApiThrowsE var cmsAuthValues = new CmsAuthValues( "cookies", - "token", Guid.NewGuid()); this.apiClientMock @@ -367,7 +361,7 @@ public async Task GetUsedExhibitsAsync_ShouldReturn_WhenApiReturnsUsedExhibits() var cmsAuthValues = new CmsAuthValues( "cookies", - "token", + Guid.NewGuid()); this.apiClientMock @@ -404,7 +398,6 @@ public async Task GetUsedExhibitsAsync_ShouldLogErrorAndRethrow_WhenApiThrowsExc var cmsAuthValues = new CmsAuthValues( "cookies", - "token", Guid.NewGuid()); this.apiClientMock @@ -569,7 +562,6 @@ public async Task GetUnusedMaterialsAsync_ShouldReturn_WhenApiReturnsUnusedMater var cmsAuthValues = new CmsAuthValues( "cookies", - "token", Guid.NewGuid()); this.apiClientMock @@ -630,7 +622,6 @@ public async Task GetUnusedMaterialsAsync_ShouldLogErrorAndRethrow_WhenApiThrows var cmsAuthValues = new CmsAuthValues( "cookies", - "token", Guid.NewGuid()); this.apiClientMock @@ -670,7 +661,6 @@ public async Task GetAttachmentsAsync_ShouldReturnAttachments_WhenApiCallIsSucce var cmsAuthValues = new CmsAuthValues( "cookies", - "token", Guid.NewGuid()); var expectedResponse = new AttachmentsResponse @@ -728,7 +718,7 @@ public async Task GetAttachmentsAsync_ShouldReturnAttachmentsWithExhibitsAndStat var cmsAuthValues = new CmsAuthValues( "cookies", - "token", + Guid.NewGuid()); var expectedResponse = new AttachmentsResponse @@ -795,7 +785,6 @@ public async Task GetAttachmentsAsync_ShouldLogAndRethrowException_WhenApiCallFa var cmsAuthValues = new CmsAuthValues( "cookies", - "token", Guid.NewGuid()); var testException = new Exception("Simulated API error"); @@ -860,7 +849,6 @@ public async Task RetrieveAllAttachmentsAsync_ShouldRetrieveAttachments_WhenComm var cmsAuthValues = new CmsAuthValues( "cookies", - "token", Guid.NewGuid()); var attachmentsResponse = new AttachmentsResponse @@ -968,7 +956,6 @@ public async Task RetrieveAllAttachmentsAsync_ShouldRetrieveAttachmentsWithExhib var cmsAuthValues = new CmsAuthValues( "cookies", - "token", Guid.NewGuid()); var attachmentsResponse = new AttachmentsResponse @@ -1069,7 +1056,6 @@ public async Task RetrieveAllAttachmentsAsync_ShouldReturnEmptyList_WhenNoCommun var cmsAuthValues = new CmsAuthValues( "cookies", - "token", Guid.NewGuid()); // Act @@ -1115,7 +1101,6 @@ public async Task RetrieveAllAttachmentsAsync_ShouldHandleCommunicationsWithoutA var cmsAuthValues = new CmsAuthValues( "cookies", - "token", Guid.NewGuid()); // Act @@ -1161,7 +1146,6 @@ public async Task RetrieveAllAttachmentsAsync_ShouldLogAndRethrowException_WhenE var cmsAuthValues = new CmsAuthValues( "cookies", - "token", Guid.NewGuid()); var testException = new Exception("Simulated error"); @@ -1419,7 +1403,6 @@ public async Task GetCommunicationLinkAsync_CommunicationLinkFound_ReturnsLink() var cmsAuthValues = new CmsAuthValues( "cookies", - "token", Guid.NewGuid()); var apiCommunications = new List @@ -1479,7 +1462,7 @@ public async Task GetCaseMaterialLinkAsync_MaterialFoundInVariousSources_Returns // Arrange int caseId = 1; int materialId = 456; - var cmsAuthValues = new CmsAuthValues("cookies", "token", Guid.NewGuid()); + var cmsAuthValues = new CmsAuthValues("cookies", Guid.NewGuid()); List communications = source == "communications" ? new List { new(1, "File1", "Subject1", 123, materialId, expectedLink, "Active", "Category1", "Type1", false) } @@ -1590,7 +1573,6 @@ public async Task GetCommunicationLinkAsync_NoCommunications_ReturnsNotFoundResu var cmsAuthValues = new CmsAuthValues( "cookies", - "token", Guid.NewGuid()); this.apiClientMock @@ -1619,7 +1601,6 @@ public async Task GetCommunicationLinkAsync_NoDirectLink_ChecksAttachments_Retur var cmsAuthValues = new CmsAuthValues( "cookies", - "token", Guid.NewGuid()); var apiCommunications = new List @@ -1698,7 +1679,6 @@ public async Task GetCommunicationLinkAsync_NoAttachments_ReturnsNotFoundResult( var cmsAuthValues = new CmsAuthValues( "cookies", - "token", Guid.NewGuid()); var apiCommunications = new List @@ -1758,7 +1738,6 @@ public async Task GetCommunicationLinkAsync_ThrowsException_ErrorIsLogged() var cmsAuthValues = new CmsAuthValues( "cookies", - "token", Guid.NewGuid()); this.apiClientMock @@ -1785,7 +1764,6 @@ public async Task RenameMaterialAsync_ShouldReturn_AsExpected_SuccessLogged() // Arrange var cmsAuthValues = new CmsAuthValues( "cookies", - "token", Guid.NewGuid()); var expectedResponse = new RenameMaterialResponse(new RenameMaterialData @@ -1827,7 +1805,6 @@ public async Task RenameMaterialAsync_WhenApiThrow_ShouldThrowException() // Arrange var cmsAuthValues = new CmsAuthValues( "cookies", - "token", Guid.NewGuid()); int caseId = 134; @@ -1866,7 +1843,6 @@ public async Task GetPcdRequestCore_ShouldThrowException_WhenApiClientThrowsExce var correlationId = Guid.NewGuid(); var cmsAuthValues = new CmsAuthValues( "cookies", - "token", correlationId); var request = new GetPcdRequestsCoreRequest(caseId, correlationId); this.apiClientMock.Setup(x => x.GetPcdRequestCoreAsync(request, cmsAuthValues)) @@ -1896,7 +1872,6 @@ public async Task GetPcdRequestByPcdIdAsync_ShouldThrowException_WhenApiClientTh var correlationId = Guid.NewGuid(); var cmsAuthValues = new CmsAuthValues( "cookies", - "token", correlationId); var request = new GetPcdRequestByPcdIdCoreRequest(caseId, pcdId, correlationId); this.apiClientMock.Setup(x => x.GetPcdRequestByPcdIdAsync(request, cmsAuthValues)) @@ -1922,7 +1897,6 @@ public async Task SetMaterialReadStatusAsync_ShouldReturn_AsExpected_SuccessLogg // Arrange var cmsAuthValues = new CmsAuthValues( "cookies", - "token", Guid.NewGuid()); var expectedResposne = new SetMaterialReadStatusResponse(new SetMaterialReadStatusResponseData @@ -1963,7 +1937,6 @@ public async Task SetMaterialReadStatusAsync_WhenApiThrow_ShouldThrowException() // Arrange var cmsAuthValues = new CmsAuthValues( "cookies", - "token", Guid.NewGuid()); var exceptionMocked = new BadHttpRequestException("Material does not exists in DDEI"); @@ -1998,7 +1971,6 @@ public async Task DiscardMaterialAsync_ShouldLogAndReturn_WhenApiReturnsSuccess( // Arrange var cmsAuthValues = new CmsAuthValues( "cookies", - "token", Guid.NewGuid()); var expectedResponse = new DiscardMaterialResponse(new DiscardMaterialData @@ -2046,7 +2018,6 @@ public async Task DiscardMaterialAsync_ShouldLogAndRethrowException_WhenApiCallF // Arrange var cmsAuthValues = new CmsAuthValues( "cookies", - "token", Guid.NewGuid()); int caseId = 134; @@ -2124,7 +2095,6 @@ public async Task GetUsedMgFormsAsync_ShouldReturn_WhenApiReturnsUsedMgForms() var cmsAuthValues = new CmsAuthValues( "cookies", - "token", Guid.NewGuid()); this.apiClientMock @@ -2167,7 +2137,6 @@ public async Task GetUsedMgFormsAsync_ShouldLogErrorAndRethrow_WhenApiThrowsExce var cmsAuthValues = new CmsAuthValues( "cookies", - "token", Guid.NewGuid()); this.apiClientMock @@ -2238,7 +2207,6 @@ public async Task GetUsedOtherMaterialsAsync_ShouldReturn_WhenApiReturnsUsedOthe var cmsAuthValues = new CmsAuthValues( "cookies", - "token", Guid.NewGuid()); this.apiClientMock @@ -2281,7 +2249,6 @@ public async Task GetUsedOtherMaterialsAsync_ShouldLogErrorAndRethrow_WhenApiThr var cmsAuthValues = new CmsAuthValues( "cookies", - "token", Guid.NewGuid()); this.apiClientMock @@ -2326,7 +2293,6 @@ public async Task GetUsedMgFormsAsync_ShouldReturnEmptyResponse_WhenApiReturnsNo var cmsAuthValues = new CmsAuthValues( "cookies", - "token", Guid.NewGuid()); this.apiClientMock @@ -2367,7 +2333,6 @@ public async Task GetUsedOtherMaterialsAsync_ShouldReturnEmptyResponse_WhenApiRe var cmsAuthValues = new CmsAuthValues( "cookies", - "token", Guid.NewGuid()); this.apiClientMock @@ -2398,7 +2363,7 @@ public async Task GetExhibitProducersAsync_ReturnsExhibitProducersForCase_WhenAp { // Arrange int caseId = 4321; - var cmsAuthValues = new CmsAuthValues("validCmsToken", "validCmsCookies"); + var cmsAuthValues = new CmsAuthValues("validCmsToken"); var expectedProducers = new ExhibitProducersResponse { @@ -2437,7 +2402,7 @@ public async Task GetExhibitProducersAsync_ThrowsException_WhenApiCallFails() { // Arrange int caseId = 4321; - var cmsAuthValues = new CmsAuthValues("validCmsToken", "validCmsCookies"); + var cmsAuthValues = new CmsAuthValues("validCmsToken"); var expectedProducers = new ExhibitProducersResponse { @@ -2477,7 +2442,6 @@ public async Task UpdateStatementAsync_ShouldLogAndReturn_WhenApiReturnsSuccess( // Arrange var cmsAuthValues = new CmsAuthValues( "cookies", - "token", Guid.NewGuid()); var expectedResponse = new UpdateStatementResponse(new UpdateStatementData @@ -2523,7 +2487,7 @@ public async Task UpdateStatementAsync_ShouldLogAndRethrowException_WhenApiCallF // Arrange var cmsAuthValues = new CmsAuthValues( "cookies", - "token", + Guid.NewGuid()); int caseId = 134; @@ -2565,7 +2529,6 @@ public async Task UpdateExhibitAsync_ShouldLogAndReturn_WhenApiReturnsSuccess() // Arrange var cmsAuthValues = new CmsAuthValues( "cookies", - "token", Guid.NewGuid()); var expectedResponse = new UpdateExhibitResponse(new UpdateExhibitData @@ -2611,7 +2574,6 @@ public async Task UpdateExhibitAsync_ShouldLogAndRethrowException_WhenApiCallFai // Arrange var cmsAuthValues = new CmsAuthValues( "cookies", - "token", Guid.NewGuid()); int caseId = 134; @@ -2658,7 +2620,6 @@ public async Task GetPcdReviewDetailAsync_ShouldReturnPcdReviewDetails_WhenApiCa var cmsAuthValues = new CmsAuthValues( "cookies", - "token", Guid.NewGuid()); var historyEvents = new List @@ -2723,7 +2684,6 @@ public async Task GetPcdReviewDetailAsync_ShouldReturnPcdReviewDetailsWithPreCha var cmsAuthValues = new CmsAuthValues( "cookies", - "token", Guid.NewGuid()); var historyEvents = new List @@ -2784,7 +2744,6 @@ public async Task GetPcdReviewDetailAsync_ShouldReturnPcdReviewDetailsWithoutPre var cmsAuthValues = new CmsAuthValues( "cookies", - "token", Guid.NewGuid()); var historyEvents = new List @@ -2835,7 +2794,6 @@ public async Task GetPcdReviewDetailAsync_ShouldThrowBadRequestException_WhenHis var cmsAuthValues = new CmsAuthValues( "cookies", - "token", Guid.NewGuid()); var historyEvents = new List @@ -2873,7 +2831,6 @@ public async Task GetPcdReviewDetailAsync_ShouldLogAndRethrowException_WhenApiCa var cmsAuthValues = new CmsAuthValues( "cookies", - "token", Guid.NewGuid()); this.apiClientMock @@ -2909,7 +2866,6 @@ public async Task GetPcdReviewDetailAsync_ShouldPassCancellationToken_ToDownstre var cmsAuthValues = new CmsAuthValues( "cookies", - "token", Guid.NewGuid()); var historyEvents = new List @@ -2959,7 +2915,6 @@ public async Task GetPcdReviewCoreAsync_ShouldReturnEarlyAdvice_WhenPcdAnalysisA var cmsAuthValues = new CmsAuthValues( "cookies", - "token", Guid.NewGuid()); var historyEvents = new List @@ -3008,7 +2963,6 @@ public async Task GetPcdReviewCoreAsync_ShouldNotReturnEarlyAdvice_WhenInitialRe var cmsAuthValues = new CmsAuthValues( "cookies", - "token", Guid.NewGuid()); var historyEvents = new List @@ -3055,7 +3009,6 @@ public async Task GetPcdReviewCoreAsync_ShouldFilterOnlyPcdRelatedEvents_WhenHis var cmsAuthValues = new CmsAuthValues( "cookies", - "token", Guid.NewGuid()); // Using the provided test data - only valid types @@ -3082,8 +3035,8 @@ public async Task GetPcdReviewCoreAsync_ShouldFilterOnlyPcdRelatedEvents_WhenHis var resultList = result.ToList(); // Verify only PCD-related events are returned - Assert.True(resultList.All(x => x.Type == PcdReviewCoreType.EarlyAdvice || - x.Type == PcdReviewCoreType.InitialReview || + Assert.True(resultList.All(x => x.Type == PcdReviewCoreType.EarlyAdvice || + x.Type == PcdReviewCoreType.InitialReview || x.Type == PcdReviewCoreType.PreChargeDecisionAnalysis)); // Verify the order is maintained @@ -3109,7 +3062,6 @@ public async Task GetPcdReviewCoreAsync_ShouldReturnEmptyCollection_WhenNoPcdRel var cmsAuthValues = new CmsAuthValues( "cookies", - "token", Guid.NewGuid()); var historyEvents = new List @@ -3148,7 +3100,6 @@ public async Task GetPcdReviewCoreAsync_ShouldReturnCorrectDates_ForAllPcdReview var cmsAuthValues = new CmsAuthValues( "cookies", - "token", Guid.NewGuid()); var testDate = "27/01/2026"; @@ -3193,7 +3144,6 @@ public async Task GetPcdReviewCoreAsync_ShouldReturnItemsOrderedById_WhenMultipl var cmsAuthValues = new CmsAuthValues( "cookies", - "token", Guid.NewGuid()); // Events are provided out of order @@ -3242,7 +3192,6 @@ public async Task GetPcdReviewCoreAsync_ShouldLogInformation_WhenFetchingCaseHis var cmsAuthValues = new CmsAuthValues( "cookies", - "token", Guid.NewGuid()); var historyEvents = new List @@ -3281,7 +3230,6 @@ public async Task GetPcdReviewCoreAsync_ShouldLogAndRethrowException_WhenApiCall var cmsAuthValues = new CmsAuthValues( "cookies", - "token", Guid.NewGuid()); this.apiClientMock @@ -3317,7 +3265,6 @@ public async Task GetPcdReviewCoreAsync_ShouldPassCancellationToken_ToDownstream var cmsAuthValues = new CmsAuthValues( "cookies", - "token", Guid.NewGuid()); var historyEvents = new List @@ -3352,7 +3299,6 @@ public async Task GetPcdReviewCoreAsync_ShouldReturnOnlyEarlyAdvice_WhenOnlyPcdA var cmsAuthValues = new CmsAuthValues( "cookies", - "token", Guid.NewGuid()); var historyEvents = new List @@ -3394,7 +3340,6 @@ public async Task GetPcdReviewCoreAsync_ShouldReturnOnlyInitialReview_WhenOnlyIn var cmsAuthValues = new CmsAuthValues( "cookies", - "token", Guid.NewGuid()); var historyEvents = new List diff --git a/Cps.Fct.Hk.Ui.Services.Tests/DocumentServiceTests.cs b/Cps.Fct.Hk.Ui.Services.Tests/DocumentServiceTests.cs index a5c410b5f..c294fe293 100644 --- a/Cps.Fct.Hk.Ui.Services.Tests/DocumentServiceTests.cs +++ b/Cps.Fct.Hk.Ui.Services.Tests/DocumentServiceTests.cs @@ -64,7 +64,7 @@ public async Task GetMaterialDocumentAsync_ValidDocument_ReturnsFileStreamResult // Arrange string caseId = "123"; string link = "/case/material/document.txt"; - var cmsAuthValues = new CmsAuthValues("valid cookies", "valid token", Guid.NewGuid()); + var cmsAuthValues = new CmsAuthValues("valid cookies", Guid.NewGuid()); var mockFileStreamResult = new FileStreamResult(new MemoryStream(), "text/plain") { FileDownloadName = "preview_document" }; string blobContainerName = "test-container"; string pdfBlobUrl = "https://blobstorage/test/preview_document.pdf"; @@ -140,7 +140,7 @@ public async Task GetMaterialDocumentAsync_DocumentNotFound_ThrowsInvalidOperati // Arrange string caseId = "123"; string link = "/case/material/missing_document.txt"; - var cmsAuthValues = new CmsAuthValues("valid cookies", "valid token", Guid.NewGuid()); + var cmsAuthValues = new CmsAuthValues("valid cookies", Guid.NewGuid()); this.mockApiClient .Setup(client => client.GetMaterialDocumentAsync(It.IsAny(), cmsAuthValues)) @@ -173,7 +173,7 @@ public async Task GetMaterialDocumentAsync_ExceptionThrown_ThrowsException() // Arrange string caseId = "123"; string link = "/case/material/document.txt"; - var cmsAuthValues = new CmsAuthValues("valid cookies", "valid token", Guid.NewGuid()); + var cmsAuthValues = new CmsAuthValues("valid cookies", Guid.NewGuid()); var exception = new Exception("DDEI API error"); this.mockApiClient @@ -208,7 +208,7 @@ public async Task GetMaterialDocumentAsync_NotSupportedExceptionThrown_ThrowsNot // Arrange string caseId = "123"; string link = "/case/material/document.txt"; - var cmsAuthValues = new CmsAuthValues("valid cookies", "valid token", Guid.NewGuid()); + var cmsAuthValues = new CmsAuthValues("valid cookies", Guid.NewGuid()); var exception = new NotSupportedException("DDEI API error"); this.mockApiClient diff --git a/Cps.Fct.Hk.Ui.Services.Tests/MaterialReclassificationOrchestrationServiceUnitTests.cs b/Cps.Fct.Hk.Ui.Services.Tests/MaterialReclassificationOrchestrationServiceUnitTests.cs index c492a0b02..798115a6a 100644 --- a/Cps.Fct.Hk.Ui.Services.Tests/MaterialReclassificationOrchestrationServiceUnitTests.cs +++ b/Cps.Fct.Hk.Ui.Services.Tests/MaterialReclassificationOrchestrationServiceUnitTests.cs @@ -57,7 +57,7 @@ public async Task CompleteReclassificationAsync_ReclassifyingMaterialToStatement int caseId = 232; int materialId = 123; int newWitnessId = 765; - var cmsAuthValues = new CmsAuthValues("valid cookies", "valid token", Guid.NewGuid()); + var cmsAuthValues = new CmsAuthValues("valid cookies", Guid.NewGuid()); var transactionId = Guid.NewGuid(); var reclassifyCaseMaterialRequest = CreateMockReclassifyToStatmentRequest(); @@ -153,7 +153,7 @@ public async Task CompleteReclassificationAsync_ReclassifyingMaterialToStatement int caseId = 232; int materialId = 123; int newWitnessId = 765; - var cmsAuthValues = new CmsAuthValues("valid cookies", "valid token", Guid.NewGuid()); + var cmsAuthValues = new CmsAuthValues("valid cookies", Guid.NewGuid()); var transactionId = Guid.NewGuid(); var reclassifyCaseMaterialRequest = CreateMockReclassifyToStatmentRequest(); @@ -247,7 +247,7 @@ public async Task CompleteReclassificationAsync_ReclassifyingMaterialToStatement // Arrange int caseId = 232; int materialId = 123; - var cmsAuthValues = new CmsAuthValues("valid cookies", "valid token", Guid.NewGuid()); + var cmsAuthValues = new CmsAuthValues("valid cookies", Guid.NewGuid()); var transactionId = Guid.NewGuid(); var reclassifyCaseMaterialRequest = CreateMockReclassifyToStatmentRequest(); @@ -342,7 +342,7 @@ public async Task CompleteReclassificationAsync_ReclassifyingMaterialToOther_All int caseId = 232; int materialId = 123; int newWitnessId = 765; - var cmsAuthValues = new CmsAuthValues("valid cookies", "valid token", Guid.NewGuid()); + var cmsAuthValues = new CmsAuthValues("valid cookies", Guid.NewGuid()); var transactionId = Guid.NewGuid(); var reclassifyCaseMaterialRequest = CreateMockReclassifyToOtherRequest(); diff --git a/Cps.Fct.Hk.Ui.Services.Tests/WitnessServiceTests.cs b/Cps.Fct.Hk.Ui.Services.Tests/WitnessServiceTests.cs index eb62aa0b7..6d49f2261 100644 --- a/Cps.Fct.Hk.Ui.Services.Tests/WitnessServiceTests.cs +++ b/Cps.Fct.Hk.Ui.Services.Tests/WitnessServiceTests.cs @@ -52,7 +52,7 @@ public async Task GetWitnessesForCaseAsync_ReturnsWitnessesForCase_WhenApiCallIs { // Arrange int caseId = 4321; - var cmsAuthValues = new CmsAuthValues("validCmsToken", "validCmsCookies"); + var cmsAuthValues = new CmsAuthValues("validCmsToken"); var expectedWitnesses = new WitnessesResponse { @@ -93,7 +93,7 @@ public async Task GetWitnessesForCaseAsync_ThrowsException_WhenApiCallFails() { // Arrange int caseId = 4321; - var cmsAuthValues = new CmsAuthValues("validCmsToken", "validCmsCookies"); + var cmsAuthValues = new CmsAuthValues("validCmsToken"); var expectedWitnesses = new WitnessesResponse { @@ -131,7 +131,7 @@ public async Task GetStatementsForWitnessAsync_ReturnsWitnessStatements_WhenApiC { // Arrange int witnessId = 789; - var cmsAuthValues = new CmsAuthValues("validCmsToken", "validCmsCookies"); + var cmsAuthValues = new CmsAuthValues("validCmsToken"); // Statements var statement1 = new WitnessStatement( @@ -180,7 +180,7 @@ public async Task GetStatementsForWitnessAsync_ThrowsExceptionAndLogsError_WhenA { // Arrange int witnessId = 789; - var cmsAuthValues = new CmsAuthValues("validCmsToken", "validCmsCookies"); + var cmsAuthValues = new CmsAuthValues("validCmsToken"); this.apiClientMock .Setup(x => x.GetWitnessStatementsAsync(It.IsAny(), cmsAuthValues)) @@ -211,7 +211,7 @@ public async Task AddWitnessAsync_ThrowsException_WhenApiCallFails() // Arrange int caseId = 4321; string urn = "12345671"; - var cmsAuthValues = new CmsAuthValues("validCmsToken", "validCmsCookies"); + var cmsAuthValues = new CmsAuthValues("validCmsToken"); this.apiClientMock .Setup(x => x.AddWitnessAsync(It.IsAny(), It.IsAny())) @@ -254,7 +254,7 @@ public async Task AddWitnessAsync_WhenNewWitnessDetailsNotFound_ThrowsAndLogsExc new (caseId, 432, "Bob", "Jackson"), }, }; - var cmsAuthValues = new CmsAuthValues("validCmsToken", "validCmsCookies"); + var cmsAuthValues = new CmsAuthValues("validCmsToken"); this.apiClientMock .Setup(x => x.AddWitnessAsync(It.IsAny(), It.IsAny())) @@ -312,7 +312,7 @@ public async Task AddWitnessAsyncReturnsOk_WhenApiCallSucceeds(string firstName, new (caseId, 432, "Bob", "Jackson"), }, }; - var cmsAuthValues = new CmsAuthValues("validCmsToken", "validCmsCookies"); + var cmsAuthValues = new CmsAuthValues("validCmsToken"); this.apiClientMock .Setup(x => x.AddWitnessAsync(It.IsAny(), It.IsAny())) diff --git a/DdeiClient/Clients/MasterDataServiceClient.cs b/DdeiClient/Clients/MasterDataServiceClient.cs index 83e365b2e..f2884994a 100644 --- a/DdeiClient/Clients/MasterDataServiceClient.cs +++ b/DdeiClient/Clients/MasterDataServiceClient.cs @@ -2,1797 +2,1654 @@ // Copyright (c) The Crown Prosecution Service. All rights reserved. // -namespace DdeiClient.Clients +namespace DdeiClient.Clients; + +using Common.Constants; +using Common.Dto.Request; +using Common.Dto.Request.HouseKeeping; +using Common.Dto.Response.HouseKeeping; +using Common.Dto.Response.HouseKeeping.Pcd; +using DdeiClient.Clients.Interfaces; +using DdeiClient.Diagnostics; +using DdeiClient.Utils; +using Microsoft; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using ApiClient = Cps.MasterDataService.Infrastructure.ApiClient; + +/// +/// Repesents Mds API client. +/// +public class MasterDataServiceClient(IMasterDataServiceApiClientFactory mdsApiClientFactory, ILoggerFactory loggerFactory) + : IMasterDataServiceClient { - using System; - using System.Collections.Generic; - using System.Diagnostics; - using System.IO; - using System.Linq; - using System.Text.Json; - using Azure.Core; - using Common.Constants; - using Common.Dto.Request; - using Common.Dto.Request.HouseKeeping; - using Common.Dto.Response.HouseKeeping; - using Common.Dto.Response.HouseKeeping.Pcd; - using DdeiClient.Clients.Interfaces; - using DdeiClient.Diagnostics; - using DdeiClient.Model; - using DdeiClient.Utils; - using Microsoft; - using Microsoft.AspNetCore.Mvc; - using Microsoft.Extensions.Logging; - using ApiClient = Cps.MasterDataService.Infrastructure.ApiClient; + private readonly IMasterDataServiceApiClientFactory mdsApiClientFactory = mdsApiClientFactory; + private readonly ILogger logger = loggerFactory.CreateLogger(); - /// - /// Repesents Mds API client. - /// - public class MasterDataServiceClient( - IMasterDataServiceApiClientFactory mdsApiClientFactory, - ILoggerFactory loggerFactory) : IMasterDataServiceClient + /// + public async Task GetCaseSummaryAsync(GetCaseSummaryRequest request, CmsAuthValues cmsAuthValues) { - private readonly IMasterDataServiceApiClientFactory mdsApiClientFactory = mdsApiClientFactory; - private readonly ILogger logger = loggerFactory.CreateLogger(); - - /// - public async Task GetCaseSummaryAsync(GetCaseSummaryRequest request, CmsAuthValues cmsAuthValues) - { - Requires.NotNull(request); - Requires.NotNull(cmsAuthValues); - Requires.NotNull(cmsAuthValues.CmsCookies, nameof(cmsAuthValues.CmsCookies)); - Requires.NotNull(cmsAuthValues.CmsModernToken, nameof(cmsAuthValues.CmsModernToken)); + Requires.NotNull(request); + Requires.NotNull(cmsAuthValues.CmsAuthFullValue); - var stopwatch = Stopwatch.StartNew(); + var stopwatch = Stopwatch.StartNew(); - var operationName = "GetCaseSummary"; + var operationName = "GetCaseSummary"; - CaseSummaryResponse result = null; + CaseSummaryResponse result = null; - try - { - var cookie = new MasterDataServiceCookie(cmsAuthValues.CmsCookies, cmsAuthValues.CmsModernToken); - var cookieString = JsonSerializer.Serialize(cookie); - var client = this.mdsApiClientFactory.Create(cookieString); - - var data = await client.GetCaseSummaryAsync(request.CaseId); + try + { + var client = this.mdsApiClientFactory.Create(cmsAuthValues.CmsAuthFullValue); - if (data?.Urn is not null) - { - result = new CaseSummaryResponse( - data.Id, - data.Urn, - data.LeadDefendantFirstNames, - data.LeadDefendantSurname, - data.NumberOfDefendants, - data.UnitName); - } + var data = await client.GetCaseSummaryAsync(request.CaseId); - this.LogOperationCompletedEvent(operationName, request, stopwatch.Elapsed, string.Empty); - } - catch (Exception exception) + if (data?.Urn is not null) { - this.HandleException(operationName, exception, request, stopwatch.Elapsed); - throw; + result = new CaseSummaryResponse( + data.Id, + data.Urn, + data.LeadDefendantFirstNames, + data.LeadDefendantSurname, + data.NumberOfDefendants, + data.UnitName); } - return result; + this.LogOperationCompletedEvent(operationName, request, stopwatch.Elapsed, string.Empty); } - - /// - public async Task GetUnusedMaterialsAsync(GetUnusedMaterialsRequest request, CmsAuthValues cmsAuthValues) + catch (Exception exception) { - Requires.NotNull(request); - Requires.NotNull(cmsAuthValues); - Requires.NotNull(cmsAuthValues.CmsCookies, nameof(cmsAuthValues.CmsCookies)); - Requires.NotNull(cmsAuthValues.CmsModernToken, nameof(cmsAuthValues.CmsModernToken)); - - var stopwatch = Stopwatch.StartNew(); - - const string OperationName = "GetUnusedMaterials"; - - try - { - UnusedMaterialsResponse results = new(); - var cookie = new MasterDataServiceCookie(cmsAuthValues.CmsCookies, cmsAuthValues.CmsModernToken); - var cookieString = JsonSerializer.Serialize(cookie); - var client = this.mdsApiClientFactory.Create(cookieString); - - string additionalInfo = $"received #0 unused materials"; - var data = await client.GetUnusedMaterialsAsync(request.CaseId); - - if (data is not null) - { - results = new UnusedMaterialsResponse - { - Exhibits = data.Exhibits?.Select(exhibit => new Exhibit( - exhibit.Id, - exhibit.Title, - exhibit.OriginalFileName, - string.Empty, - exhibit.DocumentType, - exhibit.Link, - exhibit.Status.ToString(), - exhibit.ReceivedDate?.DateTime, - exhibit.Reference, - exhibit.Producer)).ToList(), - - MgForms = data.MgForms?.Select(mgForm => new MgForm( - mgForm.Id, - mgForm.Title, - mgForm.OriginalFileName, - mgForm.MaterialType, - null, - mgForm.Link, - mgForm.Date.ToString(), - mgForm.Date?.DateTime)).ToList(), - - OtherMaterials = data.OtherMaterials?.Select(otherMaterial => new MgForm( - otherMaterial.Id, - otherMaterial.Title, - otherMaterial.OriginalFileName, - otherMaterial.MaterialType, - null, - otherMaterial.Link, - otherMaterial.Status.ToString(), - otherMaterial.Date?.DateTime)).ToList(), - - Statements = data.Statements?.Select(statement => new Statement( - statement.Id, - statement.WitnessId, - statement.Title, - statement.OriginalFileName, - string.Empty, - statement.DocumentType, - statement.Link, - statement.Status.ToString(), - statement.Date?.DateTime, - statement.StatementTakenDate?.DateTime)).ToList(), - }; - - // Generate additional info string based on the collections - additionalInfo = this.BuildAdditionalInfo(results); - } - - this.LogOperationCompletedEvent(OperationName, request, stopwatch.Elapsed, additionalInfo); - return results; - } - catch (Exception exception) - { - this.HandleException(OperationName, exception, request, stopwatch.Elapsed); - throw; - } + this.HandleException(operationName, exception, request, stopwatch.Elapsed); + throw; } - /// - public async Task GetUsedExhibitsAsync(GetUsedExhibitsRequest request, CmsAuthValues cmsAuthValues) - { - Requires.NotNull(request); - Requires.NotNull(cmsAuthValues); - Requires.NotNull(cmsAuthValues.CmsCookies, nameof(cmsAuthValues.CmsCookies)); - Requires.NotNull(cmsAuthValues.CmsModernToken, nameof(cmsAuthValues.CmsModernToken)); - - var stopwatch = Stopwatch.StartNew(); - const string OperationName = "GetUsedExhibits"; - - try - { - UsedExhibitsResponse results = new() { Exhibits = [] }; - var cookie = new MasterDataServiceCookie(cmsAuthValues.CmsCookies, cmsAuthValues.CmsModernToken); - var cookieString = JsonSerializer.Serialize(cookie); - var client = this.mdsApiClientFactory.Create(cookieString); - - string additionalInfo = $"received #0 used exhibits"; - - var data = await client.GetUsedExhibitsAsync(request.CaseId); + return result; + } - if (data?.Exhibits is not null) - { - results = new UsedExhibitsResponse - { - Exhibits = data.Exhibits.Select(exhibit => new Exhibit( - exhibit.Id, - exhibit.Title, - exhibit.OriginalFileName, - string.Empty, - exhibit.DocumentType, - exhibit.Link, - exhibit.Status.ToString(), - exhibit.ReceivedDate?.DateTime, - exhibit.Reference, - exhibit.Producer)).ToList(), - }; + /// + public async Task GetUnusedMaterialsAsync(GetUnusedMaterialsRequest request, CmsAuthValues cmsAuthValues) + { + Requires.NotNull(request); + Requires.NotNull(cmsAuthValues.CmsAuthFullValue); - if (results.Exhibits.Count != 0) - { - additionalInfo = $"received #{results.Exhibits.Count} used exhibits"; - } - } + var stopwatch = Stopwatch.StartNew(); - this.LogOperationCompletedEvent(OperationName, request, stopwatch.Elapsed, additionalInfo); - return results; - } - catch (Exception exception) - { - this.HandleException(OperationName, exception, request, stopwatch.Elapsed); - throw; - } - } + const string OperationName = "GetUnusedMaterials"; - /// - public async Task GetUsedMgFormsAsync(GetUsedMgFormsRequest request, CmsAuthValues cmsAuthValues) + try { - Requires.NotNull(request); - Requires.NotNull(cmsAuthValues); - Requires.NotNull(cmsAuthValues.CmsCookies, nameof(cmsAuthValues.CmsCookies)); - Requires.NotNull(cmsAuthValues.CmsModernToken, nameof(cmsAuthValues.CmsModernToken)); + UnusedMaterialsResponse results = new (); + var client = this.mdsApiClientFactory.Create(cmsAuthValues.CmsAuthFullValue); - var stopwatch = Stopwatch.StartNew(); - const string OperationName = "GetUsedMgForms"; + string additionalInfo = $"received #0 unused materials"; + var data = await client.GetUnusedMaterialsAsync(request.CaseId); - try + if (data is not null) { - UsedMgFormsResponse? results = new() { MgForms = [] }; - var cookie = new MasterDataServiceCookie(cmsAuthValues.CmsCookies, cmsAuthValues.CmsModernToken); - var cookieString = JsonSerializer.Serialize(cookie); - var client = this.mdsApiClientFactory.Create(cookieString); - - var data = await client.GetUsedMgFormsAsync(request.CaseId); - - if (data?.MgForms is not null) + results = new UnusedMaterialsResponse { - results = new UsedMgFormsResponse - { - MgForms = data.MgForms?.Select(mgForm => new MgForm( - mgForm.Id, - mgForm.Title, - mgForm.OriginalFileName, - mgForm.MaterialType, - null, - mgForm.Link, - mgForm.Date.ToString(), - mgForm.Date?.DateTime)).ToList(), - }; - } + Exhibits = data.Exhibits?.Select(exhibit => new Exhibit( + exhibit.Id, + exhibit.Title, + exhibit.OriginalFileName, + string.Empty, + exhibit.DocumentType, + exhibit.Link, + exhibit.Status.ToString(), + exhibit.ReceivedDate?.DateTime, + exhibit.Reference, + exhibit.Producer)).ToList(), + + MgForms = data.MgForms?.Select(mgForm => new MgForm( + mgForm.Id, + mgForm.Title, + mgForm.OriginalFileName, + mgForm.MaterialType, + null, + mgForm.Link, + mgForm.Date.ToString(), + mgForm.Date?.DateTime)).ToList(), + + OtherMaterials = data.OtherMaterials?.Select(otherMaterial => new MgForm( + otherMaterial.Id, + otherMaterial.Title, + otherMaterial.OriginalFileName, + otherMaterial.MaterialType, + null, + otherMaterial.Link, + otherMaterial.Status.ToString(), + otherMaterial.Date?.DateTime)).ToList(), - string additionalInfo = results?.MgForms is { Count: > 0 } - ? $"received #{results.MgForms.Count} used MG forms" - : "received #0 used MG forms"; + Statements = data.Statements?.Select(statement => new Statement( + statement.Id, + statement.WitnessId, + statement.Title, + statement.OriginalFileName, + string.Empty, + statement.DocumentType, + statement.Link, + statement.Status.ToString(), + statement.Date?.DateTime, + statement.StatementTakenDate?.DateTime)).ToList(), + }; - this.LogOperationCompletedEvent(OperationName, request, stopwatch.Elapsed, additionalInfo); - return results; - } - catch (Exception exception) - { - this.HandleException(OperationName, exception, request, stopwatch.Elapsed); - throw; + // Generate additional info string based on the collections + additionalInfo = this.BuildAdditionalInfo(results); } - } - /// - public async Task GetUsedOtherMaterialsAsync(GetUsedOtherMaterialsRequest request, CmsAuthValues cmsAuthValues) + this.LogOperationCompletedEvent(OperationName, request, stopwatch.Elapsed, additionalInfo); + return results; + } + catch (Exception exception) { - Requires.NotNull(request); - Requires.NotNull(cmsAuthValues); - Requires.NotNull(cmsAuthValues.CmsCookies, nameof(cmsAuthValues.CmsCookies)); - Requires.NotNull(cmsAuthValues.CmsModernToken, nameof(cmsAuthValues.CmsModernToken)); - - var stopwatch = Stopwatch.StartNew(); - const string OperationName = "GetUsedOtherMaterials"; - - try - { - UsedOtherMaterialsResponse? results = new() { MgForms = [] }; - var cookie = new MasterDataServiceCookie(cmsAuthValues.CmsCookies, cmsAuthValues.CmsModernToken); - var cookieString = JsonSerializer.Serialize(cookie); - var client = this.mdsApiClientFactory.Create(cookieString); - - var data = await client.GetUsedOtherMaterialsAsync(request.CaseId); - - if (data?.MgForms is not null) - { - results = new UsedOtherMaterialsResponse - { - MgForms = data.MgForms?.Select(mgForm => new MgForm( - mgForm.Id, - mgForm.Title, - mgForm.OriginalFileName, - mgForm.MaterialType, - null, - mgForm.Link, - mgForm.Date.ToString(), - mgForm.Date?.DateTime)).ToList(), - }; - } - - string additionalInfo = results?.MgForms is { Count: > 0 } - ? $"received #{results.MgForms.Count} used other materials" - : "received #0 used other materials"; - this.LogOperationCompletedEvent(OperationName, request, stopwatch.Elapsed, additionalInfo); - return results; - } - catch (Exception exception) - { - this.HandleException(OperationName, exception, request, stopwatch.Elapsed); - throw; - } + this.HandleException(OperationName, exception, request, stopwatch.Elapsed); + throw; } + } - /// - public async Task GetUsedStatementsAsync(GetUsedStatementsRequest request, CmsAuthValues cmsAuthValues) - { - Requires.NotNull(request); - Requires.NotNull(cmsAuthValues); - Requires.NotNull(cmsAuthValues.CmsCookies, nameof(cmsAuthValues.CmsCookies)); - Requires.NotNull(cmsAuthValues.CmsModernToken, nameof(cmsAuthValues.CmsModernToken)); + /// + public async Task GetUsedExhibitsAsync(GetUsedExhibitsRequest request, CmsAuthValues cmsAuthValues) + { + Requires.NotNull(request); + Requires.NotNull(cmsAuthValues.CmsAuthFullValue); - var stopwatch = Stopwatch.StartNew(); - const string OperationName = "GetUsedStatements"; + var stopwatch = Stopwatch.StartNew(); + const string OperationName = "GetUsedExhibits"; - try - { - UsedStatementsResponse? results = new(); + try + { + UsedExhibitsResponse results = new () { Exhibits = new List() }; + var client = this.mdsApiClientFactory.Create(cmsAuthValues.CmsAuthFullValue); - var cookie = new MasterDataServiceCookie(cmsAuthValues.CmsCookies, cmsAuthValues.CmsModernToken); - var cookieString = JsonSerializer.Serialize(cookie); - var client = this.mdsApiClientFactory.Create(cookieString); + string additionalInfo = $"received #0 used exhibits"; - string additionalInfo = $"received #0 used statements"; - var data = await client.GetUsedStatementsAsync(request.CaseId); + var data = await client.GetUsedExhibitsAsync(request.CaseId); - if (data?.Statements is not null) + if (data?.Exhibits is not null) + { + results = new UsedExhibitsResponse { - results = new UsedStatementsResponse - { - Statements = data.Statements.Select(statement => new Statement( - statement.Id, - statement.WitnessId, - statement.Title, - statement.OriginalFileName, + Exhibits = data.Exhibits.Select(exhibit => new Exhibit( + exhibit.Id, + exhibit.Title, + exhibit.OriginalFileName, string.Empty, - statement.DocumentType, - statement.Link, - statement.Status.ToString(), - statement.Date?.DateTime, - statement.StatementTakenDate?.DateTime)).ToList(), - }; - } + exhibit.DocumentType, + exhibit.Link, + exhibit.Status.ToString(), + exhibit.ReceivedDate?.DateTime, + exhibit.Reference, + exhibit.Producer)).ToList(), + }; - if (results.Statements.Count != 0) + if (results.Exhibits.Count != 0) { - additionalInfo = $"received #{results.Statements.Count} used statements"; + additionalInfo = $"received #{results.Exhibits.Count} used exhibits"; } - - this.LogOperationCompletedEvent(OperationName, request, stopwatch.Elapsed, additionalInfo); - return results; - } - catch (Exception exception) - { - this.HandleException(OperationName, exception, request, stopwatch.Elapsed); - throw; } - } - /// - public async Task> ListCommunicationsHkAsync(ListCommunicationsHkRequest request, CmsAuthValues cmsAuthValues) + this.LogOperationCompletedEvent(OperationName, request, stopwatch.Elapsed, additionalInfo); + return results; + } + catch (Exception exception) { - Requires.NotNull(request); - Requires.NotNull(cmsAuthValues); - Requires.NotNull(cmsAuthValues.CmsCookies, nameof(cmsAuthValues.CmsCookies)); - Requires.NotNull(cmsAuthValues.CmsModernToken, nameof(cmsAuthValues.CmsModernToken)); + this.HandleException(OperationName, exception, request, stopwatch.Elapsed); + throw; + } + } - var stopwatch = Stopwatch.StartNew(); - const string OperationName = "ListCommunicationsHk"; + /// + public async Task GetUsedMgFormsAsync(GetUsedMgFormsRequest request, CmsAuthValues cmsAuthValues) + { + Requires.NotNull(request); + Requires.NotNull(cmsAuthValues.CmsAuthFullValue); - try - { - List results = []; - var cookie = new MasterDataServiceCookie(cmsAuthValues.CmsCookies, cmsAuthValues.CmsModernToken); - var cookieString = JsonSerializer.Serialize(cookie); - var client = this.mdsApiClientFactory.Create(cookieString); - string additionalInfo = $"received #0 communications"; + var stopwatch = Stopwatch.StartNew(); + const string OperationName = "GetUsedMgForms"; - var data = await client.ListCommunicationsHkAsync(request.CaseId); + try + { + UsedMgFormsResponse results = new () { MgForms = new List() }; + var client = this.mdsApiClientFactory.Create(cmsAuthValues.CmsAuthFullValue); - if (data is not null) - { - results = data.Select( - communication => new Communication( - Id: communication.Id.GetValueOrDefault(), - OriginalFileName: communication.OriginalFileName, - Subject: communication.Subject, - DocumentTypeId: communication.DocumentTypeId.GetValueOrDefault(), - MaterialId: communication.MaterialId.GetValueOrDefault(), - Link: communication.Link, - Status: communication.Status, - Category: string.Empty, - Type: communication.DocumentTypeId?.ToString(), - HasAttachments: communication.HasAttachments, - Method: communication.Method, - Direction: communication.Direction, - Party: communication.Party, - Date: communication.Date?.DateTime)).ToList(); - } + var data = await client.GetUsedMgFormsAsync(request.CaseId); - if (results.Count != 0) + if (data?.MgForms is not null) + { + results = new UsedMgFormsResponse { - additionalInfo = $"received #{results.Count} communications"; - } + MgForms = data.MgForms?.Select(mgForm => new MgForm( + mgForm.Id, + mgForm.Title, + mgForm.OriginalFileName, + mgForm.MaterialType, + null, + mgForm.Link, + mgForm.Date.ToString(), + mgForm.Date?.DateTime)).ToList(), + }; + } - this.LogOperationCompletedEvent(OperationName, request, stopwatch.Elapsed, additionalInfo); + string additionalInfo = results?.MgForms is { Count: > 0 } + ? $"received #{results.MgForms.Count} used MG forms" + : "received #0 used MG forms"; - return results; - } - catch (Exception exception) - { - this.HandleException(OperationName, exception, request, stopwatch.Elapsed); - throw; - } + this.LogOperationCompletedEvent(OperationName, request, stopwatch.Elapsed, additionalInfo); + return results; } - - /// - public async Task GetAttachmentsAsync(GetAttachmentsRequest request, CmsAuthValues cmsAuthValues) + catch (Exception exception) { - Requires.NotNull(request); - Requires.NotNull(cmsAuthValues); - Requires.NotNull(cmsAuthValues.CmsCookies, nameof(cmsAuthValues.CmsCookies)); - Requires.NotNull(cmsAuthValues.CmsModernToken, nameof(cmsAuthValues.CmsModernToken)); + this.HandleException(OperationName, exception, request, stopwatch.Elapsed); + throw; + } + } - var stopwatch = Stopwatch.StartNew(); - const string OperationName = "GetAttachments"; - AttachmentsResponse results = new(); + /// + public async Task GetUsedOtherMaterialsAsync(GetUsedOtherMaterialsRequest request, CmsAuthValues cmsAuthValues) + { + Requires.NotNull(request); + Requires.NotNull(cmsAuthValues.CmsAuthFullValue); - try - { - var cookie = new MasterDataServiceCookie(cmsAuthValues.CmsCookies, cmsAuthValues.CmsModernToken); - var cookieString = JsonSerializer.Serialize(cookie); - var client = this.mdsApiClientFactory.Create(cookieString); - string additionalInfo = $"received #0 attachments"; + var stopwatch = Stopwatch.StartNew(); + const string OperationName = "GetUsedOtherMaterials"; - var data = await client.GetAttachmentsAsync(request.CommunicationId); - if (data?.Attachments is not null) - { - results = new AttachmentsResponse - { - Attachments = data.Attachments.Select(attachment => new Attachment( - attachment.MaterialId, - attachment.Name, - attachment.Description, - attachment.Link, - attachment.Classification, - attachment.DocumentTypeId, - attachment.NumOfDocVersions, - MapStatementSubType(attachment.Statement), - MapExhibitSubItem(attachment.Exhibit), - attachment.Tag, - attachment.DocId, - attachment.OriginalFileName, - attachment.CheckedOutTo, - attachment.DocumentId, - attachment.OcrProcessed, - attachment.Direction)).ToList(), - }; - } + try + { + UsedOtherMaterialsResponse results = new () { MgForms = new List() }; + var client = this.mdsApiClientFactory.Create(cmsAuthValues.CmsAuthFullValue); - if (results.Attachments.Count != 0) - { - additionalInfo = $"received #{results.Attachments.Count} attachments"; - } + var data = await client.GetUsedOtherMaterialsAsync(request.CaseId); - this.LogOperationCompletedEvent(OperationName, request, stopwatch.Elapsed, additionalInfo); - return results; - } - catch (Exception exception) + if (data?.MgForms is not null) { - this.HandleException(OperationName, exception, request, stopwatch.Elapsed); - throw; + results = new UsedOtherMaterialsResponse + { + MgForms = data.MgForms?.Select(mgForm => new MgForm( + mgForm.Id, + mgForm.Title, + mgForm.OriginalFileName, + mgForm.MaterialType, + null, + mgForm.Link, + mgForm.Date.ToString(), + mgForm.Date?.DateTime)).ToList(), + }; } - } - /// - public async Task GetMaterialDocumentAsync(GetDocumentRequest request, CmsAuthValues cmsAuthValues) + string additionalInfo = results?.MgForms is { Count: > 0 } + ? $"received #{results.MgForms.Count} used other materials" + : "received #0 used other materials"; + this.LogOperationCompletedEvent(OperationName, request, stopwatch.Elapsed, additionalInfo); + return results; + } + catch (Exception exception) { - Requires.NotNull(request); - Requires.NotNull(cmsAuthValues); - Requires.NotNull(cmsAuthValues.CmsCookies, nameof(cmsAuthValues.CmsCookies)); - Requires.NotNull(cmsAuthValues.CmsModernToken, nameof(cmsAuthValues.CmsModernToken)); + this.HandleException(OperationName, exception, request, stopwatch.Elapsed); + throw; + } + } - var stopwatch = Stopwatch.StartNew(); - const string OperationName = "GetMaterialDocument"; - FileStreamResult? results; + /// + public async Task GetUsedStatementsAsync(GetUsedStatementsRequest request, CmsAuthValues cmsAuthValues) + { + Requires.NotNull(request); + Requires.NotNull(cmsAuthValues.CmsAuthFullValue); - try - { - var cookie = new MasterDataServiceCookie(cmsAuthValues.CmsCookies, cmsAuthValues.CmsModernToken); - var cookieString = JsonSerializer.Serialize(cookie); - var client = this.mdsApiClientFactory.Create(cookieString); + var stopwatch = Stopwatch.StartNew(); + const string OperationName = "GetUsedStatements"; - int caseId = int.Parse(request.CaseId); + try + { + UsedStatementsResponse results = new () { Statements = new List() }; - var data = await client.GetMaterialDocumentAsync(caseId, request.FilePath); + var client = this.mdsApiClientFactory.Create(cmsAuthValues.CmsAuthFullValue); - string fileDownloadName = Path.GetFileName(request.FilePath); - string? contentType = FileUtils.GetMimeType(fileDownloadName) ?? - throw new InvalidOperationException($"{LoggingConstants.HskUiLogPrefix} Content type cannot be determined for file: {fileDownloadName}"); + string additionalInfo = $"received #0 used statements"; + var data = await client.GetUsedStatementsAsync(request.CaseId); - // Create FileStreamResult using the stream and content type - results = new FileStreamResult(data.Stream, contentType) + if (data?.Statements is not null) + { + results = new UsedStatementsResponse { - FileDownloadName = fileDownloadName, + Statements = data.Statements.Select(statement => new Statement( + statement.Id, + statement.WitnessId, + statement.Title, + statement.OriginalFileName, + string.Empty, + statement.DocumentType, + statement.Link, + statement.Status.ToString(), + statement.Date?.DateTime, + statement.StatementTakenDate?.DateTime)).ToList(), }; - - this.LogOperationCompletedEvent(OperationName, request, stopwatch.Elapsed, fileDownloadName); } - catch (Exception exception) + + if (results.Statements.Count != 0) { - this.HandleException(OperationName, exception, request, stopwatch.Elapsed); - throw; + additionalInfo = $"received #{results.Statements.Count} used statements"; } + this.LogOperationCompletedEvent(OperationName, request, stopwatch.Elapsed, additionalInfo); return results; } - - /// - public async Task GetExhibitProducersAsync(GetExhibitProducersRequest request, CmsAuthValues cmsAuthValues) + catch (Exception exception) { - Requires.NotNull(request); - Requires.NotNull(cmsAuthValues); - Requires.NotNull(cmsAuthValues.CmsCookies, nameof(cmsAuthValues.CmsCookies)); - Requires.NotNull(cmsAuthValues.CmsModernToken, nameof(cmsAuthValues.CmsModernToken)); - - var stopwatch = Stopwatch.StartNew(); - const string OperationName = "GetExhibitProducers"; - ExhibitProducersResponse results = new(); - - try - { - var cookie = new MasterDataServiceCookie(cmsAuthValues.CmsCookies, cmsAuthValues.CmsModernToken); - var cookieString = JsonSerializer.Serialize(cookie); - var client = this.mdsApiClientFactory.Create(cookieString); + this.HandleException(OperationName, exception, request, stopwatch.Elapsed); + throw; + } + } - string additionalInfo = "received #0 producers"; + /// + public async Task> ListCommunicationsHkAsync(ListCommunicationsHkRequest request, CmsAuthValues cmsAuthValues) + { + Requires.NotNull(request); + Requires.NotNull(cmsAuthValues.CmsAuthFullValue); - var data = await client.GetExhibitProducersAsync(request.CaseId); + var stopwatch = Stopwatch.StartNew(); + const string OperationName = "ListCommunicationsHk"; - if (data != null) - { - results = new ExhibitProducersResponse - { - ExhibitProducers = data.ExhibitProducers?.Select(x => new ExhibitProducer( - x.Id, - x.Producer, - false)).ToList(), - }; + try + { + List results = new (); + var client = this.mdsApiClientFactory.Create(cmsAuthValues.CmsAuthFullValue); + string additionalInfo = $"received #0 communications"; - if (results.ExhibitProducers?.Count > 0) - { - additionalInfo = $"retrieved #{results.ExhibitProducers.Count} producers"; - } - } + var data = await client.ListCommunicationsHkAsync(request.CaseId); - this.LogOperationCompletedEvent(OperationName, request, stopwatch.Elapsed, additionalInfo); + if (data is not null) + { + results = data.Select( + communication => new Communication( + Id: communication.Id.GetValueOrDefault(), + OriginalFileName: communication.OriginalFileName, + Subject: communication.Subject, + DocumentTypeId: communication.DocumentTypeId.GetValueOrDefault(), + MaterialId: communication.MaterialId.GetValueOrDefault(), + Link: communication.Link, + Status: communication.Status, + Category: string.Empty, + Type: communication.DocumentTypeId?.ToString(), + HasAttachments: communication.HasAttachments, + Method: communication.Method, + Direction: communication.Direction, + Party: communication.Party, + Date: communication.Date?.DateTime)).ToList(); } - catch (Exception exception) + + if (results.Count != 0) { - this.HandleException(OperationName, exception, request, stopwatch.Elapsed); - throw; + additionalInfo = $"received #{results.Count} communications"; } + this.LogOperationCompletedEvent(OperationName, request, stopwatch.Elapsed, additionalInfo); + return results; } - - /// - public async Task GetCaseDefendantsAsync(ListCaseDefendantsRequest request, CmsAuthValues cmsAuthValues) + catch (Exception exception) { - Requires.NotNull(request); - Requires.NotNull(cmsAuthValues); - Requires.NotNull(cmsAuthValues.CmsCookies, nameof(cmsAuthValues.CmsCookies)); - Requires.NotNull(cmsAuthValues.CmsModernToken, nameof(cmsAuthValues.CmsModernToken)); + this.HandleException(OperationName, exception, request, stopwatch.Elapsed); + throw; + } + } - var stopwatch = Stopwatch.StartNew(); - const string OperationName = "ListCaseDefendants"; - List results = new(); + /// + public async Task GetAttachmentsAsync(GetAttachmentsRequest request, CmsAuthValues cmsAuthValues) + { + Requires.NotNull(request); + Requires.NotNull(cmsAuthValues.CmsAuthFullValue); - try - { - var cookie = new MasterDataServiceCookie(cmsAuthValues.CmsCookies, cmsAuthValues.CmsModernToken); - var cookieString = JsonSerializer.Serialize(cookie); - var client = this.mdsApiClientFactory.Create(cookieString); + var stopwatch = Stopwatch.StartNew(); + const string OperationName = "GetAttachments"; + AttachmentsResponse results = new (); - var data = await client.ListCaseDefendantsAsync(request.CaseId); + try + { + var client = this.mdsApiClientFactory.Create(cmsAuthValues.CmsAuthFullValue); + string additionalInfo = $"received #0 attachments"; - var listCaseDefendantsResponse = new DefendantsResponse + var data = await client.GetAttachmentsAsync(request.CommunicationId); + if (data?.Attachments is not null) + { + results = new AttachmentsResponse { - Defendants = data.Select(defendant => new Defendant( - defendant.Id, - defendant.CaseId, - defendant.ListOrder, - defendant.Type, - defendant.FirstNames, - defendant.Surname, - DateTime.TryParse(defendant?.Dob, out var dob) ? dob : (DateTime?)null, - defendant?.PoliceRemandStatus?.ToString(), - defendant?.Youth, - defendant?.CustodyTimeLimit?.ToString(), - MapOffences(defendant?.Offences), - null, - MapProposedCharges(defendant?.ProposedCharges), - defendant?.NextHearing, - defendant?.DefendantPcdReview, - defendant?.Solicitor, - MapPersonalDetail(defendant?.PersonalDetail))).ToList(), + Attachments = data.Attachments.Select(attachment => new Attachment( + attachment.MaterialId, + attachment.Name, + attachment.Description, + attachment.Link, + attachment.Classification, + attachment.DocumentTypeId, + attachment.NumOfDocVersions, + MapStatementSubType(attachment.Statement), + MapExhibitSubItem(attachment.Exhibit), + attachment.Tag, + attachment.DocId, + attachment.OriginalFileName, + attachment.CheckedOutTo, + attachment.DocumentId, + attachment.OcrProcessed, + attachment.Direction)).ToList(), }; - - string additionalInfo = listCaseDefendantsResponse?.Defendants is { Count: > 0 } - ? $"received #{listCaseDefendantsResponse.Defendants.Count} defendants" - : "received #0 defendants"; - this.LogOperationCompletedEvent(OperationName, request, stopwatch.Elapsed, additionalInfo); - - return listCaseDefendantsResponse; } - catch (Exception exception) + + if (results.Attachments.Count != 0) { - this.HandleException(OperationName, exception, request, stopwatch.Elapsed); - throw; + additionalInfo = $"received #{results.Attachments.Count} attachments"; } - } - /// - public async Task GetCaseWitnessesAsync(GetCaseWitnessesRequest request, CmsAuthValues cmsAuthValues) + this.LogOperationCompletedEvent(OperationName, request, stopwatch.Elapsed, additionalInfo); + return results; + } + catch (Exception exception) { - Requires.NotNull(request); - Requires.NotNull(cmsAuthValues); - Requires.NotNull(cmsAuthValues.CmsCookies, nameof(cmsAuthValues.CmsCookies)); - Requires.NotNull(cmsAuthValues.CmsModernToken, nameof(cmsAuthValues.CmsModernToken)); + this.HandleException(OperationName, exception, request, stopwatch.Elapsed); + throw; + } + } - var stopwatch = Stopwatch.StartNew(); - const string OperationName = "ListCaseWitnesses"; - string additionalInfo = $"received #0 witnesses"; - WitnessesResponse results = new(); + /// + public async Task GetMaterialDocumentAsync(GetDocumentRequest request, CmsAuthValues cmsAuthValues) + { + Requires.NotNull(request); + Requires.NotNull(cmsAuthValues.CmsAuthFullValue); - try - { - var cookie = new MasterDataServiceCookie(cmsAuthValues.CmsCookies, cmsAuthValues.CmsModernToken); - var cookieString = JsonSerializer.Serialize(cookie); - var client = this.mdsApiClientFactory.Create(cookieString); + var stopwatch = Stopwatch.StartNew(); + const string OperationName = "GetMaterialDocument"; + FileStreamResult? results; - var data = await client.ListCaseWitnessesAsync(request.CaseId); + try + { + var client = this.mdsApiClientFactory.Create(cmsAuthValues.CmsAuthFullValue); - if (data is not null) - { - results.Witnesses = data.Select(witness => new Witness( - witness.CaseId, - witness.WitnessId, - witness.FirstName, - witness.Surname)).ToList(); - } + int caseId = int.Parse(request.CaseId); - if (results.Witnesses.Count > 0) - { - additionalInfo = $"retrieved #{results.Witnesses.Count} witnesses"; - } + var data = await client.GetMaterialDocumentAsync(caseId, request.FilePath); - this.LogOperationCompletedEvent(OperationName, request, stopwatch.Elapsed, additionalInfo); - } - catch (Exception exception) + string fileDownloadName = Path.GetFileName(request.FilePath); + string? contentType = FileUtils.GetMimeType(fileDownloadName) ?? + throw new InvalidOperationException($"{LoggingConstants.HskUiLogPrefix} Content type cannot be determined for file: {fileDownloadName}"); + + // Create FileStreamResult using the stream and content type + results = new FileStreamResult(data.Stream, contentType) { - this.HandleException(OperationName, exception, request, stopwatch.Elapsed); - throw; - } + FileDownloadName = fileDownloadName, + }; - return results; + this.LogOperationCompletedEvent(OperationName, request, stopwatch.Elapsed, fileDownloadName); } - - /// - public async Task GetWitnessStatementsAsync(GetWitnessStatementsRequest request, CmsAuthValues cmsAuthValues) + catch (Exception exception) { - Requires.NotNull(request); - Requires.NotNull(cmsAuthValues); - Requires.NotNull(cmsAuthValues.CmsCookies, nameof(cmsAuthValues.CmsCookies)); - Requires.NotNull(cmsAuthValues.CmsModernToken, nameof(cmsAuthValues.CmsModernToken)); + this.HandleException(OperationName, exception, request, stopwatch.Elapsed); + throw; + } - var stopwatch = Stopwatch.StartNew(); - const string OperationName = "GetStatementsForWitness"; - string additionalInfo = "received #0 statements"; + return results; + } - WitnessStatementsResponse results = new(); + /// + public async Task GetExhibitProducersAsync(GetExhibitProducersRequest request, CmsAuthValues cmsAuthValues) + { + Requires.NotNull(request); + Requires.NotNull(cmsAuthValues.CmsAuthFullValue); - try - { - var cookie = new MasterDataServiceCookie(cmsAuthValues.CmsCookies, cmsAuthValues.CmsModernToken); - var cookieString = JsonSerializer.Serialize(cookie); - var client = this.mdsApiClientFactory.Create(cookieString); + var stopwatch = Stopwatch.StartNew(); + const string OperationName = "GetExhibitProducers"; + ExhibitProducersResponse results = new (); - var data = await client.GetStatementsForWitnessAsync(request.WitnessId); + try + { + var client = this.mdsApiClientFactory.Create(cmsAuthValues.CmsAuthFullValue); + + string additionalInfo = "received #0 producers"; - if (data?.StatementsForWitness is not null) + var data = await client.GetExhibitProducersAsync(request.CaseId); + + if (data != null) + { + results = new ExhibitProducersResponse { - results.WitnessStatements = data.StatementsForWitness.Select(statement => - new WitnessStatement(statement.Id, statement.Title)).ToList(); - } + ExhibitProducers = data.ExhibitProducers?.Select(x => new ExhibitProducer( + x.Id, + x.Producer, + false)).ToList(), + }; - if (results.WitnessStatements?.Count > 0) + if (results.ExhibitProducers?.Count > 0) { - additionalInfo = $"retrieved #{results.WitnessStatements.Count} statements"; + additionalInfo = $"retrieved #{results.ExhibitProducers.Count} producers"; } } - catch (Exception exception) - { - this.HandleException(OperationName, exception, request, stopwatch.Elapsed); - throw; - } - return results; + this.LogOperationCompletedEvent(OperationName, request, stopwatch.Elapsed, additionalInfo); } - - /// - public async Task AddCaseActionPlanAsync(int caseId, AddActionPlanRequest request, CmsAuthValues cmsAuthValues) + catch (Exception exception) { - Requires.NotNull(request); - Requires.NotNull(cmsAuthValues); - Requires.NotNull(cmsAuthValues.CmsCookies, nameof(cmsAuthValues.CmsCookies)); - Requires.NotNull(cmsAuthValues.CmsModernToken, nameof(cmsAuthValues.CmsModernToken)); + this.HandleException(OperationName, exception, request, stopwatch.Elapsed); + throw; + } + + return results; + } - var stopwatch = Stopwatch.StartNew(); - const string OperationName = "AddActionPlan"; + /// + public async Task GetCaseDefendantsAsync(ListCaseDefendantsRequest request, CmsAuthValues cmsAuthValues) + { + Requires.NotNull(request); + Requires.NotNull(cmsAuthValues.CmsAuthFullValue); - try - { - var cookie = new MasterDataServiceCookie(cmsAuthValues.CmsCookies, cmsAuthValues.CmsModernToken); - var cookieString = JsonSerializer.Serialize(cookie); - var client = this.mdsApiClientFactory.Create(cookieString); + var stopwatch = Stopwatch.StartNew(); + const string OperationName = "ListCaseDefendants"; + List results = new (); - var mdsRequest = MapApAction(request); + try + { + var client = this.mdsApiClientFactory.Create(cmsAuthValues.CmsAuthFullValue); + + var data = await client.ListCaseDefendantsAsync(request.CaseId); + + var listCaseDefendantsResponse = new DefendantsResponse + { + Defendants = data.Select(defendant => new Defendant( + defendant.Id, + defendant.CaseId, + defendant.ListOrder, + defendant.Type, + defendant.FirstNames, + defendant.Surname, + DateTime.TryParse(defendant?.Dob, out var dob) ? dob : (DateTime?)null, + defendant?.PoliceRemandStatus?.ToString(), + defendant?.Youth, + defendant?.CustodyTimeLimit?.ToString(), + MapOffences(defendant?.Offences), + null, + MapProposedCharges(defendant?.ProposedCharges), + defendant?.NextHearing, + defendant?.DefendantPcdReview, + defendant?.Solicitor, + MapPersonalDetail(defendant?.PersonalDetail))).ToList(), + }; - await client.AddActionPlanAsync(caseId, mdsRequest); + string additionalInfo = listCaseDefendantsResponse?.Defendants is { Count: > 0 } + ? $"received #{listCaseDefendantsResponse.Defendants.Count} defendants" + : "received #0 defendants"; + this.LogOperationCompletedEvent(OperationName, request, stopwatch.Elapsed, additionalInfo); - this.LogOperationCompletedEvent(OperationName, request, stopwatch.Elapsed, ""); - return new NoContentResult(); - } - catch (Exception exception) - { - this.HandleException(OperationName, exception, request, stopwatch.Elapsed); - throw; - } + return listCaseDefendantsResponse; } - - /// - public async Task AddWitnessAsync(AddWitnessRequest request, CmsAuthValues cmsAuthValues) + catch (Exception exception) { - Requires.NotNull(request); - Requires.NotNull(request.caseId); - Requires.NotNull(request.Surname); - Requires.NotNull(cmsAuthValues); - Requires.NotNull(cmsAuthValues.CmsCookies, nameof(cmsAuthValues.CmsCookies)); - Requires.NotNull(cmsAuthValues.CmsModernToken, nameof(cmsAuthValues.CmsModernToken)); + this.HandleException(OperationName, exception, request, stopwatch.Elapsed); + throw; + } + } - var stopwatch = Stopwatch.StartNew(); - const string OperationName = "AddWitness"; + /// + public async Task GetCaseWitnessesAsync(GetCaseWitnessesRequest request, CmsAuthValues cmsAuthValues) + { + Requires.NotNull(request); + Requires.NotNull(cmsAuthValues.CmsAuthFullValue); - try - { - var cookie = new MasterDataServiceCookie(cmsAuthValues.CmsCookies, cmsAuthValues.CmsModernToken); - var cookieString = JsonSerializer.Serialize(cookie); - var client = this.mdsApiClientFactory.Create(cookieString); + var stopwatch = Stopwatch.StartNew(); + const string OperationName = "ListCaseWitnesses"; + string additionalInfo = $"received #0 witnesses"; + WitnessesResponse results = new (); - var mdsRequest = new ApiClient.Witness() - { - CaseId = request.caseId, - Surname = request.Surname, - FirstName = request.FirstName, - }; + try + { + var client = this.mdsApiClientFactory.Create(cmsAuthValues.CmsAuthFullValue); - await client.AddWitnessAsync(request.caseId, mdsRequest); - this.LogOperationCompletedEvent(OperationName, request, stopwatch.Elapsed, string.Empty); - return new NoContentResult(); + var data = await client.ListCaseWitnessesAsync(request.CaseId); + + if (data is not null) + { + results.Witnesses = data.Select(witness => new Witness( + witness.CaseId, + witness.WitnessId, + witness.FirstName, + witness.Surname)).ToList(); } - catch (Exception exception) + + if (results.Witnesses.Count > 0) { - this.HandleException(OperationName, exception, request, stopwatch.Elapsed); - throw; + additionalInfo = $"retrieved #{results.Witnesses.Count} witnesses"; } - } - /// - public async Task RenameMaterialAsync(RenameMaterialRequest request, CmsAuthValues cmsAuthValues) + this.LogOperationCompletedEvent(OperationName, request, stopwatch.Elapsed, additionalInfo); + } + catch (Exception exception) { - Requires.NotNull(request); - Requires.NotNull(request.materialId); - Requires.NotNull(cmsAuthValues); - Requires.NotNull(cmsAuthValues.CmsCookies, nameof(cmsAuthValues.CmsCookies)); - Requires.NotNull(cmsAuthValues.CmsModernToken, nameof(cmsAuthValues.CmsModernToken)); - - var stopwatch = Stopwatch.StartNew(); - const string OperationName = "RenameMaterial"; + this.HandleException(OperationName, exception, request, stopwatch.Elapsed); + throw; + } - try - { - var cookie = new MasterDataServiceCookie(cmsAuthValues.CmsCookies, cmsAuthValues.CmsModernToken); - var cookieString = JsonSerializer.Serialize(cookie); - var client = this.mdsApiClientFactory.Create(cookieString); + return results; + } - var mdsRequest = new ApiClient.RenameMaterialRequest() - { - MaterialId = request.materialId, - Subject = request.subject, - }; + /// + public async Task GetWitnessStatementsAsync(GetWitnessStatementsRequest request, CmsAuthValues cmsAuthValues) + { + Requires.NotNull(request); + Requires.NotNull(cmsAuthValues.CmsAuthFullValue); - var data = await client.RenameMaterialAsync(request.materialId, mdsRequest); + var stopwatch = Stopwatch.StartNew(); + const string OperationName = "GetStatementsForWitness"; + string additionalInfo = "received #0 statements"; - if (data?.UpdateCommunication?.Id == null) - { - return default; - } + WitnessStatementsResponse results = new (); - RenameMaterialResponse result = new(new RenameMaterialData { Id = data.UpdateCommunication.Id }); + try + { + var client = this.mdsApiClientFactory.Create(cmsAuthValues.CmsAuthFullValue); - this.LogOperationCompletedEvent(OperationName, request, stopwatch.Elapsed, string.Empty); + var data = await client.GetStatementsForWitnessAsync(request.WitnessId); - return result; + if (data?.StatementsForWitness is not null) + { + results.WitnessStatements = data.StatementsForWitness.Select(statement => + new WitnessStatement(statement.Id, statement.Title)).ToList(); } - catch (Exception exception) + + if (results.WitnessStatements?.Count > 0) { - this.HandleException(OperationName, exception, request, stopwatch.Elapsed); - throw; + additionalInfo = $"retrieved #{results.WitnessStatements.Count} statements"; } } - - /// - public async Task ReclassifyCommunicationAsync(ReclassifyCommunicationRequest request, CmsAuthValues cmsAuthValues) + catch (Exception exception) { - Requires.NotNull(request); - Requires.NotNull(cmsAuthValues); - Requires.NotNull(cmsAuthValues.CmsCookies, nameof(cmsAuthValues.CmsCookies)); - Requires.NotNull(cmsAuthValues.CmsModernToken, nameof(cmsAuthValues.CmsModernToken)); + this.HandleException(OperationName, exception, request, stopwatch.Elapsed); + throw; + } - var stopwatch = Stopwatch.StartNew(); - const string OperationName = "ReclassifyCommunication"; + return results; + } - try - { - var cookie = new MasterDataServiceCookie(cmsAuthValues.CmsCookies, cmsAuthValues.CmsModernToken); - var cookieString = JsonSerializer.Serialize(cookie); - var client = this.mdsApiClientFactory.Create(cookieString); + /// + public async Task AddCaseActionPlanAsync(int caseId, AddActionPlanRequest request, CmsAuthValues cmsAuthValues) + { + Requires.NotNull(request); + Requires.NotNull(cmsAuthValues.CmsAuthFullValue); - var mdsRequest = new ApiClient.HkReclassifyCommunicationRequest() - { - Classification = request.classification, - MaterialId = request.materialId, - DocumentTypeId = request.documentTypeId, - Used = request.used, - Subject = request.subject, - Statement = MapStatement(request.Statement), - Exhibit = MapExhibit(request.Exhibit), - }; + var stopwatch = Stopwatch.StartNew(); + const string OperationName = "AddActionPlan"; - var data = await client.ReclassifyCommunicationAsync(mdsRequest); + try + { + var client = this.mdsApiClientFactory.Create(cmsAuthValues.CmsAuthFullValue); - if (data?.ReclassifyCommunication?.Id == null) - { - return default; - } + var mdsRequest = MapApAction(request); - ReclassificationResponse result = new ReclassificationResponse(new ReclassifyCommunication { Id = data.ReclassifyCommunication.Id }); - this.LogOperationCompletedEvent(OperationName, request, stopwatch.Elapsed, string.Empty); + await client.AddActionPlanAsync(caseId, mdsRequest); - return result; - } - catch (Exception exception) - { - this.HandleException(OperationName, exception, request, stopwatch.Elapsed); - throw; - } + this.LogOperationCompletedEvent(OperationName, request, stopwatch.Elapsed, string.Empty); + return new NoContentResult(); } - - /// - public async Task CheckCaseLockAsync(int caseId, CmsAuthValues cmsAuthValues) + catch (Exception exception) { - if (caseId <= 0) - { - throw new ArgumentOutOfRangeException(nameof(caseId), "Case ID must be a positive integer."); - } + this.HandleException(OperationName, exception, request, stopwatch.Elapsed); + throw; + } + } - Requires.NotNull(cmsAuthValues); - Requires.NotNull(cmsAuthValues.CmsCookies, nameof(cmsAuthValues.CmsCookies)); - Requires.NotNull(cmsAuthValues.CmsModernToken, nameof(cmsAuthValues.CmsModernToken)); + /// + public async Task AddWitnessAsync(AddWitnessRequest request, CmsAuthValues cmsAuthValues) + { + Requires.NotNull(request); + Requires.NotNull(request.caseId); + Requires.NotNull(request.Surname); + Requires.NotNull(cmsAuthValues.CmsAuthFullValue); - var stopwatch = Stopwatch.StartNew(); - const string OperationName = "CaseLockStatus"; + var stopwatch = Stopwatch.StartNew(); + const string OperationName = "AddWitness"; - var dummyRequest = new BaseRequest(Guid.NewGuid()); + try + { + var client = this.mdsApiClientFactory.Create(cmsAuthValues.CmsAuthFullValue); - try + var mdsRequest = new ApiClient.Witness() { - var cookie = new MasterDataServiceCookie(cmsAuthValues.CmsCookies, cmsAuthValues.CmsModernToken); - var cookieString = JsonSerializer.Serialize(cookie); - var client = this.mdsApiClientFactory.Create(cookieString); - - var data = await client.GetCaseLockStatusAsync(caseId); + CaseId = request.caseId, + Surname = request.Surname, + FirstName = request.FirstName, + }; - var result = new CaseLockedStatusResult - { - IsLocked = data.IsLocked, - LockedByUser = data.LockedByUser, - CaseLockedMessage = data.CaseLockedMessage, - IsLockedByCurrentUser = data.IsLockedByCurrentUser, - }; - this.LogOperationCompletedEvent(OperationName, dummyRequest, stopwatch.Elapsed, string.Empty); - return result; - } - catch (Exception exception) - { - this.HandleException(OperationName, exception, dummyRequest, stopwatch.Elapsed); - throw; - } + await client.AddWitnessAsync(request.caseId, mdsRequest); + this.LogOperationCompletedEvent(OperationName, request, stopwatch.Elapsed, string.Empty); + return new NoContentResult(); } - - /// - public async Task DiscardMaterialAsync(DiscardMaterialRequest request, CmsAuthValues cmsAuthValues) + catch (Exception exception) { - Requires.NotNull(request); - Requires.NotNull(request.materialId); - Requires.NotNull(cmsAuthValues); - Requires.NotNull(cmsAuthValues.CmsCookies, nameof(cmsAuthValues.CmsCookies)); - Requires.NotNull(cmsAuthValues.CmsModernToken, nameof(cmsAuthValues.CmsModernToken)); + this.HandleException(OperationName, exception, request, stopwatch.Elapsed); + throw; + } + } - var stopwatch = Stopwatch.StartNew(); - const string OperationName = "DiscardMaterial"; + /// + public async Task RenameMaterialAsync(RenameMaterialRequest request, CmsAuthValues cmsAuthValues) + { + Requires.NotNull(request); + Requires.NotNull(request.materialId); + Requires.NotNull(cmsAuthValues.CmsAuthFullValue); - try - { - var cookie = new MasterDataServiceCookie(cmsAuthValues.CmsCookies, cmsAuthValues.CmsModernToken); - var cookieString = JsonSerializer.Serialize(cookie); - var client = this.mdsApiClientFactory.Create(cookieString); + var stopwatch = Stopwatch.StartNew(); + const string OperationName = "RenameMaterial"; - var mdsReqest = new ApiClient.DiscardMaterialRequest() - { - MaterialId = request.materialId, - DiscardReason = request.discardReason, - DiscardReasonDescription = request.discardReasonDescription, - }; + try + { + var client = this.mdsApiClientFactory.Create(cmsAuthValues.CmsAuthFullValue); - var data = await client.DiscardMaterialAsync(request.materialId, mdsReqest); - this.LogOperationCompletedEvent(OperationName, request, stopwatch.Elapsed, string.Empty); + var mdsRequest = new ApiClient.RenameMaterialRequest() + { + MaterialId = request.materialId, + Subject = request.subject, + }; - if (data?.DiscardMaterial?.Id == null) - { - return default; - } + var data = await client.RenameMaterialAsync(request.materialId, mdsRequest); - DiscardMaterialResponse result = new DiscardMaterialResponse(new DiscardMaterialData { Id = data.DiscardMaterial.Id }); - return result; - } - catch (Exception exception) + if (data?.UpdateCommunication?.Id == null) { - this.HandleException(OperationName, exception, request, stopwatch.Elapsed); - throw; + return default; } - } - /// - public async Task SetMaterialReadStatusAsync(SetMaterialReadStatusRequest request, CmsAuthValues cmsAuthValues) - { - Requires.NotNull(request); - Requires.NotNull(request.materialId); - Requires.NotNull(cmsAuthValues); - Requires.NotNull(cmsAuthValues.CmsCookies, nameof(cmsAuthValues.CmsCookies)); - Requires.NotNull(cmsAuthValues.CmsModernToken, nameof(cmsAuthValues.CmsModernToken)); + RenameMaterialResponse result = new (new RenameMaterialData { Id = data.UpdateCommunication.Id }); - var stopwatch = Stopwatch.StartNew(); - const string OperationName = "SetMaterialReadStatus"; - try - { - var cookie = new MasterDataServiceCookie(cmsAuthValues.CmsCookies, cmsAuthValues.CmsModernToken); - var cookieString = JsonSerializer.Serialize(cookie); - var client = this.mdsApiClientFactory.Create(cookieString); + this.LogOperationCompletedEvent(OperationName, request, stopwatch.Elapsed, string.Empty); - var mdsReqest = new ApiClient.MaterialReadStateRequest() - { - MaterialId = request.materialId, - State = (ApiClient.MaterialReadStateRequestState)request.state, - }; + return result; + } + catch (Exception exception) + { + this.HandleException(OperationName, exception, request, stopwatch.Elapsed); + throw; + } + } - var data = await client.SetMaterialReadStateAsync(request.materialId, mdsReqest); + /// + public async Task ReclassifyCommunicationAsync(ReclassifyCommunicationRequest request, CmsAuthValues cmsAuthValues) + { + Requires.NotNull(request); + Requires.NotNull(cmsAuthValues.CmsAuthFullValue); - if (data?.CompleteCommunication?.Id == null) - { - return default; - } + var stopwatch = Stopwatch.StartNew(); + const string OperationName = "ReclassifyCommunication"; - SetMaterialReadStatusResponse result = new SetMaterialReadStatusResponse(new SetMaterialReadStatusResponseData { Id = data.CompleteCommunication.Id }); + try + { + var client = this.mdsApiClientFactory.Create(cmsAuthValues.CmsAuthFullValue); - this.LogOperationCompletedEvent(OperationName, request, stopwatch.Elapsed, string.Empty); + var mdsRequest = new ApiClient.HkReclassifyCommunicationRequest() + { + Classification = request.classification, + MaterialId = request.materialId, + DocumentTypeId = request.documentTypeId, + Used = request.used, + Subject = request.subject, + Statement = MapStatement(request.Statement), + Exhibit = MapExhibit(request.Exhibit), + }; - return result; - } - catch (Exception exception) + var data = await client.ReclassifyCommunicationAsync(mdsRequest); + + if (data?.ReclassifyCommunication?.Id == null) { - this.HandleException(OperationName, exception, request, stopwatch.Elapsed); - throw; + return default; } - } - /// - public async Task> GetPcdRequestCoreAsync(GetPcdRequestsCoreRequest request, CmsAuthValues cmsAuthValues) + ReclassificationResponse result = new ReclassificationResponse(new ReclassifyCommunication { Id = data.ReclassifyCommunication.Id }); + this.LogOperationCompletedEvent(OperationName, request, stopwatch.Elapsed, string.Empty); + + return result; + } + catch (Exception exception) { - Requires.NotNull(request); - Requires.NotNull(cmsAuthValues); - Requires.NotNull(cmsAuthValues.CmsCookies, nameof(cmsAuthValues.CmsCookies)); - Requires.NotNull(cmsAuthValues.CmsModernToken, nameof(cmsAuthValues.CmsModernToken)); + this.HandleException(OperationName, exception, request, stopwatch.Elapsed); + throw; + } + } - if (string.IsNullOrEmpty(cmsAuthValues.CmsCookies)) - { - throw new ArgumentException($"{LoggingConstants.HskUiLogPrefix} CMS Cookies cannot be null or empty.", nameof(request)); - } + /// + public async Task CheckCaseLockAsync(int caseId, CmsAuthValues cmsAuthValues) + { + if (caseId <= 0) + { + throw new ArgumentOutOfRangeException(nameof(caseId), "Case ID must be a positive integer."); + } - var stopwatch = Stopwatch.StartNew(); - const string OperationName = "PcdRequestCore"; + Requires.NotNull(cmsAuthValues.CmsAuthFullValue); - List results = new(); - try - { - var cookie = new MasterDataServiceCookie(cmsAuthValues.CmsCookies, cmsAuthValues.CmsModernToken); - var cookieString = JsonSerializer.Serialize(cookie); - var client = this.mdsApiClientFactory.Create(cookieString); + var stopwatch = Stopwatch.StartNew(); + const string OperationName = "CaseLockStatus"; - var data = await client.GetCasePcdRequestCoreAsync(request.caseId); + var dummyRequest = new BaseRequest(Guid.NewGuid()); - if (data is not null) - { - results = data.Select(pcd => new PcdRequestCore() - { - Id = pcd.Id, - Type = pcd.Type, - DecisionRequiredBy = pcd.DecisionRequiredBy, - DecisionRequested = pcd.DecisionRequested, - }).ToList(); - } + try + { + var client = this.mdsApiClientFactory.Create(cmsAuthValues.CmsAuthFullValue); - this.LogOperationCompletedEvent(OperationName, request, stopwatch.Elapsed, string.Empty); + var data = await client.GetCaseLockStatusAsync(caseId); - return results; - } - catch (Exception exception) + var result = new CaseLockedStatusResult { - this.HandleException(OperationName, exception, request, stopwatch.Elapsed); - throw; - } + IsLocked = data.IsLocked, + LockedByUser = data.LockedByUser, + CaseLockedMessage = data.CaseLockedMessage, + IsLockedByCurrentUser = data.IsLockedByCurrentUser, + }; + this.LogOperationCompletedEvent(OperationName, dummyRequest, stopwatch.Elapsed, string.Empty); + return result; } - - /// - public async Task GetPcdRequestByPcdIdAsync(GetPcdRequestByPcdIdCoreRequest request, CmsAuthValues cmsAuthValues) + catch (Exception exception) { - Requires.NotNull(request); - Requires.NotNull(cmsAuthValues); - Requires.NotNull(cmsAuthValues.CmsCookies, nameof(cmsAuthValues.CmsCookies)); - Requires.NotNull(cmsAuthValues.CmsModernToken, nameof(cmsAuthValues.CmsModernToken)); + this.HandleException(OperationName, exception, dummyRequest, stopwatch.Elapsed); + throw; + } + } - if (string.IsNullOrEmpty(cmsAuthValues.CmsCookies)) - { - throw new ArgumentException($"{LoggingConstants.HskUiLogPrefix} CMS Cookies cannot be null or empty.", nameof(request)); - } + /// + public async Task DiscardMaterialAsync(DiscardMaterialRequest request, CmsAuthValues cmsAuthValues) + { + Requires.NotNull(request); + Requires.NotNull(request.materialId); + Requires.NotNull(cmsAuthValues.CmsAuthFullValue); - var stopwatch = Stopwatch.StartNew(); - const string OperationName = "GetCasePcdRequestByPcdId"; + var stopwatch = Stopwatch.StartNew(); + const string OperationName = "DiscardMaterial"; - var results = new PcdRequestDto(); + try + { + var client = this.mdsApiClientFactory.Create(cmsAuthValues.CmsAuthFullValue); - try + var mdsReqest = new ApiClient.DiscardMaterialRequest() { - var cookie = new MasterDataServiceCookie(cmsAuthValues.CmsCookies, cmsAuthValues.CmsModernToken); - var cookieString = JsonSerializer.Serialize(cookie); - var client = this.mdsApiClientFactory.Create(cookieString); - - var data = await client.GetCasePcdRequestByPcdIdAsync(request.caseId, request.pcdId); + MaterialId = request.materialId, + DiscardReason = request.discardReason, + DiscardReasonDescription = request.discardReasonDescription, + }; - if (data is not null) - { - results = - new PcdRequestDto() - { - CaseOutline = data.CaseOutline.Select(co => new PcdCaseOutlineLine() - { - Heading = co.Heading, - Text = co.Text, - TextWithCmsMarkup = co.TextWithCmsMarkup, - }).ToList(), - Comments = new PcdComments() - { - Text = data.Comments?.Text, - TextWithCmsMarkup = data.Comments?.TextWithCmsMarkup, - }, - Suspects = data.Suspects.Select(sus => new PcdRequestSuspect() - { - Surname = sus.Surname, - FirstNames = sus.FirstNames, - Dob = sus.Dob, - BailConditions = sus.BailConditions, - BailDate = sus.BailDate, - RemandStatus = sus.RemandStatus, - ProposedCharges = sus.ProposedCharges.Select(charge => new PcdProposedCharge() { Charge = charge.Charge, EarlyDate = charge.EarlyDate, LateDate = charge.LateDate, Location = charge.Location, Category = charge.Category }).ToList(), - }).ToList(), - PoliceContactDetails = data.PoliceContactDetails.Select(police => new PCDPoliceContactDetails() - { - Role = police.Role, - Rank = police.Rank, - Name = police.Name, - Number = police.Number, - }).ToList(), - MaterialProvided = data.MaterialProvided.Select(mat => new MaterialProvided() - { - Subject = mat.Subject, - Date = mat.Date, - }).ToList(), - Id = data.Id, - Type = data.Type, - DecisionRequested = data.DecisionRequested, - DecisionRequiredBy = data.DecisionRequiredBy, - }; - } + var data = await client.DiscardMaterialAsync(request.materialId, mdsReqest); + this.LogOperationCompletedEvent(OperationName, request, stopwatch.Elapsed, string.Empty); - this.LogOperationCompletedEvent(OperationName, request, stopwatch.Elapsed, string.Empty); - return results; - } - catch (Exception exception) + if (data?.DiscardMaterial?.Id == null) { - this.HandleException(OperationName, exception, request, stopwatch.Elapsed); - throw; + return default; } - } - /// - public async Task UpdateStatementAsync(UpdateStatementRequest request, CmsAuthValues cmsAuthValues) + DiscardMaterialResponse result = new DiscardMaterialResponse(new DiscardMaterialData { Id = data.DiscardMaterial.Id }); + return result; + } + catch (Exception exception) { - Requires.NotNull(request); - Requires.NotNull(request.MaterialId); - Requires.NotNull(request.WitnessId); - Requires.NotNull(request.StatementNumber); - Requires.NotNull(cmsAuthValues); - Requires.NotNull(cmsAuthValues.CmsCookies, nameof(cmsAuthValues.CmsCookies)); - Requires.NotNull(cmsAuthValues.CmsModernToken, nameof(cmsAuthValues.CmsModernToken)); + this.HandleException(OperationName, exception, request, stopwatch.Elapsed); + throw; + } + } - var stopwatch = Stopwatch.StartNew(); - const string OperationName = "UpdateStatement"; + /// + public async Task SetMaterialReadStatusAsync(SetMaterialReadStatusRequest request, CmsAuthValues cmsAuthValues) + { + Requires.NotNull(request); + Requires.NotNull(request.materialId); + Requires.NotNull(cmsAuthValues.CmsAuthFullValue); + + var stopwatch = Stopwatch.StartNew(); + const string OperationName = "SetMaterialReadStatus"; + try + { + var client = this.mdsApiClientFactory.Create(cmsAuthValues.CmsAuthFullValue); - try + var mdsReqest = new ApiClient.MaterialReadStateRequest() { - var cookie = new MasterDataServiceCookie(cmsAuthValues.CmsCookies, cmsAuthValues.CmsModernToken); - var cookieString = JsonSerializer.Serialize(cookie); - var client = this.mdsApiClientFactory.Create(cookieString); + MaterialId = request.materialId, + State = (ApiClient.MaterialReadStateRequestState)request.state, + }; - var statementDate = ConvertToDateTimeOffset(request.StatementDate); + var data = await client.SetMaterialReadStateAsync(request.materialId, mdsReqest); - var mdsRequest = new ApiClient.UpdateStatementRequest - { - MaterialId = request.MaterialId, - WitnessId = request.WitnessId, - StatementNumber = request.StatementNumber, - StatementDate = statementDate, - Used = request.Used, - }; + if (data?.CompleteCommunication?.Id == null) + { + return default; + } - var data = await client.UpdateStatementAsync(request.CaseId, request.MaterialId, mdsRequest); + SetMaterialReadStatusResponse result = new SetMaterialReadStatusResponse(new SetMaterialReadStatusResponseData { Id = data.CompleteCommunication.Id }); - if (data?.UpdateStatement?.Id == null) - { - return default; - } + this.LogOperationCompletedEvent(OperationName, request, stopwatch.Elapsed, string.Empty); - UpdateStatementResponse result = new UpdateStatementResponse(new UpdateStatementData { Id = data.UpdateStatement.Id }); - this.LogOperationCompletedEvent(OperationName, request, stopwatch.Elapsed, string.Empty); - return result; - } - catch (Exception exception) - { - this.HandleException(OperationName, exception, request, stopwatch.Elapsed); - throw; - } + return result; + } + catch (Exception exception) + { + this.HandleException(OperationName, exception, request, stopwatch.Elapsed); + throw; } + } + + /// + public async Task> GetPcdRequestCoreAsync(GetPcdRequestsCoreRequest request, CmsAuthValues cmsAuthValues) + { + Requires.NotNull(request); + Requires.NotNull(cmsAuthValues.CmsAuthFullValue); - /// - public async Task UpdateExhibitAsync(UpdateExhibitRequest request, CmsAuthValues cmsAuthValues) + var stopwatch = Stopwatch.StartNew(); + const string OperationName = "PcdRequestCore"; + + List results = new (); + try { - Requires.NotNull(request); - Requires.NotNull(request.CaseId); - Requires.NotNull(request.MaterialId); - Requires.NotNull(request.DocumentType); - Requires.NotNull(request.Item); - Requires.NotNull(request.Reference); - Requires.NotNull(cmsAuthValues); - Requires.NotNull(cmsAuthValues.CmsCookies, nameof(cmsAuthValues.CmsCookies)); - Requires.NotNull(cmsAuthValues.CmsModernToken, nameof(cmsAuthValues.CmsModernToken)); + var client = this.mdsApiClientFactory.Create(cmsAuthValues.CmsAuthFullValue); - var stopwatch = Stopwatch.StartNew(); - const string OperationName = "UpdateExhibit"; + var data = await client.GetCasePcdRequestCoreAsync(request.caseId); - try + if (data is not null) { - var cookie = new MasterDataServiceCookie(cmsAuthValues.CmsCookies, cmsAuthValues.CmsModernToken); - var cookieString = JsonSerializer.Serialize(cookie); - var client = this.mdsApiClientFactory.Create(cookieString); - - var mdsRequest = new ApiClient.UpdateExhibitRequest + results = data.Select(pcd => new PcdRequestCore() { - CaseId = request.CaseId, - MaterialId = request.MaterialId, - DocumentType = request.DocumentType, - Item = request.Item, - Reference = request.Reference, - Subject = request.Subject, - ExistingProducerOrWitnessId = request.ExistingProducerOrWitnessId, - NewProducer = request.NewProducer, - Used = request.Used, - }; + Id = pcd.Id, + Type = pcd.Type, + DecisionRequiredBy = pcd.DecisionRequiredBy, + DecisionRequested = pcd.DecisionRequested, + }).ToList(); + } - var data = await client.UpdateExhibitAsync(request.CaseId, request.MaterialId, mdsRequest); + this.LogOperationCompletedEvent(OperationName, request, stopwatch.Elapsed, string.Empty); - if (data?.UpdateExhibit?.Id == null) - { - return default; - } + return results; + } + catch (Exception exception) + { + this.HandleException(OperationName, exception, request, stopwatch.Elapsed); + throw; + } + } - UpdateExhibitResponse result = new UpdateExhibitResponse(new UpdateExhibitData { Id = data.UpdateExhibit.Id }); + /// + public async Task GetPcdRequestByPcdIdAsync(GetPcdRequestByPcdIdCoreRequest request, CmsAuthValues cmsAuthValues) + { + Requires.NotNull(request); + Requires.NotNull(cmsAuthValues.CmsAuthFullValue); - this.LogOperationCompletedEvent(OperationName, request, stopwatch.Elapsed, string.Empty); - return result; + var stopwatch = Stopwatch.StartNew(); + const string OperationName = "GetCasePcdRequestByPcdId"; - } - catch (Exception exception) - { - this.HandleException(OperationName, exception, request, stopwatch.Elapsed); - throw; - } - } + var results = new PcdRequestDto(); - /// - public async Task FirstInitialReviewGetCaseHistoryAsync(int caseId, CmsAuthValues cmsAuthValues) + try { - Requires.NotNull(caseId); - Requires.NotNull(cmsAuthValues); - Requires.NotNull(cmsAuthValues.CmsCookies, nameof(cmsAuthValues.CmsCookies)); - Requires.NotNull(cmsAuthValues.CmsModernToken, nameof(cmsAuthValues.CmsModernToken)); + var client = this.mdsApiClientFactory.Create(cmsAuthValues.CmsAuthFullValue); - var stopwatch = Stopwatch.StartNew(); - const string OperationName = "FirstInitialReviewGetCaseHistory"; + var data = await client.GetCasePcdRequestByPcdIdAsync(request.caseId, request.pcdId); - try + if (data is not null) { - var cookie = new MasterDataServiceCookie(cmsAuthValues.CmsCookies, cmsAuthValues.CmsModernToken); - var cookieString = JsonSerializer.Serialize(cookie); - var client = this.mdsApiClientFactory.Create(cookieString); - - var data = await client.FirstInitialReviewGetCaseHistoryAsync(caseId); - return data; - } - catch (Exception exception) - { - this.HandleException(OperationName, exception, null, stopwatch.Elapsed); - throw; + results = + new PcdRequestDto() + { + CaseOutline = data.CaseOutline.Select(co => new PcdCaseOutlineLine() + { + Heading = co.Heading, + Text = co.Text, + TextWithCmsMarkup = co.TextWithCmsMarkup, + }).ToList(), + Comments = new PcdComments() + { + Text = data.Comments?.Text, + TextWithCmsMarkup = data.Comments?.TextWithCmsMarkup, + }, + Suspects = data.Suspects.Select(sus => new PcdRequestSuspect() + { + Surname = sus.Surname, + FirstNames = sus.FirstNames, + Dob = sus.Dob, + BailConditions = sus.BailConditions, + BailDate = sus.BailDate, + RemandStatus = sus.RemandStatus, + ProposedCharges = sus.ProposedCharges.Select(charge => new PcdProposedCharge() { Charge = charge.Charge, EarlyDate = charge.EarlyDate, LateDate = charge.LateDate, Location = charge.Location, Category = charge.Category }).ToList(), + }).ToList(), + PoliceContactDetails = data.PoliceContactDetails.Select(police => new PCDPoliceContactDetails() + { + Role = police.Role, + Rank = police.Rank, + Name = police.Name, + Number = police.Number, + }).ToList(), + MaterialProvided = data.MaterialProvided.Select(mat => new MaterialProvided() + { + Subject = mat.Subject, + Date = mat.Date, + }).ToList(), + Id = data.Id, + Type = data.Type, + DecisionRequested = data.DecisionRequested, + DecisionRequiredBy = data.DecisionRequiredBy, + }; } + + this.LogOperationCompletedEvent(OperationName, request, stopwatch.Elapsed, string.Empty); + return results; + } + catch (Exception exception) + { + this.HandleException(OperationName, exception, request, stopwatch.Elapsed); + throw; } + } - /// - public async Task GetInitialReviewByHistoryIdAsync(int caseId, int historyId, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken) + /// + public async Task UpdateStatementAsync(UpdateStatementRequest request, CmsAuthValues cmsAuthValues) + { + Requires.NotNull(request); + Requires.NotNull(request.MaterialId); + Requires.NotNull(request.WitnessId); + Requires.NotNull(request.StatementNumber); + Requires.NotNull(cmsAuthValues.CmsAuthFullValue); + + var stopwatch = Stopwatch.StartNew(); + const string OperationName = "UpdateStatement"; + + try { - Requires.NotNull(caseId); - Requires.NotNull(historyId); - Requires.NotNull(cmsAuthValues); - Requires.NotNull(cmsAuthValues.CmsCookies, nameof(cmsAuthValues.CmsCookies)); - Requires.NotNull(cmsAuthValues.CmsModernToken, nameof(cmsAuthValues.CmsModernToken)); + var client = this.mdsApiClientFactory.Create(cmsAuthValues.CmsAuthFullValue); - var stopwatch = Stopwatch.StartNew(); - const string OperationName = "GetInitialReviewByHistoryId"; + var statementDate = ConvertToDateTimeOffset(request.StatementDate); - try + var mdsRequest = new ApiClient.UpdateStatementRequest { - var cookie = new MasterDataServiceCookie(cmsAuthValues.CmsCookies, cmsAuthValues.CmsModernToken); - var cookieString = JsonSerializer.Serialize(cookie); - var client = this.mdsApiClientFactory.Create(cookieString); + MaterialId = request.MaterialId, + WitnessId = request.WitnessId, + StatementNumber = request.StatementNumber, + StatementDate = statementDate, + Used = request.Used, + }; - var data = await client.GetInitialReviewByIdAsync(caseId, historyId, cancellationToken); - return data; - } - catch (Exception exception) + var data = await client.UpdateStatementAsync(request.CaseId, request.MaterialId, mdsRequest); + + if (data?.UpdateStatement?.Id == null) { - this.HandleException(OperationName, exception, null, stopwatch.Elapsed); - throw; + return default; } - } - /// - public async Task GetPcdAnalysisByIdAsync( - int caseId, - int historyId, - CmsAuthValues cmsAuthValues, - CancellationToken cancellationToken) + UpdateStatementResponse result = new UpdateStatementResponse(new UpdateStatementData { Id = data.UpdateStatement.Id }); + this.LogOperationCompletedEvent(OperationName, request, stopwatch.Elapsed, string.Empty); + return result; + } + catch (Exception exception) { - Requires.NotNull(caseId); - Requires.NotNull(historyId); - Requires.NotNull(cmsAuthValues); - Requires.NotNull(cmsAuthValues.CmsCookies, nameof(cmsAuthValues.CmsCookies)); - Requires.NotNull(cmsAuthValues.CmsModernToken, nameof(cmsAuthValues.CmsModernToken)); + this.HandleException(OperationName, exception, request, stopwatch.Elapsed); + throw; + } + } - var stopwatch = Stopwatch.StartNew(); - const string OperationName = "GetInitialReviewByHistoryId"; + /// + public async Task UpdateExhibitAsync(UpdateExhibitRequest request, CmsAuthValues cmsAuthValues) + { + Requires.NotNull(request); + Requires.NotNull(request.CaseId); + Requires.NotNull(request.MaterialId); + Requires.NotNull(request.DocumentType); + Requires.NotNull(request.Item); + Requires.NotNull(request.Reference); + Requires.NotNull(cmsAuthValues); + Requires.NotNull(cmsAuthValues.CmsAuthFullValue); + + var stopwatch = Stopwatch.StartNew(); + const string OperationName = "UpdateExhibit"; + + try + { + var client = this.mdsApiClientFactory.Create(cmsAuthValues.CmsAuthFullValue); + + var mdsRequest = new ApiClient.UpdateExhibitRequest + { + CaseId = request.CaseId, + MaterialId = request.MaterialId, + DocumentType = request.DocumentType, + Item = request.Item, + Reference = request.Reference, + Subject = request.Subject, + ExistingProducerOrWitnessId = request.ExistingProducerOrWitnessId, + NewProducer = request.NewProducer, + Used = request.Used, + }; - try - { - var cookie = new MasterDataServiceCookie(cmsAuthValues.CmsCookies, cmsAuthValues.CmsModernToken); - var cookieString = JsonSerializer.Serialize(cookie); - var client = this.mdsApiClientFactory.Create(cookieString); + var data = await client.UpdateExhibitAsync(request.CaseId, request.MaterialId, mdsRequest); - var data = await client.GetPcdAnalysisByIdAsync(caseId, historyId); - return data; - } - catch (Exception exception) + if (data?.UpdateExhibit?.Id == null) { - this.HandleException(OperationName, exception, null, stopwatch.Elapsed); - throw; + return default; } - } - /// - public async Task> GetHistoryEventsAsync(int caseId, CmsAuthValues cmsAuthValues) + UpdateExhibitResponse result = new UpdateExhibitResponse(new UpdateExhibitData { Id = data.UpdateExhibit.Id }); + + this.LogOperationCompletedEvent(OperationName, request, stopwatch.Elapsed, string.Empty); + return result; + } + catch (Exception exception) { - Requires.NotNull(caseId); - Requires.NotNull(cmsAuthValues); - Requires.NotNull(cmsAuthValues.CmsCookies, nameof(cmsAuthValues.CmsCookies)); - Requires.NotNull(cmsAuthValues.CmsModernToken, nameof(cmsAuthValues.CmsModernToken)); + this.HandleException(OperationName, exception, request, stopwatch.Elapsed); + throw; + } + } - var stopwatch = Stopwatch.StartNew(); - const string OperationName = "GetHistoryEvents"; + /// + public async Task FirstInitialReviewGetCaseHistoryAsync(int caseId, CmsAuthValues cmsAuthValues) + { + Requires.NotNull(caseId); + Requires.NotNull(cmsAuthValues.CmsAuthFullValue); - try - { - var cookie = new MasterDataServiceCookie(cmsAuthValues.CmsCookies, cmsAuthValues.CmsModernToken); - var cookieString = JsonSerializer.Serialize(cookie); - var client = this.mdsApiClientFactory.Create(cookieString); + var stopwatch = Stopwatch.StartNew(); + const string OperationName = "FirstInitialReviewGetCaseHistory"; - var data = await client.GetCaseHistoryEventsAsync(caseId); - return data; - } - catch (Exception exception) - { - this.HandleException(OperationName, exception, null, stopwatch.Elapsed); - throw; - } - } + try + { + var client = this.mdsApiClientFactory.Create(cmsAuthValues.CmsAuthFullValue); - /// - public async Task GetOffenceChargeByHistoryIdAsync(int caseId, int historyId, CmsAuthValues cmsAuthValues) + var data = await client.FirstInitialReviewGetCaseHistoryAsync(caseId); + return data; + } + catch (Exception exception) { - Requires.NotNull(caseId); - Requires.NotNull(historyId); - Requires.NotNull(cmsAuthValues); - Requires.NotNull(cmsAuthValues.CmsCookies, nameof(cmsAuthValues.CmsCookies)); - Requires.NotNull(cmsAuthValues.CmsModernToken, nameof(cmsAuthValues.CmsModernToken)); + this.HandleException(OperationName, exception, null, stopwatch.Elapsed); + throw; + } + } - var stopwatch = Stopwatch.StartNew(); - const string OperationName = "GetOffenceCharge"; + /// + public async Task GetInitialReviewByHistoryIdAsync(int caseId, int historyId, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken) + { + Requires.NotNull(caseId); + Requires.NotNull(historyId); + Requires.NotNull(cmsAuthValues.CmsAuthFullValue); - try - { - var cookie = new MasterDataServiceCookie(cmsAuthValues.CmsCookies, cmsAuthValues.CmsModernToken); - var cookieString = JsonSerializer.Serialize(cookie); - var client = this.mdsApiClientFactory.Create(cookieString); + var stopwatch = Stopwatch.StartNew(); + const string OperationName = "GetInitialReviewByHistoryId"; - var data = await client.GetOffenceChangeByIdAsync(caseId, historyId); - return data; - } - catch (Exception exception) - { - this.HandleException(OperationName, exception, null, stopwatch.Elapsed); - throw; - } - } + try + { + var client = this.mdsApiClientFactory.Create(cmsAuthValues.CmsAuthFullValue); - /// - public async Task GetPreChargeDecisionCaseHistoryEventDetailsAsync(int caseId, CmsAuthValues cmsAuthValues) + var data = await client.GetInitialReviewByIdAsync(caseId, historyId, cancellationToken); + return data; + } + catch (Exception exception) { - Requires.NotNull(caseId); - Requires.NotNull(cmsAuthValues); - Requires.NotNull(cmsAuthValues.CmsCookies, nameof(cmsAuthValues.CmsCookies)); - Requires.NotNull(cmsAuthValues.CmsModernToken, nameof(cmsAuthValues.CmsModernToken)); + this.HandleException(OperationName, exception, null, stopwatch.Elapsed); + throw; + } + } - var stopwatch = Stopwatch.StartNew(); - const string OperationName = "GetOffenceCharge"; + /// + public async Task GetPcdAnalysisByIdAsync( + int caseId, + int historyId, + CmsAuthValues cmsAuthValues, + CancellationToken cancellationToken) + { + Requires.NotNull(caseId); + Requires.NotNull(historyId); + Requires.NotNull(cmsAuthValues.CmsAuthFullValue); - try - { - var cookie = new MasterDataServiceCookie(cmsAuthValues.CmsCookies, cmsAuthValues.CmsModernToken); - var cookieString = JsonSerializer.Serialize(cookie); - var client = this.mdsApiClientFactory.Create(cookieString); + var stopwatch = Stopwatch.StartNew(); + const string OperationName = "GetInitialReviewByHistoryId"; - var data = await client.GetPreChargeDecisionOutcomesAsync(caseId); - return data; - } - catch (Exception exception) - { - this.HandleException(OperationName, exception, null, stopwatch.Elapsed); - throw; - } - } + try + { + var client = this.mdsApiClientFactory.Create(cmsAuthValues.CmsAuthFullValue); - /// - public async Task GetPreChargeDecisionByHistoryId(int caseId, int historyId, CmsAuthValues cmsAuthValues) + var data = await client.GetPcdAnalysisByIdAsync(caseId, historyId); + return data; + } + catch (Exception exception) { - Requires.NotNull(caseId); - Requires.NotNull(historyId); - Requires.NotNull(cmsAuthValues); - Requires.NotNull(cmsAuthValues.CmsCookies, nameof(cmsAuthValues.CmsCookies)); - Requires.NotNull(cmsAuthValues.CmsModernToken, nameof(cmsAuthValues.CmsModernToken)); + this.HandleException(OperationName, exception, null, stopwatch.Elapsed); + throw; + } + } - var stopwatch = Stopwatch.StartNew(); - const string OperationName = "GetPreChargeDecisionByHistoryId"; + /// + public async Task> GetHistoryEventsAsync(int caseId, CmsAuthValues cmsAuthValues) + { + Requires.NotNull(caseId); + Requires.NotNull(cmsAuthValues.CmsAuthFullValue); - try - { - var cookie = new MasterDataServiceCookie(cmsAuthValues.CmsCookies, cmsAuthValues.CmsModernToken); - var cookieString = JsonSerializer.Serialize(cookie); - var client = this.mdsApiClientFactory.Create(cookieString); + var stopwatch = Stopwatch.StartNew(); + const string OperationName = "GetHistoryEvents"; - var data = await client.GetPreChargeDecisionByIdAsync(caseId, historyId); - return data; - } - catch (Exception exception) - { - this.HandleException(OperationName, exception, null, stopwatch.Elapsed); - throw; - } - } + try + { + var client = this.mdsApiClientFactory.Create(cmsAuthValues.CmsAuthFullValue); - /// - public async Task GetPcdReview(int caseId, CmsAuthValues cmsAuthValues) + var data = await client.GetCaseHistoryEventsAsync(caseId); + return data; + } + catch (Exception exception) { - Requires.NotNull(caseId); - Requires.NotNull(cmsAuthValues); - Requires.NotNull(cmsAuthValues.CmsCookies, nameof(cmsAuthValues.CmsCookies)); - Requires.NotNull(cmsAuthValues.CmsModernToken, nameof(cmsAuthValues.CmsModernToken)); + this.HandleException(OperationName, exception, null, stopwatch.Elapsed); + throw; + } + } - var stopwatch = Stopwatch.StartNew(); - const string OperationName = "GetPcdReview"; + /// + public async Task GetOffenceChargeByHistoryIdAsync(int caseId, int historyId, CmsAuthValues cmsAuthValues) + { + Requires.NotNull(caseId); + Requires.NotNull(historyId); + Requires.NotNull(cmsAuthValues.CmsAuthFullValue); - try - { - var cookie = new MasterDataServiceCookie(cmsAuthValues.CmsCookies, cmsAuthValues.CmsModernToken); - var cookieString = JsonSerializer.Serialize(cookie); - var client = this.mdsApiClientFactory.Create(cookieString); + var stopwatch = Stopwatch.StartNew(); + const string OperationName = "GetOffenceCharge"; - var data = await client.GetPcdReviewAsync(caseId); - return data; - } - catch (Exception exception) - { - this.HandleException(OperationName, exception, null, stopwatch.Elapsed); - throw; - } + try + { + var client = this.mdsApiClientFactory.Create(cmsAuthValues.CmsAuthFullValue); + + var data = await client.GetOffenceChangeByIdAsync(caseId, historyId); + return data; } + catch (Exception exception) + { + this.HandleException(OperationName, exception, null, stopwatch.Elapsed); + throw; + } + } + + /// + public async Task GetPreChargeDecisionCaseHistoryEventDetailsAsync(int caseId, CmsAuthValues cmsAuthValues) + { + Requires.NotNull(caseId); + Requires.NotNull(cmsAuthValues.CmsAuthFullValue); + + var stopwatch = Stopwatch.StartNew(); + const string OperationName = "GetOffenceCharge"; - private static ExhibitAttachmentSubType MapExhibitSubItem(ApiClient.ExhibitAttachmentHkSubType exhibit) + try { - if (exhibit is null) - { - return null; - } + var client = this.mdsApiClientFactory.Create(cmsAuthValues.CmsAuthFullValue); - return new ExhibitAttachmentSubType(exhibit.Reference, exhibit.Item, exhibit.Producer); + var data = await client.GetPreChargeDecisionOutcomesAsync(caseId); + return data; } + catch (Exception exception) + { + this.HandleException(OperationName, exception, null, stopwatch.Elapsed); + throw; + } + } - private static StatementAttachmentSubType MapStatementSubType(ApiClient.StatementAttachmentHkSubType statement) + /// + public async Task GetPreChargeDecisionByHistoryId(int caseId, int historyId, CmsAuthValues cmsAuthValues) + { + Requires.NotNull(caseId); + Requires.NotNull(historyId); + Requires.NotNull(cmsAuthValues.CmsAuthFullValue); + + var stopwatch = Stopwatch.StartNew(); + const string OperationName = "GetPreChargeDecisionByHistoryId"; + + try { - if (statement == null) - { - return null; - } + var client = this.mdsApiClientFactory.Create(cmsAuthValues.CmsAuthFullValue); - return new StatementAttachmentSubType( - statement.WitnessName, - statement?.WitnessTitle, - statement?.WitnessShoulderNo, - statement.StatementNo, - statement.Date, - statement?.Witness); + var data = await client.GetPreChargeDecisionByIdAsync(caseId, historyId); + return data; } - - private static List MapOffences(ICollection offence) + catch (Exception exception) { - if (offence is null) - { - return null; - } + this.HandleException(OperationName, exception, null, stopwatch.Elapsed); + throw; + } + } - return new List( - offence.Select(offence => - new Offence( - offence.Id, - offence.ListOrder, - offence.Code, - offence.Type, - offence.Active, - offence.Description, - offence.FromDate, - offence.ToDate, - offence.LatestPlea, - offence.LatestVerdict, - offence.DisposedReason, - offence.LastHearingOutcome, - offence?.CustodyTimeLimit?.ToString(), - offence.LatestPleaDescription))); - } - - private static List MapProposedCharges(ICollection proposedCharges) - { - if (proposedCharges is null) - { - return null; - } + /// + public async Task GetPcdReview(int caseId, CmsAuthValues cmsAuthValues) + { + Requires.NotNull(caseId); + Requires.NotNull(cmsAuthValues.CmsAuthFullValue); - return new List( - proposedCharges.Select(charge => - new ProposedCharge( - charge.Id, - charge.CaseId, - charge.DefendantId, - charge.Surname, - charge.FirstNames, - charge.Code, - charge.Description, - MapLocation(charge.Location), - charge.FromDate, - charge.ToDate, - charge.ChargeParticulars, - charge.AnticipatedPlea.ToString(), - charge.AdjudicationCode.ToString()))); - } - - private static PersonalDetail MapPersonalDetail(ApiClient.DefendantPersonalDetail defendantPersonalDetail) - { - if (defendantPersonalDetail is null) - { - return null; - } + var stopwatch = Stopwatch.StartNew(); + const string OperationName = "GetPcdReview"; - return new PersonalDetail( - MappAddress(defendantPersonalDetail.Address), - defendantPersonalDetail.Email, - defendantPersonalDetail.Ethnicity.ToString(), - defendantPersonalDetail.Gender.ToString(), - defendantPersonalDetail.Occupation, - defendantPersonalDetail.HomePhoneNumber, - defendantPersonalDetail.MobilePhoneNumber, - defendantPersonalDetail.WorkPhoneNumber, - defendantPersonalDetail.PreferredCorrespondenceLanguage.ToString(), - defendantPersonalDetail.Religion.ToString(), - defendantPersonalDetail.Guardian); - } + try + { + var client = this.mdsApiClientFactory.Create(cmsAuthValues.CmsAuthFullValue); - private static Address MappAddress(ApiClient.PostalAddress address) + var data = await client.GetPcdReviewAsync(caseId); + return data; + } + catch (Exception exception) { - if (address is null) - { - return default; - } + this.HandleException(OperationName, exception, null, stopwatch.Elapsed); + throw; + } + } - return new Address( - address.Postcode, - address.AddressLine1, - address.AddressLine2, - address.AddressLine3, - address.AddressLine4, - address.AddressLine5, - address.AddressLine6, - address.AddressLine7, - address.AddressLine8); + private static ExhibitAttachmentSubType MapExhibitSubItem(ApiClient.ExhibitAttachmentHkSubType exhibit) + { + if (exhibit is null) + { + return null; } - private static Location MapLocation(ApiClient.InternationalAddress address) + return new ExhibitAttachmentSubType(exhibit.Reference, exhibit.Item, exhibit.Producer); + } + + private static StatementAttachmentSubType MapStatementSubType(ApiClient.StatementAttachmentHkSubType statement) + { + if (statement == null) { - if (address is null) - { - return default; - } + return null; + } - return new Location( - address.Country, - address.Postcode, - address.AddressLine1, - address.AddressLine2, - address.AddressLine3, - address.AddressLine4, - address.AddressLine5, - address.AddressLine6, - address.AddressLine7, - address.AddressLine8); + return new StatementAttachmentSubType( + statement.WitnessName, + statement?.WitnessTitle, + statement?.WitnessShoulderNo, + statement.StatementNo, + statement.Date, + statement?.Witness); + } + + private static List MapOffences(ICollection offence) + { + if (offence is null) + { + return null; } - private static ApiClient.ApAction MapApAction(AddActionPlanRequest addActionPlanRequest) + return new List( + offence.Select(offence => + new Offence( + offence.Id, + offence.ListOrder, + offence.Code, + offence.Type, + offence.Active, + offence.Description, + offence.FromDate, + offence.ToDate, + offence.LatestPlea, + offence.LatestVerdict, + offence.DisposedReason, + offence.LastHearingOutcome, + offence?.CustodyTimeLimit?.ToString(), + offence.LatestPleaDescription))); + } + + private static List MapProposedCharges(ICollection proposedCharges) + { + if (proposedCharges is null) { - return new ApiClient.ApAction() - { - FullDefendantName = addActionPlanRequest.fullDefendantName, - AllDefendants = addActionPlanRequest.allDefendants, - Date = ConvertToDateTimeOffset(addActionPlanRequest.date), - DateExpected = ConvertToDateTimeOffset(addActionPlanRequest.dateExpected.Value), - DateTimeCreated = addActionPlanRequest.dateTimeCreated, - ActionPointText = addActionPlanRequest.actionPointText, - Status = addActionPlanRequest.status, - StatusDescription = addActionPlanRequest.statusDescription, - ExpectedDateUpdated = addActionPlanRequest.expectedDateUpdated, - PartyType = addActionPlanRequest.partyType, - PoliceChangeReason = addActionPlanRequest.policeChangeReason, - StatusUpdated = addActionPlanRequest.statusUpdated, - SyncedWithPolice = addActionPlanRequest.syncedWithPolice, - CpsChangeReason = addActionPlanRequest.cpsChangeReason, - ChaserTaskDate = ConvertToDateTimeOffset(addActionPlanRequest.chaserTaskDate), - Steps = MapActionStep(addActionPlanRequest.steps), - }; + return null; } - private static ICollection MapActionStep(Step[] steps) + return new List( + proposedCharges.Select(charge => + new ProposedCharge( + charge.Id, + charge.CaseId, + charge.DefendantId, + charge.Surname, + charge.FirstNames, + charge.Code, + charge.Description, + MapLocation(charge.Location), + charge.FromDate, + charge.ToDate, + charge.ChargeParticulars, + charge.AnticipatedPlea.ToString(), + charge.AdjudicationCode.ToString()))); + } + + private static PersonalDetail MapPersonalDetail(ApiClient.DefendantPersonalDetail defendantPersonalDetail) + { + if (defendantPersonalDetail is null) { - return steps.Select(step => new ApiClient.ActionPlanStep - { - Code = step.code, - Description = step.description, - Text = step.text, - Hidden = step.hidden, - HiddenDraft = step.hiddenDraft, - }).ToList(); + return null; } - private static ApiClient.CommunicationStatementType MapStatement(ReclassifyStatementRequest statement) + return new PersonalDetail( + MappAddress(defendantPersonalDetail.Address), + defendantPersonalDetail.Email, + defendantPersonalDetail.Ethnicity.ToString(), + defendantPersonalDetail.Gender.ToString(), + defendantPersonalDetail.Occupation, + defendantPersonalDetail.HomePhoneNumber, + defendantPersonalDetail.MobilePhoneNumber, + defendantPersonalDetail.WorkPhoneNumber, + defendantPersonalDetail.PreferredCorrespondenceLanguage.ToString(), + defendantPersonalDetail.Religion.ToString(), + defendantPersonalDetail.Guardian); + } + + private static Address MappAddress(ApiClient.PostalAddress address) + { + if (address is null) { - if (statement == null) - { - return default; - } + return default; + } - return new ApiClient.CommunicationStatementType - { - Witness = statement.Witness, - StatementNo = statement.StatementNo, - Date = ConvertToDateTime(statement.Date), - }; + return new Address( + address.Postcode, + address.AddressLine1, + address.AddressLine2, + address.AddressLine3, + address.AddressLine4, + address.AddressLine5, + address.AddressLine6, + address.AddressLine7, + address.AddressLine8); + } + + private static Location MapLocation(ApiClient.InternationalAddress address) + { + if (address is null) + { + return default; } - private static ApiClient.CommunicationExhibitType MapExhibit(ReclassifyExhibitRequest exhibit) + return new Location( + address.Country, + address.Postcode, + address.AddressLine1, + address.AddressLine2, + address.AddressLine3, + address.AddressLine4, + address.AddressLine5, + address.AddressLine6, + address.AddressLine7, + address.AddressLine8); + } + + private static ApiClient.ApAction MapApAction(AddActionPlanRequest addActionPlanRequest) + { + return new ApiClient.ApAction() { - if (exhibit == null) - { - return default; - } + FullDefendantName = addActionPlanRequest.fullDefendantName, + AllDefendants = addActionPlanRequest.allDefendants, + Date = ConvertToDateTimeOffset(addActionPlanRequest.date), + DateExpected = ConvertToDateTimeOffset(addActionPlanRequest.dateExpected.Value), + DateTimeCreated = addActionPlanRequest.dateTimeCreated, + ActionPointText = addActionPlanRequest.actionPointText, + Status = addActionPlanRequest.status, + StatusDescription = addActionPlanRequest.statusDescription, + ExpectedDateUpdated = addActionPlanRequest.expectedDateUpdated, + PartyType = addActionPlanRequest.partyType, + PoliceChangeReason = addActionPlanRequest.policeChangeReason, + StatusUpdated = addActionPlanRequest.statusUpdated, + SyncedWithPolice = addActionPlanRequest.syncedWithPolice, + CpsChangeReason = addActionPlanRequest.cpsChangeReason, + ChaserTaskDate = ConvertToDateTimeOffset(addActionPlanRequest.chaserTaskDate), + Steps = MapActionStep(addActionPlanRequest.steps), + }; + } - return new ApiClient.CommunicationExhibitType - { - Item = exhibit.Item, - Reference = exhibit.Reference, - Producer = exhibit.Producer, - NewProducer = exhibit.NewProducer, - ExistingProducerOrWitnessId = exhibit.ExistingProducerOrWitnessId, - }; + private static ICollection MapActionStep(Step[] steps) + { + return steps.Select(step => new ApiClient.ActionPlanStep + { + Code = step.code, + Description = step.description, + Text = step.text, + Hidden = step.hidden, + HiddenDraft = step.hiddenDraft, + }).ToList(); + } + + private static ApiClient.CommunicationStatementType MapStatement(ReclassifyStatementRequest statement) + { + if (statement == null) + { + return default; } - private static DateTimeOffset ConvertToDateTimeOffset(DateOnly? date, TimeOnly? time = null) + return new ApiClient.CommunicationStatementType { - if (date is null) - { - return default; - } + Witness = statement.Witness, + StatementNo = statement.StatementNo, + Date = ConvertToDateTime(statement.Date), + }; + } - TimeOnly actualTime = time ?? TimeOnly.MinValue; - DateTime dateTime = date.Value.ToDateTime(actualTime); - TimeSpan offset = TimeZoneInfo.Local.GetUtcOffset(dateTime); - return new DateTimeOffset(dateTime, offset); + private static ApiClient.CommunicationExhibitType MapExhibit(ReclassifyExhibitRequest exhibit) + { + if (exhibit == null) + { + return default; } - private static DateTime ConvertToDateTime(DateOnly? date, TimeOnly? time = null) + return new ApiClient.CommunicationExhibitType { - if (date is null) - { - return default; - } - - TimeOnly actualTime = time ?? TimeOnly.MinValue; - DateTime dateTime = date.Value.ToDateTime(actualTime); + Item = exhibit.Item, + Reference = exhibit.Reference, + Producer = exhibit.Producer, + NewProducer = exhibit.NewProducer, + ExistingProducerOrWitnessId = exhibit.ExistingProducerOrWitnessId, + }; + } - // Mark as local time - return DateTime.SpecifyKind(dateTime, DateTimeKind.Local); + private static DateTimeOffset ConvertToDateTimeOffset(DateOnly? date, TimeOnly? time = null) + { + if (date is null) + { + return default; } - /// - /// Handles an exception that occurred while calling the MDS API. - /// - /// The operation name. - /// The exception to handle. - /// The request with a correspondence ID. - /// The duration of the operation. - private void HandleException( - string operationName, - Exception exception, - BaseRequest request, - TimeSpan duration) + TimeOnly actualTime = time ?? TimeOnly.MinValue; + DateTime dateTime = date.Value.ToDateTime(actualTime); + TimeSpan offset = TimeZoneInfo.Local.GetUtcOffset(dateTime); + return new DateTimeOffset(dateTime, offset); + } + + private static DateTime ConvertToDateTime(DateOnly? date, TimeOnly? time = null) + { + if (date is null) { - Requires.NotNull(operationName); - Requires.NotNull(exception); + return default; + } + + TimeOnly actualTime = time ?? TimeOnly.MinValue; + DateTime dateTime = date.Value.ToDateTime(actualTime); + + // Mark as local time + return DateTime.SpecifyKind(dateTime, DateTimeKind.Local); + } + + /// + /// Handles an exception that occurred while calling the MDS API. + /// + /// The operation name. + /// The exception to handle. + /// The request with a correspondence ID. + /// The duration of the operation. + private void HandleException( + string operationName, + Exception exception, + BaseRequest request, + TimeSpan duration) + { + Requires.NotNull(operationName); + Requires.NotNull(exception); - const string LogMessage = DiagnosticsUtility.Error + @"Calling the MDS API failed for {Operation} after {Duration}. Path: {Path}, Correspondence ID: {CorrespondenceId}, Failure: {Reason} + const string LogMessage = DiagnosticsUtility.Error + @"Calling the MDS API failed for {Operation} after {Duration}. Path: {Path}, Correspondence ID: {CorrespondenceId}, Failure: {Reason} - Failure response: {FailureResponse}"; - this.logger.LogError( - exception, - $"{LogMessage}", - string.Empty, - operationName, - duration, - request?.CorrespondenceId, - exception.ToAggregatedMessage(), - string.Empty); - } - - /// - /// Logs an operation completed event. - /// - /// The operation name. - /// The request with a correspondence ID. - /// The duration of the operation. - /// Any additional information. - private void LogOperationCompletedEvent( - string operationName, - BaseRequest request, - TimeSpan duration, - string additionalInfo) - { - const string LogMessage = @"Calling the MDS API succeeded for {Operation} after {Duration}. Path: {Path}, Correspondence ID: {CorrespondenceId} - - Additional info: {AdditionalInfo}"; + this.logger.LogError( + exception, + $"{LogMessage}", + string.Empty, + operationName, + duration, + request?.CorrespondenceId, + exception.ToAggregatedMessage(), + string.Empty); + } - this.logger.LogInformation( - LogMessage, - operationName, - string.Empty, - duration, - request.CorrespondenceId, - additionalInfo); - } + /// + /// Logs an operation completed event. + /// + /// The operation name. + /// The request with a correspondence ID. + /// The duration of the operation. + /// Any additional information. + private void LogOperationCompletedEvent( + string operationName, + BaseRequest request, + TimeSpan duration, + string additionalInfo) + { + const string LogMessage = @"Calling the MDS API succeeded for {Operation} after {Duration}. Path: {Path}, Correspondence ID: {CorrespondenceId} + - Additional info: {AdditionalInfo}"; - /// - /// Builds a string containing information about the unused materials, based on the provided response. - /// The information includes the number of unused exhibits, mg forms, other materials, and statements. - /// - /// The response object containing the lists of unused materials. - /// A string that describes the received unused materials, including counts for each type. - private string BuildAdditionalInfo(UnusedMaterialsResponse results) - { - string additionalInfo = string.Empty; - bool addedInfo = false; + this.logger.LogInformation( + LogMessage, + operationName, + string.Empty, + duration, + request.CorrespondenceId, + additionalInfo); + } - if (results.Exhibits?.Count > 0) - { - additionalInfo += $"received #{results.Exhibits.Count} unused exhibits"; - addedInfo = true; - } + /// + /// Builds a string containing information about the unused materials, based on the provided response. + /// The information includes the number of unused exhibits, mg forms, other materials, and statements. + /// + /// The response object containing the lists of unused materials. + /// A string that describes the received unused materials, including counts for each type. + private string BuildAdditionalInfo(UnusedMaterialsResponse results) + { + string additionalInfo = string.Empty; + bool addedInfo = false; - if (results.MgForms?.Count > 0) - { - additionalInfo += (addedInfo ? "," : "") + $" received #{results.MgForms.Count} unused mg forms"; - addedInfo = true; - } + if (results.Exhibits?.Count > 0) + { + additionalInfo += $"received #{results.Exhibits.Count} unused exhibits"; + addedInfo = true; + } - if (results.OtherMaterials?.Count > 0) - { - additionalInfo += (addedInfo ? "," : "") + $" received #{results.OtherMaterials.Count} unused other materials"; - addedInfo = true; - } + if (results.MgForms?.Count > 0) + { + additionalInfo += (addedInfo ? "," : string.Empty) + $" received #{results.MgForms.Count} unused mg forms"; + addedInfo = true; + } - if (results.Statements?.Count > 0) - { - additionalInfo += (addedInfo ? "," : "") + $" received #{results.Statements.Count} unused statements"; - } + if (results.OtherMaterials?.Count > 0) + { + additionalInfo += (addedInfo ? "," : string.Empty) + $" received #{results.OtherMaterials.Count} unused other materials"; + addedInfo = true; + } - if (!addedInfo) - { - additionalInfo = "received #0 unused materials"; - } + if (results.Statements?.Count > 0) + { + additionalInfo += (addedInfo ? "," : string.Empty) + $" received #{results.Statements.Count} unused statements"; + } - return additionalInfo; + if (!addedInfo) + { + additionalInfo = "received #0 unused materials"; } + + return additionalInfo; } -} \ No newline at end of file +} diff --git a/DdeiClient/Model/MasterDataServiceCookie.cs b/DdeiClient/Model/MasterDataServiceCookie.cs deleted file mode 100644 index 712e92260..000000000 --- a/DdeiClient/Model/MasterDataServiceCookie.cs +++ /dev/null @@ -1,43 +0,0 @@ -// -// Copyright (c) The Crown Prosecution Service. All rights reserved. -// - -namespace DdeiClient.Model -{ - using System; - using System.Globalization; - - /// - /// Mds cookie. - /// - public class MasterDataServiceCookie - { - /// - /// Initializes a new instance of the class. - /// - /// Auth cookie. - /// CMS auth token. - public MasterDataServiceCookie(string cookies, string token) - { - this.Cookies = cookies; - this.Token = token; - this.ExpiryTime = DateTime.UtcNow.AddHours(1).ToString("o", CultureInfo.InvariantCulture); - } - - /// - /// Gets CMS cookie. - /// - public string Cookies { get; init; } = string.Empty; - - /// - /// Gets CMS token. - /// - public string Token { get; init; } = string.Empty; - - /// - /// Gets token expiry. - /// - public string ExpiryTime { get; init; } = string.Empty; - } - -} diff --git a/hkui-functions-integration-tests/TestBase.cs b/hkui-functions-integration-tests/TestBase.cs index 71db76cba..651470911 100644 --- a/hkui-functions-integration-tests/TestBase.cs +++ b/hkui-functions-integration-tests/TestBase.cs @@ -415,7 +415,7 @@ protected internal async Task ResetAllCommunications() AuthenticationContext authContext = await this.AuthenticateAsync(authenticationRequest).ConfigureAwait(true); - CmsAuthValues cmsAuthValues = new CmsAuthValues(authContext.Cookies, authContext.Token); + CmsAuthValues cmsAuthValues = new CmsAuthValues(authContext.ToString()); var request = new ListCommunicationsHkRequest(caseId, Guid.NewGuid()); diff --git a/polaris-devops-pipelines/deployments_v2/polaris-triggered-build-qa.yml b/polaris-devops-pipelines/deployments_v2/polaris-triggered-build-qa.yml new file mode 100644 index 000000000..c8558a8bd --- /dev/null +++ b/polaris-devops-pipelines/deployments_v2/polaris-triggered-build-qa.yml @@ -0,0 +1,34 @@ +--- +name: '$(majorMinorVersion).$(Year:yy)$(DayOfYear).$(semanticVersion)-ci' + +trigger: + batch: true + branches: + include: + - main + paths: + include: + - polaris-terraform/main-terraform/* + - polaris-gateway/* + - polaris-maintenance/* + - polaris-pipeline/* + - polaris-ui/* + - polaris-e2e/* + +pr: none + +variables: + - name: buildConfiguration + value: "Release" + - name: majorMinorVersion + value: "1.0" + - name: semanticVersion + value: "$[counter(variables['majorMinorVersion'], 1)]" + +pool: + name: $(build-agent) + +stages: + - template: stages/stage_publish-all-artifacts.yml + parameters: + environment: $(environment) \ No newline at end of file diff --git a/polaris-gateway.tests/Functions/HouseKeeping/CaseDefendantsServiceTests.cs b/polaris-gateway.tests/Functions/HouseKeeping/CaseDefendantsServiceTests.cs index 3eaf76d5a..d7ea33f99 100644 --- a/polaris-gateway.tests/Functions/HouseKeeping/CaseDefendantsServiceTests.cs +++ b/polaris-gateway.tests/Functions/HouseKeeping/CaseDefendantsServiceTests.cs @@ -49,7 +49,7 @@ public async Task GetCaseDefendantsAsync_ReturnsCaseDefendants_WhenApiCallIsSucc { // Arrange int caseId = 123; - var cmsAuthValues = new CmsAuthValues("validCmsToken", "validCmsCookies"); + var cmsAuthValues = new CmsAuthValues("validCmsToken"); // Setup the expected DefendantsResponse result var expectedCaseDefendants = new DefendantsResponse @@ -182,7 +182,7 @@ public async Task GetCaseDefendantsAsync_ThrowsInvalidOperationException_WhenCas { // Arrange int caseId = 123; - var cmsAuthValues = new CmsAuthValues("validCmsToken", "validCmsCookies"); + var cmsAuthValues = new CmsAuthValues("validCmsToken"); // Setup the API client to return null for the case defendants this.apiClientMock @@ -213,7 +213,7 @@ public async Task GetCaseDefendantsAsync_ThrowsException_WhenApiCallFails() { // Arrange int caseId = 123; - var cmsAuthValues = new CmsAuthValues("validCmsToken", "validCmsCookies"); + var cmsAuthValues = new CmsAuthValues("validCmsToken"); // Setup the API client to throw an exception this.apiClientMock diff --git a/polaris-gateway.tests/Functions/HouseKeeping/CompleteReclassificationTests.cs b/polaris-gateway.tests/Functions/HouseKeeping/CompleteReclassificationTests.cs index a91b1c802..d8f6ebcdd 100644 --- a/polaris-gateway.tests/Functions/HouseKeeping/CompleteReclassificationTests.cs +++ b/polaris-gateway.tests/Functions/HouseKeeping/CompleteReclassificationTests.cs @@ -61,7 +61,7 @@ public async Task Run_ReturnsOkResultWithOperationsResultobject_WhenAllOperation int caseId = 232; int materialId = 123; int newWitnessId = 765; - var cmsAuthValues = new CmsAuthValues("valid cookies", "valid token", Guid.NewGuid()); + var cmsAuthValues = new CmsAuthValues("valid cookies", Guid.NewGuid()); var transactionId = Guid.NewGuid(); var reclassifyCaseMaterialRequest = CreateMockReclassifyToOtherRequest(); @@ -132,7 +132,7 @@ public async Task Run_ReturnsMultStatusResultWithOperationsResultobject_WhenSome int caseId = 232; int materialId = 123; int newWitnessId = 765; - var cmsAuthValues = new CmsAuthValues("valid cookies", "valid token", Guid.NewGuid()); + var cmsAuthValues = new CmsAuthValues("valid cookies", Guid.NewGuid()); var transactionId = Guid.NewGuid(); var reclassifyCaseMaterialRequest = CreateMockReclassifyToOtherRequest(); @@ -205,7 +205,7 @@ public async Task Run_ReturnsUnprocessableEntityWithOperationsObjectResult_WhenA int caseId = 232; int materialId = 123; int newWitnessId = 765; - var cmsAuthValues = new CmsAuthValues("valid cookies", "valid token", Guid.NewGuid()); + var cmsAuthValues = new CmsAuthValues("valid cookies", Guid.NewGuid()); var transactionId = Guid.NewGuid(); var reclassifyCaseMaterialRequest = CreateMockReclassifyToOtherRequest(); @@ -278,7 +278,7 @@ public async Task ReturnsUnprocessableEntityError_WhenInvalidOperationExceptionI int caseId = 232; int materialId = 123; int newWitnessId = 765; - var cmsAuthValues = new CmsAuthValues("valid cookies", "valid token", Guid.NewGuid()); + var cmsAuthValues = new CmsAuthValues("valid cookies", Guid.NewGuid()); var transactionId = Guid.NewGuid(); var reclassifyCaseMaterialRequest = CreateMockReclassifyToOtherRequest(); @@ -345,7 +345,7 @@ public async Task Run_ReturnsUnauthorizedError_WhenUnauthorizedAccessExceptionIs int caseId = 232; int materialId = 123; int newWitnessId = 765; - var cmsAuthValues = new CmsAuthValues("valid cookies", "valid token", Guid.NewGuid()); + var cmsAuthValues = new CmsAuthValues("valid cookies", Guid.NewGuid()); var transactionId = Guid.NewGuid(); var reclassifyCaseMaterialRequest = CreateMockReclassifyToOtherRequest(); diff --git a/polaris-gateway.tests/Functions/HouseKeeping/DiscardMaterialTests.cs b/polaris-gateway.tests/Functions/HouseKeeping/DiscardMaterialTests.cs index cf2664324..9aaa6674e 100644 --- a/polaris-gateway.tests/Functions/HouseKeeping/DiscardMaterialTests.cs +++ b/polaris-gateway.tests/Functions/HouseKeeping/DiscardMaterialTests.cs @@ -4,23 +4,23 @@ namespace PolarisGateway.Tests.Functions.HouseKeeping; -using System.Threading.Tasks; +using Common.Constants; +using Common.Dto.Request; +using Common.Dto.Request.HouseKeeping; +using Common.Dto.Response.HouseKeeping; using Cps.Fct.Hk.Ui.Interfaces; +using Cps.Fct.Hk.Ui.Services.Tests.TestUtilities; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; -using Moq; -using Xunit; -using Cps.Fct.Hk.Ui.Services.Tests.TestUtilities; using Microsoft.Extensions.Logging; -using System.Text.Json; -using System.Text; +using Moq; using PolarisGateway.Functions.HouseKeeping; -using Common.Dto.Request.HouseKeeping; using System; using System.IO; -using Common.Dto.Response.HouseKeeping; -using Common.Dto.Request; -using Common.Constants; +using System.Text; +using System.Text.Json; +using System.Threading.Tasks; +using Xunit; /// /// Unit tests for the function. @@ -38,8 +38,8 @@ public class DiscardMaterialTests public DiscardMaterialTests() { this.mockLogger = new TestLogger(); - this.mockCommunicationService = new Mock(); - + this.mockCommunicationService = new Mock(); + this.discardMaterial = new DiscardMaterial( this.mockLogger, this.mockCommunicationService.Object); @@ -163,8 +163,8 @@ public async Task Run_ReturnsUnprocessableEntityError_WhenInvalidOperationExcept // Assert ObjectResult objectResult = Assert.IsType(result); Assert.Equal(StatusCodes.Status422UnprocessableEntity, objectResult.StatusCode); - Assert.Equal("Material with Id [456] has not been found to discard.", objectResult.Value.ToString()); - + Assert.Equal("Material with Id [456] has not been found to discard.", objectResult.Value.ToString()); + Assert.Contains(this.mockLogger.Logs, log => log.LogLevel == LogLevel.Information && log.Message != null && log.Message.Contains($"{LoggingConstants.HskUiLogPrefix} DiscardMaterial function processed a request.")); diff --git a/polaris-gateway/Functions/BaseFunction.cs b/polaris-gateway/Functions/BaseFunction.cs index d363f712d..a00a37808 100644 --- a/polaris-gateway/Functions/BaseFunction.cs +++ b/polaris-gateway/Functions/BaseFunction.cs @@ -2,16 +2,15 @@ // Copyright (c) The Crown Prosecution Service. All rights reserved. // -using System; -using System.Web; +namespace PolarisGateway.Functions; + using Common.Constants; using Common.Dto.Request; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Logging; +using System; -namespace PolarisGateway.Functions; - -public class BaseFunction(ILogger? logger = null) +public class BaseFunction(ILogger logger = null) { private readonly ILogger logger = logger; @@ -25,59 +24,18 @@ protected static string EstablishCmsAuthValues(HttpRequest req) { req.Cookies.TryGetValue(HttpHeaderKeys.CmsAuthValues, out var cmsAuthValues); return cmsAuthValues; - } - - protected string GetCmsToken(HttpRequest req) - { - return this.GetCookiePartByIndex(req, 0); - } - - protected string GetCmsCookie(HttpRequest req, bool urlEncode = false) - { - string cookie = this.GetCookiePartByIndex(req, 4); - - if (urlEncode) - { - return HttpUtility.UrlEncode(cookie); - } - - return cookie; } protected CmsAuthValues BuildCmsAuthValues(HttpRequest req) { - var token = this.GetCmsToken(req) ?? string.Empty; - var cookie = this.GetCmsCookie(req) ?? string.Empty; - var correlation = EstablishCorrelation(req); - - return new CmsAuthValues(cookie, token, correlation); - } - - private string? GetCookiePartByIndex(HttpRequest req, int index) - { - if (req.Cookies == null) + if (req?.Cookies is null) { - return string.Empty; + return null; } - if (req.Cookies.TryGetValue(HttpHeaderKeys.CmsAuthValues, out string? cmsCookie)) - { - string[] cmsParts = cmsCookie.Split(','); + var cmsAuthValues = EstablishCmsAuthValues(req); + var correlation = EstablishCorrelation(req); - if (cmsParts.Length > index) - { - return cmsParts[index].Split(':')[1].Replace("\"", string.Empty); - } - else - { - this.logger.LogWarning($"CMS cookie does not contain enough parts. Requested index: {index}."); - return null; - } - } - else - { - this.logger.LogWarning($"CMS cookie not found in the request."); - return null; - } + return new CmsAuthValues(cmsAuthValues, correlation); } -} \ No newline at end of file +} diff --git a/polaris-pipeline/Common/Dto/Request/CmsAuthValues.cs b/polaris-pipeline/Common/Dto/Request/CmsAuthValues.cs index aab1fba0a..c06b7da82 100644 --- a/polaris-pipeline/Common/Dto/Request/CmsAuthValues.cs +++ b/polaris-pipeline/Common/Dto/Request/CmsAuthValues.cs @@ -12,23 +12,17 @@ namespace Common.Dto.Request; /// /// Initializes a new instance of the class. /// -/// The CMS cookies, which may be null. -/// The CMS modern API token, which may be null. +/// The CMS authentication string value /// The correlation ID to track requests. -public class CmsAuthValues(string cmsCookies, string cmsModernToken, Guid correlationId = default) +public class CmsAuthValues(string cmsAuthFullValue, Guid correlationId = default) { /// - /// Gets or sets the CMS cookies. - /// - public string CmsCookies { get; set; } = cmsCookies; - - /// - /// Gets or sets the CMS modern API token. + /// Gets or sets the correlation ID used to track requests. /// - public string CmsModernToken { get; set; } = cmsModernToken; + public Guid CorrelationId { get; set; } = correlationId; /// - /// Gets or sets the correlation ID used to track requests. + /// Gets or sets the full CMS authentication value. /// - public Guid CorrelationId { get; set; } = correlationId; + public string CmsAuthFullValue { get; set; } = cmsAuthFullValue; } diff --git a/polaris-ui/src/app/auth/msal/useUserGroupsFeatureFlag.ts b/polaris-ui/src/app/auth/msal/useUserGroupsFeatureFlag.ts index 0c02adc64..85116827e 100644 --- a/polaris-ui/src/app/auth/msal/useUserGroupsFeatureFlag.ts +++ b/polaris-ui/src/app/auth/msal/useUserGroupsFeatureFlag.ts @@ -12,11 +12,7 @@ import { FEATURE_FLAG_STATE_RETENTION, FEATURE_FLAG_GLOBAL_NAV, PRIVATE_BETA_FEATURE_USER_GROUP, - FEATURE_FLAG_EXTERNAL_REDIRECT_CASE_REVIEW_APP, - FEATURE_FLAG_EXTERNAL_REDIRECT_BULK_UM_APP, PRIVATE_BETA_FEATURE_USER_GROUP2, - PRIVATE_BETA_FEATURE_USER_GROUP3, - PRIVATE_BETA_FEATURE_USER_GROUP4, PRIVATE_BETA_FEATURE_USER_GROUP5, PRIVATE_BETA_FEATURE_USER_GROUP6, FEATURE_FLAG_BACKGROUND_PIPELINE_REFRESH, @@ -82,8 +78,6 @@ export const useUserGroupsFeatureFlag = (): FeatureFlagData => { searchPII, renameDocument, reclassify, - externalRedirectCaseReviewApp, - externalRedirectBulkUmApp, pageDelete, pageRotate, notifications, @@ -125,18 +119,6 @@ export const useUserGroupsFeatureFlag = (): FeatureFlagData => { userDetails?.username, renameDocument ), - externalRedirectCaseReviewApp: shouldShowFeature( - FEATURE_FLAG_EXTERNAL_REDIRECT_CASE_REVIEW_APP, - userDetails?.username, - externalRedirectCaseReviewApp, - { groups: groupClaims, groupKey: PRIVATE_BETA_FEATURE_USER_GROUP3 } - ), - externalRedirectBulkUmApp: shouldShowFeature( - FEATURE_FLAG_EXTERNAL_REDIRECT_BULK_UM_APP, - userDetails?.username, - externalRedirectBulkUmApp, - { groups: groupClaims, groupKey: PRIVATE_BETA_FEATURE_USER_GROUP4 } - ), reclassify: shouldShowFeature( FEATURE_FLAG_RECLASSIFY, userDetails?.username, diff --git a/polaris-ui/src/app/features/cases/domain/CombinedState.ts b/polaris-ui/src/app/features/cases/domain/CombinedState.ts index ae6fc717f..329221db1 100644 --- a/polaris-ui/src/app/features/cases/domain/CombinedState.ts +++ b/polaris-ui/src/app/features/cases/domain/CombinedState.ts @@ -178,8 +178,6 @@ export const initialState = { searchPII: false, renameDocument: false, reclassify: false, - externalRedirectCaseReviewApp: false, - externalRedirectBulkUmApp: false, pageDelete: false, pageRotate: false, notifications: false, diff --git a/polaris-ui/src/app/features/cases/domain/FeatureFlagData.ts b/polaris-ui/src/app/features/cases/domain/FeatureFlagData.ts index 4147721ba..2d8c2e22d 100644 --- a/polaris-ui/src/app/features/cases/domain/FeatureFlagData.ts +++ b/polaris-ui/src/app/features/cases/domain/FeatureFlagData.ts @@ -11,8 +11,6 @@ export type FeatureFlagData = { searchPII: boolean; renameDocument: boolean; reclassify: boolean; - externalRedirectCaseReviewApp: boolean; - externalRedirectBulkUmApp: boolean; pageDelete: boolean; pageRotate: boolean; notifications: boolean; @@ -30,8 +28,6 @@ export type FeatureFlagQueryParams = { searchPII: string; renameDocument: string; reclassify: string; - externalRedirectCaseReviewApp: string; - externalRedirectBulkUmApp: string; pageDelete: string; pageRotate: string; notifications: string; diff --git a/polaris-ui/src/app/features/cases/presentation/case-details/index.tsx b/polaris-ui/src/app/features/cases/presentation/case-details/index.tsx index 09525ba78..80d534151 100644 --- a/polaris-ui/src/app/features/cases/presentation/case-details/index.tsx +++ b/polaris-ui/src/app/features/cases/presentation/case-details/index.tsx @@ -680,35 +680,31 @@ export const Page: React.FC = ({ backLinkProps, context }) => { )} {
- {featureFlags.externalRedirectCaseReviewApp && ( - - )} - - {featureFlags.externalRedirectBulkUmApp && ( - - )} + + +
} From dfa10c5794582fca9f92c771745a154679490e88 Mon Sep 17 00:00:00 2001 From: TahmeedAhmed-NTT-CPS Date: Fri, 3 Jul 2026 14:30:28 +0000 Subject: [PATCH 12/19] Feature/fct2 18624 warning message large file size (#2075) * add response header flag for large files * refactor header name * refactor caching to store file size * removed unused code * fixed indentation * refactored code * use terraform to retreive filesize * unit tests fixed * terraform update * moved header to HttpHeaderKeys --- .../Services/Artefact/CacheServiceTests.cs | 4 +- .../Artefact/PdfArtefactServiceTests.cs | 154 +++++++++++++++++- .../ApplicationStartup/ServiceExtensions.cs | 51 +++--- polaris-gateway/Functions/GetPdf.cs | 7 + .../Models/RedactionFileSizeOptions.cs | 13 ++ .../Services/Artefact/CacheService.cs | 24 ++- .../Artefact/Domain/ArtefactResult.cs | 4 +- .../ArtefactServiceResponseFactory.cs | 11 ++ .../IArtefactServiceResponseFactory.cs | 2 + .../Services/Artefact/ICacheService.cs | 4 +- .../Services/Artefact/IPdfArtefactService.cs | 3 +- .../Services/Artefact/PdfArtefactService.cs | 65 +++++--- .../Common/Constants/HttpHeaderKeys.cs | 1 + .../BlobStorage/BlobStorageService.cs | 11 ++ .../BlobStorage/IBlobStorageService.cs | 1 + .../BlobStorage/IPolarisBlobStorageService.cs | 8 +- .../BlobStorage/PolarisBlobStorageService.cs | 31 +++- polaris-terraform/main-terraform/dev.tfvars | 2 + .../main-terraform/function-gateway.tf | 1 + polaris-terraform/main-terraform/prod.tfvars | 2 + polaris-terraform/main-terraform/qa.tfvars | 2 + polaris-terraform/main-terraform/uat.tfvars | 4 +- polaris-terraform/main-terraform/variables.tf | 4 + 23 files changed, 345 insertions(+), 64 deletions(-) create mode 100644 polaris-gateway/Models/RedactionFileSizeOptions.cs diff --git a/polaris-gateway.tests/Services/Artefact/CacheServiceTests.cs b/polaris-gateway.tests/Services/Artefact/CacheServiceTests.cs index b68f4a977..14cfbd734 100644 --- a/polaris-gateway.tests/Services/Artefact/CacheServiceTests.cs +++ b/polaris-gateway.tests/Services/Artefact/CacheServiceTests.cs @@ -104,11 +104,11 @@ public async Task UploadPdfAsync_WhenUploadingPdf_WillUploadPdf() var pdfStream = new MemoryStream(_fixture.Create()); // Act - await _cacheService.UploadPdfAsync(_caseId, _documentId, _versionId, _isOcrProcessed, pdfStream); + await _cacheService.UploadPdfAsync(_caseId, _documentId, _versionId, _isOcrProcessed, pdfStream, It.IsAny()); // Assert _polarisBlobStorageServiceMock - .Verify(x => x.UploadBlobAsync(pdfStream, _blobIdType, _isOcrProcessed), Times.Once); + .Verify(x => x.UploadBlobAsync(pdfStream, _blobIdType, _isOcrProcessed, It.IsAny()), Times.Once); } [Fact] diff --git a/polaris-gateway.tests/Services/Artefact/PdfArtefactServiceTests.cs b/polaris-gateway.tests/Services/Artefact/PdfArtefactServiceTests.cs index e6ca4a095..34ad41d7b 100644 --- a/polaris-gateway.tests/Services/Artefact/PdfArtefactServiceTests.cs +++ b/polaris-gateway.tests/Services/Artefact/PdfArtefactServiceTests.cs @@ -2,14 +2,19 @@ using AutoFixture; using Common.Constants; using Common.Domain.Ocr; -using Common.Services.OcrService; using Common.Services.BlobStorage; +using Common.Services.OcrService; using FluentAssertions; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Logging; using Moq; +using Microsoft.Extensions.Options; +using PolarisGateway.Models; using PolarisGateway.Services.Artefact; using PolarisGateway.Services.Artefact.Domain; using PolarisGateway.Services.Artefact.Factories; using System; +using System.Collections.Generic; using System.IO; using System.Threading.Tasks; using Xunit; @@ -47,6 +52,8 @@ public PdfArtefactServiceTests() _ocrServiceMock = new Mock(); _pdfArtefactService = new PdfArtefactService( + Options.Create(new RedactionFileSizeOptions { FileSizeLimitMb = 10 }), + new Mock>().Object, _cacheServiceMock.Object, _artefactServiceResponseFactoryMock.Object, _pdfRetrievalServiceMock.Object, @@ -114,7 +121,7 @@ public async Task GetPdfAsync_WhenAPdfIsNotAlreadyInCacheAndConversionSucceeds_W .ReturnsAsync((true, pdfStream)); _cacheServiceMock - .Setup(x => x.UploadPdfAsync(_caseId, _documentId, _versionId, false, It.IsAny())) + .Setup(x => x.UploadPdfAsync(_caseId, _documentId, _versionId, false, It.IsAny(), It.IsAny())) .Returns(Task.CompletedTask); var fakeOcrOperationId = Guid.NewGuid(); @@ -152,6 +159,145 @@ public async Task GetPdfAsync_WhenAPdfIsNotAlreadyInCacheAndConversionSucceeds_W // Assert result.Should().Be(expectedResult); - _cacheServiceMock.Verify(x => x.UploadPdfAsync(_caseId, _documentId, _versionId, false, It.IsAny()), Times.Once); + _cacheServiceMock.Verify(x => x.UploadPdfAsync(_caseId, _documentId, _versionId, false, It.IsAny(), It.IsAny()), Times.Once); + } + + [Fact] + public async Task GetPdfAsync_WhenCachedPdfExceedsSizeLimit_ShouldReturnLargeFileFlag() + { + // Arrange + var largeStream = new MemoryStream(new byte[20 * 1024 * 1024]); // 20 MB + + _cacheServiceMock + .Setup(x => x.TryGetPdfAsync(_caseId, _documentId, _versionId, false)) + .ReturnsAsync((true, (Stream)largeStream)); + + _cacheServiceMock + .Setup(x => x.GetPdfSizeFromMetadataAsync(_caseId, _documentId, _versionId, false)) + .ReturnsAsync(20); // MB (above limit of 10) + + var expectedResult = new ArtefactResult(); + + _artefactServiceResponseFactoryMock + .Setup(x => x.CreateOkResultWithLargeFileFlag(It.IsAny(), true, true)) + .Returns(expectedResult); + + // Act + var result = await _pdfArtefactService.GetPdfAsync( + _cmsAuthValues, + _correlationId, + _urn, + _caseId, + _documentId, + _versionId, + false); + + // Assert + result.Should().Be(expectedResult); + + _artefactServiceResponseFactoryMock.Verify( + x => x.CreateOkResultWithLargeFileFlag(It.IsAny(), true, true), + Times.Once); + } + + [Fact] + public async Task GetPdfAsync_WhenCachedPdfWithinLimit_ShouldReturnNormalResult() + { + // Arrange + var smallStream = new MemoryStream(new byte[1 * 1024 * 1024]); // 1 MB + + _cacheServiceMock + .Setup(x => x.TryGetPdfAsync(_caseId, _documentId, _versionId, false)) + .ReturnsAsync((true, (Stream)smallStream)); + + _cacheServiceMock + .Setup(x => x.GetPdfSizeFromMetadataAsync(_caseId, _documentId, _versionId, false)) + .ReturnsAsync(1); // below limit + + var expectedResult = new ArtefactResult(); + + _artefactServiceResponseFactoryMock + .Setup(x => x.CreateOkfResult(It.IsAny(), true)) + .Returns(expectedResult); + + // Act + var result = await _pdfArtefactService.GetPdfAsync( + _cmsAuthValues, + _correlationId, + _urn, + _caseId, + _documentId, + _versionId, + false); + + // Assert + result.Should().Be(expectedResult); + } + + [Fact] + public async Task GetPdfAsync_WhenNewPdfExceedsSizeLimit_ShouldReturnLargeFileFlag() + { + // Arrange + var largeBytes = new byte[20 * 1024 * 1024]; + var stream = new MemoryStream(largeBytes); + + _cacheServiceMock + .SetupSequence(x => x.TryGetPdfAsync(_caseId, _documentId, _versionId, false)) + .ReturnsAsync((false, null)) + .ReturnsAsync((true, (Stream)stream)); + + _pdfRetrievalServiceMock + .Setup(x => x.GetPdfStreamAsync( + _cmsAuthValues, _correlationId, _urn, + _caseId, _documentId, _versionId)) + .ReturnsAsync(new DocumentRetrievalResult + { + Status = PdfConversionStatus.DocumentConverted, + PdfStream = new MemoryStream(largeBytes) + }); + + _cacheServiceMock + .Setup(x => x.UploadPdfAsync( + _caseId, _documentId, _versionId, + false, It.IsAny(), It.IsAny())) + .Returns(Task.CompletedTask); + + var fakeOcrOperationId = Guid.NewGuid(); + + _ocrServiceMock + .Setup(x => x.InitiateOperationAsync(It.IsAny(), It.IsAny())) + .ReturnsAsync(fakeOcrOperationId); + + _ocrServiceMock + .Setup(x => x.GetOperationResultsAsync(fakeOcrOperationId, It.IsAny())) + .ReturnsAsync(new OcrOperationResult + { + IsSuccess = true, + AnalyzeResults = new AnalyzeResults() + }); + + _cacheServiceMock + .Setup(x => x.UploadJsonObjectAsync( + _caseId, _documentId, _versionId, + BlobType.Ocr, It.IsAny())) + .Returns(Task.CompletedTask); + + var expectedResult = new ArtefactResult(); + + _artefactServiceResponseFactoryMock + .Setup(x => x.CreateOkResultWithLargeFileFlag(It.IsAny(), false, true)) + .Returns(expectedResult); + + // Act + var result = await _pdfArtefactService.GetPdfAsync( + _cmsAuthValues, _correlationId, _urn, + _caseId, _documentId, _versionId, false); + + // Assert + result.Should().Be(expectedResult); + + _artefactServiceResponseFactoryMock.Verify( + x => x.CreateOkResultWithLargeFileFlag(It.IsAny(), false, true), + Times.Once); } -} \ No newline at end of file +} diff --git a/polaris-gateway/ApplicationStartup/ServiceExtensions.cs b/polaris-gateway/ApplicationStartup/ServiceExtensions.cs index 1fbd7bf89..efe64b566 100644 --- a/polaris-gateway/ApplicationStartup/ServiceExtensions.cs +++ b/polaris-gateway/ApplicationStartup/ServiceExtensions.cs @@ -1,37 +1,38 @@ -using System.Net; -using System.Net.Http.Headers; +using Common.Clients.PdfGenerator; +using Common.Factories.ComputerVisionClientFactory; +using Common.Mappers; +using Common.Services.BlobStorage; +using Common.Services.DocumentToggle; +using Common.Services.OcrService; +using Common.Services.PiiService; +using Common.Telemetry; +using Common.Wrappers; +using Cps.Fct.Hk.Ui.Interfaces; +using Cps.Fct.Hk.Ui.ServiceClient.Uma; +using Cps.Fct.Hk.Ui.ServiceClient.Uma.Configuration; +using Cps.Fct.Hk.Ui.Services; +using Cps.Fct.Hk.Ui.Services.Validators; +using Ddei.Extensions; +using DdeiClient.Clients; +using DdeiClient.Clients.Interfaces; +using DdeiClient.Configuration; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.IdentityModel.Protocols; using Microsoft.IdentityModel.Protocols.OpenIdConnect; -using Common.Telemetry; -using Common.Wrappers; using PolarisGateway.Clients.Coordinator; +using PolarisGateway.Clients.PdfThumbnailGenerator; using PolarisGateway.Mappers; +using PolarisGateway.Models; +using PolarisGateway.Services.Artefact; +using PolarisGateway.Services.MdsOrchestration; using PolarisGateway.Validators; using Polly; using Polly.Contrib.WaitAndRetry; -using Ddei.Extensions; -using Common.Services.DocumentToggle; -using Common.Services.OcrService; -using Common.Factories.ComputerVisionClientFactory; -using Common.Clients.PdfGenerator; -using Common.Services.BlobStorage; -using Common.Services.PiiService; -using PolarisGateway.Clients.PdfThumbnailGenerator; -using PolarisGateway.Services.Artefact; -using PolarisGateway.Services.MdsOrchestration; -using System.Net.Http; using System; -using Cps.Fct.Hk.Ui.Interfaces; -using Cps.Fct.Hk.Ui.Services; -using DdeiClient.Clients.Interfaces; -using DdeiClient.Clients; -using DdeiClient.Configuration; -using Common.Mappers; -using Cps.Fct.Hk.Ui.Services.Validators; -using Cps.Fct.Hk.Ui.ServiceClient.Uma; -using Cps.Fct.Hk.Ui.ServiceClient.Uma.Configuration; +using System.Net; +using System.Net.Http; +using System.Net.Http.Headers; namespace PolarisGateway.ApplicationStartup; @@ -77,6 +78,8 @@ public static IServiceCollection ConfigureServices(this IServiceCollection servi services.AddPiiService(); services.AddArtefactService(); services.AddMdsOrchestrationService(); + services.Configure(configuration.GetSection(RedactionFileSizeOptions.ConfigKey)); + // House keeping. services.AddSingleton(); diff --git a/polaris-gateway/Functions/GetPdf.cs b/polaris-gateway/Functions/GetPdf.cs index 8661f009c..b42e1e01c 100644 --- a/polaris-gateway/Functions/GetPdf.cs +++ b/polaris-gateway/Functions/GetPdf.cs @@ -1,5 +1,6 @@ using Common.Configuration; using Common.Extensions; +using Common.Constants; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.Azure.Functions.Worker; @@ -54,6 +55,12 @@ public async Task Run( var isOcrProcessed = req.Query.ContainsKey(isOcrProcessedParamName) && bool.Parse(req.Query[isOcrProcessedParamName]); var forceRefresh = req.Query.ContainsKey(ForceRefreshParamName) && bool.Parse(req.Query[ForceRefreshParamName]); var getPdfResult = await _pdfArtefactService.GetPdfAsync(cmsAuthValues, correlationId, caseUrn, caseId, materialId, documentId, isOcrProcessed, forceRefresh); + + if (getPdfResult.FileSizeExceedsLimit == true) + { + req.HttpContext.Response.Headers[HttpHeaderKeys.CpsFileTooLarge] = "true"; + } + return getPdfResult.Status == ResultStatus.ArtefactAvailable ? new FileStreamResult(getPdfResult.Artefact, PdfContentType) : new JsonResult(getPdfResult) diff --git a/polaris-gateway/Models/RedactionFileSizeOptions.cs b/polaris-gateway/Models/RedactionFileSizeOptions.cs new file mode 100644 index 000000000..132041863 --- /dev/null +++ b/polaris-gateway/Models/RedactionFileSizeOptions.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace PolarisGateway.Models +{ + public class RedactionFileSizeOptions + { + public const string ConfigKey = "RedactionFileSize"; + + public double FileSizeLimitMb { get; set; } + } +} diff --git a/polaris-gateway/Services/Artefact/CacheService.cs b/polaris-gateway/Services/Artefact/CacheService.cs index 905869e85..fa2a0e3f2 100644 --- a/polaris-gateway/Services/Artefact/CacheService.cs +++ b/polaris-gateway/Services/Artefact/CacheService.cs @@ -29,10 +29,10 @@ public CacheService( return (result != null, result); } - public async Task UploadPdfAsync(int caseId, string materialId, long documentId, bool isOcrProcessed, Stream stream) + public async Task UploadPdfAsync(int caseId, string materialId, long documentId, bool isOcrProcessed, Stream stream, double fileSizeInMb) { var blobId = _blobTypeIdFactory.CreateBlobId(caseId, materialId, documentId, BlobType.Pdf); - await _polarisBlobStorageService.UploadBlobAsync(stream, blobId, isOcrProcessed); + await _polarisBlobStorageService.UploadBlobAsync(stream, blobId, isOcrProcessed, fileSizeInMb); } public async Task<(bool, T)> TryGetJsonObjectAsync(int caseId, string materialId, long documentId, BlobType blobType) @@ -47,5 +47,25 @@ public async Task UploadJsonObjectAsync(int caseId, string materialId, long d var blobId = _blobTypeIdFactory.CreateBlobId(caseId, materialId, documentId, blobType); await _polarisBlobStorageService.UploadObjectAsync(obj, blobId); } + + public async Task GetPdfSizeFromMetadataAsync(int caseId, string materialId, long documentId, bool isOcrProcessed) + { + var blobId = _blobTypeIdFactory.CreateBlobId( + caseId, + materialId, + documentId, + BlobType.Pdf); + + var metadata = await _polarisBlobStorageService.GetMetadataAsync(blobId); + + if (metadata != null && + metadata.TryGetValue("FileSizeInMb", out var value) && + double.TryParse(value, out var size)) + { + return size; + } + + return null; + } } } \ No newline at end of file diff --git a/polaris-gateway/Services/Artefact/Domain/ArtefactResult.cs b/polaris-gateway/Services/Artefact/Domain/ArtefactResult.cs index 2fc327a14..73c0b6ef1 100644 --- a/polaris-gateway/Services/Artefact/Domain/ArtefactResult.cs +++ b/polaris-gateway/Services/Artefact/Domain/ArtefactResult.cs @@ -21,4 +21,6 @@ public class ArtefactResult // Diagnostic property public bool? IsFromStorage { get; set; } -} \ No newline at end of file + + public bool? FileSizeExceedsLimit { get; set; } +} diff --git a/polaris-gateway/Services/Artefact/Factories/ArtefactServiceResponseFactory.cs b/polaris-gateway/Services/Artefact/Factories/ArtefactServiceResponseFactory.cs index 5b4604545..b428a7375 100644 --- a/polaris-gateway/Services/Artefact/Factories/ArtefactServiceResponseFactory.cs +++ b/polaris-gateway/Services/Artefact/Factories/ArtefactServiceResponseFactory.cs @@ -18,6 +18,17 @@ public ArtefactResult CreateOkfResult(T result, bool? isFromStorage) }; } + public ArtefactResult CreateOkResultWithLargeFileFlag(T result, bool? isFromStorage, bool? fileSizeExceedsLimit) + { + return new ArtefactResult + { + Status = ResultStatus.ArtefactAvailable, + Artefact = result, + IsFromStorage = isFromStorage, + FileSizeExceedsLimit = fileSizeExceedsLimit, + }; + } + public ArtefactResult CreateInterimResult(Guid continuationToken) { return new ArtefactResult diff --git a/polaris-gateway/Services/Artefact/Factories/IArtefactServiceResponseFactory.cs b/polaris-gateway/Services/Artefact/Factories/IArtefactServiceResponseFactory.cs index 4930f5914..49a047b32 100644 --- a/polaris-gateway/Services/Artefact/Factories/IArtefactServiceResponseFactory.cs +++ b/polaris-gateway/Services/Artefact/Factories/IArtefactServiceResponseFactory.cs @@ -8,6 +8,8 @@ public interface IArtefactServiceResponseFactory { ArtefactResult CreateOkfResult(T result, bool? isFromStorage); + ArtefactResult CreateOkResultWithLargeFileFlag(T result, bool? isFromStorage, bool? fileSizeExceedsLimit); + ArtefactResult CreateInterimResult(Guid continuationToken); ArtefactResult CreateFailedResult(PdfConversionStatus? pdfConversionStatus, int? httpStatusCode); diff --git a/polaris-gateway/Services/Artefact/ICacheService.cs b/polaris-gateway/Services/Artefact/ICacheService.cs index c055b83f1..664779873 100644 --- a/polaris-gateway/Services/Artefact/ICacheService.cs +++ b/polaris-gateway/Services/Artefact/ICacheService.cs @@ -8,10 +8,12 @@ public interface ICacheService { Task<(bool, Stream)> TryGetPdfAsync(int caseId, string materialId, long documentId, bool isOcrProcessed); - Task UploadPdfAsync(int caseId, string materialId, long documentId, bool isOcrProcessed, Stream stream); + Task UploadPdfAsync(int caseId, string materialId, long documentId, bool isOcrProcessed, Stream stream, double fileSizeInMb); Task<(bool, T)> TryGetJsonObjectAsync(int caseId, string materialId, long documentId, BlobType blobType); Task UploadJsonObjectAsync(int caseId, string materialId, long documentId, BlobType blobType, T obj); + + Task GetPdfSizeFromMetadataAsync(int caseId, string materialId, long documentId, bool isOcrProcessed); } } \ No newline at end of file diff --git a/polaris-gateway/Services/Artefact/IPdfArtefactService.cs b/polaris-gateway/Services/Artefact/IPdfArtefactService.cs index 0b54a7b05..6a318ca27 100644 --- a/polaris-gateway/Services/Artefact/IPdfArtefactService.cs +++ b/polaris-gateway/Services/Artefact/IPdfArtefactService.cs @@ -2,10 +2,11 @@ using System; using System.IO; using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; namespace PolarisGateway.Services.Artefact; public interface IPdfArtefactService { public Task> GetPdfAsync(string cmsAuthValues, Guid correlationId, string urn, int caseId, string materialId, long documentId, bool isOcrProcessed, bool forceRefresh = false); -} \ No newline at end of file +} diff --git a/polaris-gateway/Services/Artefact/PdfArtefactService.cs b/polaris-gateway/Services/Artefact/PdfArtefactService.cs index a452f5284..eb2b767b2 100644 --- a/polaris-gateway/Services/Artefact/PdfArtefactService.cs +++ b/polaris-gateway/Services/Artefact/PdfArtefactService.cs @@ -3,7 +3,12 @@ using Common.Extensions; using Common.Services.BlobStorage; using Common.Services.OcrService; +using Microsoft.AspNetCore.Http; using Microsoft.CodeAnalysis.Operations; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using PolarisGateway.Models; using PolarisGateway.Services.Artefact.Domain; using PolarisGateway.Services.Artefact.Factories; using System; @@ -12,30 +17,29 @@ namespace PolarisGateway.Services.Artefact; -public class PdfArtefactService : IPdfArtefactService +public class PdfArtefactService( + IOptions options, + ILogger logger, + ICacheService cacheService, + IArtefactServiceResponseFactory artefactServiceResponseFactory, + IPdfRetrievalService pdfRetrievalService, + IOcrService ocrService) + : IPdfArtefactService { - private readonly IArtefactServiceResponseFactory _artefactServiceResponseFactory; - private readonly ICacheService _cacheService; - private readonly IPdfRetrievalService _pdfRetrievalService; - private readonly IOcrService _ocrService; - - public PdfArtefactService( - ICacheService cacheService, - IArtefactServiceResponseFactory artefactServiceResponseFactory, - IPdfRetrievalService pdfRetrievalService, - IOcrService ocrService) - { - _cacheService = cacheService.ExceptionIfNull(); - _artefactServiceResponseFactory = artefactServiceResponseFactory.ExceptionIfNull(); - _pdfRetrievalService = pdfRetrievalService.ExceptionIfNull(); - _ocrService = ocrService.ExceptionIfNull(); - } + private readonly ILogger _logger = logger.ExceptionIfNull(); + private readonly RedactionFileSizeOptions _redactionFileSizeOptions = options.Value; + private readonly IArtefactServiceResponseFactory _artefactServiceResponseFactory = artefactServiceResponseFactory.ExceptionIfNull(); + private readonly ICacheService _cacheService = cacheService.ExceptionIfNull(); + private readonly IPdfRetrievalService _pdfRetrievalService = pdfRetrievalService.ExceptionIfNull(); + private readonly IOcrService _ocrService = ocrService.ExceptionIfNull(); public async Task> GetPdfAsync(string cmsAuthValues, Guid correlationId, string urn, int caseId, string materialId, long documentId, bool isOcrProcessed, bool forceRefresh = false) { if (!forceRefresh && await _cacheService.TryGetPdfAsync(caseId, materialId, documentId, isOcrProcessed) is (true, var stream)) { - return _artefactServiceResponseFactory.CreateOkfResult(stream, true); + var cachedFileSizeInMb = await _cacheService.GetPdfSizeFromMetadataAsync(caseId, materialId, documentId, isOcrProcessed); + + return ValidateFileSizeAndCreatePdfResult(stream, documentId, true, cachedFileSizeInMb ?? 0); } var result = await _pdfRetrievalService.GetPdfStreamAsync(cmsAuthValues, correlationId, urn, caseId, materialId, documentId); @@ -47,6 +51,8 @@ public async Task> GetPdfAsync(string cmsAuthValues, Guid // Read the PDF into a byte array byte[] pdfBytes; + double fileSizeInMb; + using (var buffer = new MemoryStream()) { await result.PdfStream.CopyToAsync(buffer); @@ -59,11 +65,30 @@ public async Task> GetPdfAsync(string cmsAuthValues, Guid // For PDF upload: use another fresh MemoryStream using (var uploadStream = new MemoryStream(pdfBytes)) { - await _cacheService.UploadPdfAsync(caseId, materialId, documentId, isOcrProcessed, uploadStream); + fileSizeInMb = uploadStream.Length / (1024.0 * 1024.0); + await _cacheService.UploadPdfAsync(caseId, materialId, documentId, isOcrProcessed, uploadStream, fileSizeInMb); } var (_, pdfStream) = await _cacheService.TryGetPdfAsync(caseId, materialId, documentId, isOcrProcessed); - return _artefactServiceResponseFactory.CreateOkfResult(pdfStream, false); + + return ValidateFileSizeAndCreatePdfResult(pdfStream, documentId, false, fileSizeInMb); + } + + private ArtefactResult ValidateFileSizeAndCreatePdfResult(Stream pdfStream, long documentId, bool fromCache, double fileSizeInMb) + { + if (fileSizeInMb > _redactionFileSizeOptions.FileSizeLimitMb) + { + _logger.LogInformation( + "Warning: document {DocumentId} has file size {FileSizeMb}MB which exceeds limit {FileSizeLimitMb}MB.", + documentId, + fileSizeInMb, + _redactionFileSizeOptions.FileSizeLimitMb + ); + + return _artefactServiceResponseFactory.CreateOkResultWithLargeFileFlag(pdfStream, fromCache, true); + } + + return _artefactServiceResponseFactory.CreateOkfResult(pdfStream, fromCache); } private async Task ProcessAndUploadOcrAsync(byte[] pdfBytes, int caseId, string materialId, long documentId, Guid correlationId) diff --git a/polaris-pipeline/Common/Constants/HttpHeaderKeys.cs b/polaris-pipeline/Common/Constants/HttpHeaderKeys.cs index bb97f7d8b..e0a131433 100644 --- a/polaris-pipeline/Common/Constants/HttpHeaderKeys.cs +++ b/polaris-pipeline/Common/Constants/HttpHeaderKeys.cs @@ -6,5 +6,6 @@ public static class HttpHeaderKeys public const string CmsAuthValues = "Cms-Auth-Values"; public const string CmsToken = "Token"; public const string CmsCookie = "Cookies"; + public const string CpsFileTooLarge = "CPS-File-Too-Large"; } } diff --git a/polaris-pipeline/Common/Services/BlobStorage/BlobStorageService.cs b/polaris-pipeline/Common/Services/BlobStorage/BlobStorageService.cs index 1754b12e0..f9f85c6bd 100644 --- a/polaris-pipeline/Common/Services/BlobStorage/BlobStorageService.cs +++ b/polaris-pipeline/Common/Services/BlobStorage/BlobStorageService.cs @@ -74,6 +74,15 @@ public async Task UploadBlobAsync(Stream stream, string blobName, IDictionary> GetMetadataAsync(string blobName) + { + var blobContainerClient = await GetBlobContainerClientOrThrow(); + var blobClient = blobContainerClient.GetBlobClient(blobName); + var properties = await blobClient.GetPropertiesAsync(); + + return properties.Value.Metadata; + } + public async Task UploadObjectAsync(T obj, string blobName) { var objectString = _jsonConvertWrapper.SerializeObject(obj); @@ -102,6 +111,8 @@ public async Task BlobExistsAsync(string blobName, IDictionary GetBlobContainerClientOrThrow() { var blobContainerClient = _blobServiceClient.GetBlobContainerClient(_blobServiceContainerName); diff --git a/polaris-pipeline/Common/Services/BlobStorage/IBlobStorageService.cs b/polaris-pipeline/Common/Services/BlobStorage/IBlobStorageService.cs index 8b66103ef..4b8122911 100644 --- a/polaris-pipeline/Common/Services/BlobStorage/IBlobStorageService.cs +++ b/polaris-pipeline/Common/Services/BlobStorage/IBlobStorageService.cs @@ -7,6 +7,7 @@ namespace Common.Services.BlobStorage public interface IBlobStorageService { Task UploadBlobAsync(Stream stream, string blobName, IDictionary metaData = null); + Task> GetMetadataAsync(string blobName); Task GetBlob(string blobName); Task TryGetBlobAsync(string blobName, IDictionary mustMatchMetadata = null); Task TryGetObjectAsync(string blobName); diff --git a/polaris-pipeline/Common/Services/BlobStorage/IPolarisBlobStorageService.cs b/polaris-pipeline/Common/Services/BlobStorage/IPolarisBlobStorageService.cs index 5e1f074f6..808aa488d 100644 --- a/polaris-pipeline/Common/Services/BlobStorage/IPolarisBlobStorageService.cs +++ b/polaris-pipeline/Common/Services/BlobStorage/IPolarisBlobStorageService.cs @@ -1,14 +1,17 @@ -using System.IO; +using System.Collections.Generic; +using System.IO; using System.Threading.Tasks; namespace Common.Services.BlobStorage { public interface IPolarisBlobStorageService { - Task UploadBlobAsync(Stream stream, BlobIdType blobId, bool? isOcred = null); + Task UploadBlobAsync(Stream stream, BlobIdType blobId, bool? isOcred = null, double? fileSizeInMb = null); Task UploadBlobAsync(Stream stream, BlobIdType blobId, int? pageIndex = null, int? maxDimensionPixel = null); + Task> GetMetadataAsync(BlobIdType blobId); + Task GetBlobAsync(BlobIdType blobId); Task TryGetBlobAsync(BlobIdType blobId, bool? mustBeOcred = null); @@ -20,5 +23,6 @@ public interface IPolarisBlobStorageService Task DeleteBlobsByPrefixAsync(int prefix); Task BlobExistsAsync(BlobIdType blobId, bool? mustBeOcred = null); + } } diff --git a/polaris-pipeline/Common/Services/BlobStorage/PolarisBlobStorageService.cs b/polaris-pipeline/Common/Services/BlobStorage/PolarisBlobStorageService.cs index 03e8d2bab..1228359c2 100644 --- a/polaris-pipeline/Common/Services/BlobStorage/PolarisBlobStorageService.cs +++ b/polaris-pipeline/Common/Services/BlobStorage/PolarisBlobStorageService.cs @@ -1,6 +1,8 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.IO; +using System.Text; using System.Threading.Tasks; namespace Common.Services.BlobStorage; @@ -30,8 +32,13 @@ public Task TryGetBlobAsync(BlobIdType blobId, bool? mustBeOcred = null) public Task UploadBlobAsync(Stream stream, BlobIdType blobId) => _blobStorageService.UploadBlobAsync(stream, GetBlobName(blobId)); - public Task UploadBlobAsync(Stream stream, BlobIdType blobId, bool? isOcred = null) - => _blobStorageService.UploadBlobAsync(stream, GetBlobName(blobId), CreateMetaData(isOcred)); + public Task UploadBlobAsync(Stream stream, BlobIdType blobId, bool? isOcred = null, double? fileSizeInMb = null) + => _blobStorageService.UploadBlobAsync(stream, GetBlobName(blobId), CreateMetaData(isOcred, fileSizeInMb)); + + public Task> GetMetadataAsync(BlobIdType blobId) + { + return _blobStorageService.GetMetadataAsync(GetBlobName(blobId)); + } public Task UploadBlobAsync(Stream stream, BlobIdType blobId, int? pageIndex = null, int? maxDimensionPixel = null) => _blobStorageService.UploadBlobAsync(stream, GetBlobName(blobId, pageIndex, maxDimensionPixel)); @@ -69,8 +76,20 @@ private static string GetSafePrefix(int caseId) return $"{caseId}/"; } - private static Dictionary CreateMetaData(bool? ocrFlag) - => ocrFlag == true - ? new Dictionary { { IsOcrProcessedInCms, true.ToString() } } - : null; + private static Dictionary CreateMetaData(bool? ocrFlag, double? fileSizeInMb = null) + { + var metadata = new Dictionary(); + + if (ocrFlag == true) + { + metadata[IsOcrProcessedInCms] = true.ToString(); + } + + if (fileSizeInMb.HasValue) + { + metadata["FileSizeInMb"] = fileSizeInMb.Value.ToString("F3"); // formatting + } + + return metadata; + } } \ No newline at end of file diff --git a/polaris-terraform/main-terraform/dev.tfvars b/polaris-terraform/main-terraform/dev.tfvars index c8d6c5ea9..b565ba5d2 100644 --- a/polaris-terraform/main-terraform/dev.tfvars +++ b/polaris-terraform/main-terraform/dev.tfvars @@ -180,3 +180,5 @@ cps_global_components = { sp_polaris_web_enabled = true # this SP has been temporarily disabled for Dev on the 29/07/2025. app_reg_owners = ["49a53165-9fa6-4f51-bebe-90ed1cc2e58f", "2cd0a11e-402b-4562-998c-2376d61bbb7f"] + +redaction_file_size_limit_mb = 15 diff --git a/polaris-terraform/main-terraform/function-gateway.tf b/polaris-terraform/main-terraform/function-gateway.tf index 648c89795..65dd32bb1 100644 --- a/polaris-terraform/main-terraform/function-gateway.tf +++ b/polaris-terraform/main-terraform/function-gateway.tf @@ -46,6 +46,7 @@ resource "azurerm_linux_function_app" "fa_polaris" { "PolarisPipelineCoordinatorBaseUrl" = "https://fa-${local.global_resource_name}-coordinator.azurewebsites.net/api/" "PolarisPipelineRedactPdfBaseUrl" = "https://fa-${local.global_resource_name}-pdf-generator.azurewebsites.net/api/" "PolarisPdfThumbnailGeneratorBaseUrl" = "https://fa-${local.global_resource_name}-pdf-thumb-gen.azurewebsites.net/api/" + "RedactionFileSize__FileSizeLimitMb" = var.redaction_file_size_limit_mb "TenantId" = data.azurerm_client_config.current.tenant_id "WEBSITE_ADD_SITENAME_BINDINGS_IN_APPHOST_CONFIG" = "1" "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING" = azurerm_storage_account.sa_gateway.primary_connection_string diff --git a/polaris-terraform/main-terraform/prod.tfvars b/polaris-terraform/main-terraform/prod.tfvars index c6ea4db6e..4ab3f70cf 100644 --- a/polaris-terraform/main-terraform/prod.tfvars +++ b/polaris-terraform/main-terraform/prod.tfvars @@ -179,3 +179,5 @@ cps_global_components = { sp_polaris_web_enabled = true app_reg_owners = ["49a53165-9fa6-4f51-bebe-90ed1cc2e58f", "2cd0a11e-402b-4562-998c-2376d61bbb7f"] + +redaction_file_size_limit_mb = 15 \ No newline at end of file diff --git a/polaris-terraform/main-terraform/qa.tfvars b/polaris-terraform/main-terraform/qa.tfvars index c1a655e8b..ef12a7654 100644 --- a/polaris-terraform/main-terraform/qa.tfvars +++ b/polaris-terraform/main-terraform/qa.tfvars @@ -180,3 +180,5 @@ cps_global_components = { sp_polaris_web_enabled = true app_reg_owners = ["49a53165-9fa6-4f51-bebe-90ed1cc2e58f", "2cd0a11e-402b-4562-998c-2376d61bbb7f"] + +redaction_file_size_limit_mb = 15 diff --git a/polaris-terraform/main-terraform/uat.tfvars b/polaris-terraform/main-terraform/uat.tfvars index 7155cf563..62322f63a 100644 --- a/polaris-terraform/main-terraform/uat.tfvars +++ b/polaris-terraform/main-terraform/uat.tfvars @@ -179,4 +179,6 @@ cps_global_components = { sp_polaris_web_enabled = true -app_reg_owners = ["49a53165-9fa6-4f51-bebe-90ed1cc2e58f", "2cd0a11e-402b-4562-998c-2376d61bbb7f"] \ No newline at end of file +app_reg_owners = ["49a53165-9fa6-4f51-bebe-90ed1cc2e58f", "2cd0a11e-402b-4562-998c-2376d61bbb7f"] + +redaction_file_size_limit_mb = 15 \ No newline at end of file diff --git a/polaris-terraform/main-terraform/variables.tf b/polaris-terraform/main-terraform/variables.tf index f739f446d..c2733c8cd 100644 --- a/polaris-terraform/main-terraform/variables.tf +++ b/polaris-terraform/main-terraform/variables.tf @@ -340,6 +340,10 @@ variable "hte_feature_flag" { type = bool } +variable "redaction_file_size_limit_mb" { + type = number +} + variable "image_conversion_redaction" { type = object({ resolution = number From 64c5fb7e717d9845da0d658e58c60d86509801fc Mon Sep 17 00:00:00 2001 From: girmacps Date: Fri, 3 Jul 2026 16:35:44 +0100 Subject: [PATCH 13/19] FCT2-19748 & FCT2-20177 Mg Forms to Comms mapping changes (#2081) * Apply new logic for Comms to MG Forms mapping * apply new logic for mgForms to comms mapping * delete invalid files * check for null --- .../Constants/CommsDocumentTypeIds.cs | 32 +++++ Cps.Fct.Hk.Ui.Services/DocumentTypeMapper.cs | 2 +- .../HouseKeeping/GetCaseMaterialsTests.cs | 126 ++++++++++++++++++ .../HouseKeeping/GetCaseMaterials.cs | 10 +- 4 files changed, 168 insertions(+), 2 deletions(-) create mode 100644 Cps.Fct.Hk.Ui.Services/Constants/CommsDocumentTypeIds.cs diff --git a/Cps.Fct.Hk.Ui.Services/Constants/CommsDocumentTypeIds.cs b/Cps.Fct.Hk.Ui.Services/Constants/CommsDocumentTypeIds.cs new file mode 100644 index 000000000..910f5d952 --- /dev/null +++ b/Cps.Fct.Hk.Ui.Services/Constants/CommsDocumentTypeIds.cs @@ -0,0 +1,32 @@ +// +// Copyright (c) The Crown Prosecution Service. All rights reserved. +// + +namespace Cps.Fct.Hk.Ui.Services.Constants; + +/// +/// Contains constants for Communication document Type IDs to be excluded from MGForms listings. +/// These IDs correspond to specific document types in the DocumentTypeMapper. +/// +public static class CommsDocumentTypeIds +{ + /// + /// Communication Type ID for PE3 document type. + /// + public const string PE3 = "1053"; + + /// + /// Communication Type ID for PE4 document type. + /// + public const string PE4 = "1054"; + + /// + /// Communication Type ID for DREP document type. + /// + public const string DREP = "1055"; + + /// + /// Communication Type IDs that should be excluded from Used MG Forms. + /// + public static readonly string[] ExcludedFromUsedMgForms = { PE3, PE4, DREP }; +} diff --git a/Cps.Fct.Hk.Ui.Services/DocumentTypeMapper.cs b/Cps.Fct.Hk.Ui.Services/DocumentTypeMapper.cs index 4f2f2b0ce..b22809b6c 100644 --- a/Cps.Fct.Hk.Ui.Services/DocumentTypeMapper.cs +++ b/Cps.Fct.Hk.Ui.Services/DocumentTypeMapper.cs @@ -87,7 +87,7 @@ public DocumentTypeMapper(ILogger logger) { 1028, new DocumentTypeInfo { DocumentType = "MG/FSSB", Category = DocumentTypeCategories.Exhibit, Group = DocumentTypeGroups.Exhibit } }, { 1029, new DocumentTypeInfo { DocumentType = "Other Communication", Category = DocumentTypeCategories.Communication, Group = DocumentTypeGroups.Other } }, { 1030, new DocumentTypeInfo { DocumentType = "Other Exhibit", Category = DocumentTypeCategories.Exhibit, Group = DocumentTypeGroups.Exhibit } }, - { 1200, new DocumentTypeInfo { DocumentType = "Other Material", Category = DocumentTypeCategories.Communication, Group = DocumentTypeGroups.Other } }, + { 1200, new DocumentTypeInfo { DocumentType = "Other Material", Category = DocumentTypeCategories.OtherMaterial, Group = DocumentTypeGroups.Other } }, { 1056, new DocumentTypeInfo { DocumentType = "PCN1", Category = DocumentTypeCategories.DefendantPreCons, Group = DocumentTypeGroups.Other } }, { 1057, new DocumentTypeInfo { DocumentType = "PCN2", Category = DocumentTypeCategories.DefendantPreCons, Group = DocumentTypeGroups.Other } }, { 1058, new DocumentTypeInfo { DocumentType = "PCN3", Category = DocumentTypeCategories.UnusedMaterial, Group = DocumentTypeGroups.MgForm } }, diff --git a/polaris-gateway.tests/Functions/HouseKeeping/GetCaseMaterialsTests.cs b/polaris-gateway.tests/Functions/HouseKeeping/GetCaseMaterialsTests.cs index 62fa4776e..cfee952d0 100644 --- a/polaris-gateway.tests/Functions/HouseKeeping/GetCaseMaterialsTests.cs +++ b/polaris-gateway.tests/Functions/HouseKeeping/GetCaseMaterialsTests.cs @@ -1661,6 +1661,132 @@ public async Task Run_ReturnsOkResult_WhenUsedMgFormsAreEmpty() log.Message != null && log.Message.Contains($"{LoggingConstants.HskUiLogPrefix} Milestone: caseId [123] GetCaseMaterials function completed")); } + /// + /// Tests that PE3 (1053), PE4 (1054), and DREP (1055) material types are excluded from Used MG Forms. + /// + /// A task representing the asynchronous test operation. + [Fact] + public async Task Run_ExcludesPE3PE4AndDREPMaterialTypes_FromUsedMgForms() + { + // Arrange + var mockRequest = SetUpMockRequest(); + + var mockCommunications = new List + { + new Communication(1, "FileA.pdf", "Subject A", 1012, 123, "/some/path/doc1.pdf", "None", "Administrative", "Type A", false), + }; + + var mockCaseMaterials = new List + { + new CaseMaterial(1, "FileA.pdf", "Subject A", 1012, 123, "/some/path/doc1.pdf", "Administrative", "Type A", false, "None"), + }; + + // Create Used MG Forms with both excluded and included material types + var mgFormPE3 = new MgForm( + Id: 1, + Title: "PE3 Form", + OriginalFileName: "pe3.pdf", + MaterialType: "1053", // PE3 - should be excluded + DocumentType: 1053, + Link: "http://example1.com", + Status: "Used", + Date: receivedDate); + + var mgFormPE4 = new MgForm( + Id: 2, + Title: "PE4 Form", + OriginalFileName: "pe4.pdf", + MaterialType: "1054", // PE4 - should be excluded + DocumentType: 1054, + Link: "http://example2.com", + Status: "Used", + Date: receivedDate); + + var mgFormDREP = new MgForm( + Id: 3, + Title: "DREP Form", + OriginalFileName: "drep.pdf", + MaterialType: "1055", // DREP - should be excluded + DocumentType: 1055, + Link: "http://example3.com", + Status: "Used", + Date: receivedDate); + + var mgFormValid = new MgForm( + Id: 4, + Title: "Valid MG Form", + OriginalFileName: "valid.pdf", + MaterialType: "1202", // Valid - should NOT be excluded + DocumentType: 1202, + Link: "http://example4.com", + Status: "Used", + Date: receivedDate); + + var usedMgForms = new UsedMgFormsResponse + { + MgForms = new List { mgFormPE3, mgFormPE4, mgFormDREP, mgFormValid }, + }; + + // Only the valid MG form should be mapped (PE3, PE4, DREP excluded) + var mappedUsedMgFormsCaseMaterials = new List + { + new CaseMaterial(4, "valid.pdf", "Valid MG Form", 1202, 4, "http://example4.com", "MG Form", "MG Form", false, "Used"), + }; + + // Mock empty responses for other materials + var unusedMaterials = new UnusedMaterialsResponse(); + var usedStatements = new Common.Dto.Response.HouseKeeping.UsedStatementsResponse(); + var usedExhibits = new UsedExhibitsResponse(); + var usedOtherMaterials = new UsedOtherMaterialsResponse(); + var exhibitProducers = new ExhibitProducersResponse(); + + // Mock RetrieveCaseMaterialsAsync + mockCaseMaterialService + .Setup(x => x.RetrieveCaseMaterialsAsync(123, It.IsAny())) + .ReturnsAsync((mockCommunications, unusedMaterials, usedStatements, usedExhibits, usedMgForms, usedOtherMaterials, exhibitProducers)); + + // Mock MapCommunicationsToCaseMaterials + mockCaseMaterialService + .Setup(x => x.MapCommunicationsToCaseMaterials(mockCommunications)) + .Returns(mockCaseMaterials); + + // Mock MapUsedMgFormsToCaseMaterials - should only receive the valid MG form after filtering + mockCaseMaterialService + .Setup(x => x.MapUsedMgFormsToCaseMaterials(It.IsAny())) + .Returns(response => + { + // Verify that PE3, PE4, and DREP were filtered out + Assert.Single(response.MgForms); + Assert.Equal("1202", response.MgForms[0].MaterialType); + Assert.Equal("Valid MG Form", response.MgForms[0].Title); + return mappedUsedMgFormsCaseMaterials; + }); + + // Act + IActionResult result = await getCaseMaterialsFunction.Run(mockRequest.Object, 123); + + // Assert + OkObjectResult okResult = Assert.IsType(result); + Assert.NotNull(okResult.Value); + + List caseMaterials = Assert.IsType>(okResult.Value); + + // Verify the result contains communications + the valid MG form (PE3, PE4, DREP excluded) + Assert.Equal(2, caseMaterials.Count); + Assert.Contains(caseMaterials, cm => cm.Id == 1 && cm.Subject == "Subject A"); + Assert.Contains(caseMaterials, cm => cm.Id == 4 && cm.Subject == "Valid MG Form"); + + // Verify PE3, PE4, and DREP are NOT in the result + Assert.DoesNotContain(caseMaterials, cm => cm.Subject == "PE3 Form"); + Assert.DoesNotContain(caseMaterials, cm => cm.Subject == "PE4 Form"); + Assert.DoesNotContain(caseMaterials, cm => cm.Subject == "DREP Form"); + + // Verify the MapUsedMgFormsToCaseMaterials was called once + mockCaseMaterialService.Verify( + x => x.MapUsedMgFormsToCaseMaterials(It.IsAny()), + Times.Once); + } + private static Mock SetUpMockRequest() { var mockRequest = new Mock(); diff --git a/polaris-gateway/Functions/HouseKeeping/GetCaseMaterials.cs b/polaris-gateway/Functions/HouseKeeping/GetCaseMaterials.cs index 391eaf675..8e6695e3d 100644 --- a/polaris-gateway/Functions/HouseKeeping/GetCaseMaterials.cs +++ b/polaris-gateway/Functions/HouseKeeping/GetCaseMaterials.cs @@ -27,6 +27,7 @@ namespace PolarisGateway.Functions.HouseKeeping; using Common.Configuration; using Common.Constants; using Common.Enums; +using Cps.Fct.Hk.Ui.Services.Constants; /// /// Represents a function that retrieves the case materials for a case, @@ -42,7 +43,7 @@ namespace PolarisGateway.Functions.HouseKeeping; public class GetCaseMaterials( ILogger logger, ICommunicationService communicationService, - ICaseMaterialService caseMaterialService): BaseFunction(logger) + ICaseMaterialService caseMaterialService) : BaseFunction(logger) { private readonly ILogger logger = logger; private readonly ICommunicationService communicationService = communicationService; @@ -118,6 +119,13 @@ public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, } // Add Used MG forms + // Exclude MG forms with material types that are in the ExcludedFromUsedMgForms list as they are already included in communications and will be mapped to CaseMaterials from communications + if (usedMgForms.MgForms != null) + { + usedMgForms.MgForms.RemoveAll(mgForm => + CommsDocumentTypeIds.ExcludedFromUsedMgForms.Contains(mgForm.MaterialType)); + } + this.caseMaterialService.AddCaseMaterials(allCaseMaterials!, usedMgForms.MgForms ?? Enumerable.Empty(), "MG Form", "MG Form", "Used"); if (usedMgForms.MgForms != null && usedMgForms.MgForms.Count != 0) { From 65518ecd0b82244889441ab0b88c5de435afd053 Mon Sep 17 00:00:00 2001 From: girmacps Date: Tue, 7 Jul 2026 16:50:27 +0100 Subject: [PATCH 14/19] Feature/fct2 15654 Add cancellation token to APIs and Services (#2064) * initial commit * updating services and apis * remove unused files * initial commit * updating services and apis * remove unused files * fix unit tests * Address PR comments * merge from development 2 * merge from dev * refactoring to address SonarQube warnings * address sonar * sonarqube warnings * sonarqube warnings take 4 * sonarqube take 5 * fix unit test --- .../IBulkSetUnusedService.cs | 3 +- .../ICaseActionPlanService.cs | 3 +- .../ICaseDefendantsService.cs | 3 +- Cps.Fct.Hk.Ui.Interfaces/ICaseInfoService.cs | 4 +- Cps.Fct.Hk.Ui.Interfaces/ICaseLockService.cs | 3 +- .../ICaseMaterialService.cs | 7 +- .../ICommunicationService.cs | 84 +++-- .../IConversionService.cs | 33 +- Cps.Fct.Hk.Ui.Interfaces/IDocumentService.cs | 3 +- ...ialReclassificationOrchestrationService.cs | 4 +- .../IReclassificationService.cs | 16 +- .../IUmaReclassifyService.cs | 3 +- Cps.Fct.Hk.Ui.Interfaces/IWitnessService.cs | 9 +- .../BulkSetUnusedServiceTests.cs | 10 +- .../CaseInfoServiceTests.cs | 1 + .../CommunicationServiceTests.cs | 9 +- ...sificationOrchestrationServiceUnitTests.cs | 16 +- .../BulkSetUnusedService.cs | 4 +- .../CaseActionPlanService.cs | 6 +- .../CaseDefendantsService.cs | 4 +- Cps.Fct.Hk.Ui.Services/CaseInfoService.cs | 6 +- Cps.Fct.Hk.Ui.Services/CaseLockService.cs | 4 +- Cps.Fct.Hk.Ui.Services/CaseMaterialService.cs | 48 +-- .../CommunicationService.cs | 124 ++++---- Cps.Fct.Hk.Ui.Services/ConversionService.cs | 81 +++-- Cps.Fct.Hk.Ui.Services/DocumentService.cs | 15 +- ...ialReclassificationOrchestrationService.cs | 51 ++-- .../ReclassificationService.cs | 35 +-- .../UmaReclassifyService.cs | 3 +- Cps.Fct.Hk.Ui.Services/WitnessService.cs | 12 +- DdeiClient/Clients/BaseCmsClient.cs | 35 +-- .../Interfaces/IMasterDataServiceClient.cs | 93 ++++-- DdeiClient/Clients/Interfaces/IMdsClient.cs | 45 +-- DdeiClient/Clients/MasterDataServiceClient.cs | 150 ++++----- DdeiClient/Clients/MdsClient.cs | 97 +++--- global.json | 6 + .../HouseKeeping/GetCaseInfoTests.cs | 143 +++++++-- .../Artefact/OcrArtefactServiceTests.cs | 16 +- .../Artefact/PdfArtefactServiceTests.cs | 64 ++-- polaris-gateway/Functions/AddDocumentNote.cs | 4 +- .../Functions/CancelCheckoutDocument.cs | 5 +- polaris-gateway/Functions/CheckoutDocument.cs | 5 +- .../Functions/GenerateThumbnail.cs | 4 +- polaris-gateway/Functions/GetCase.cs | 5 +- polaris-gateway/Functions/GetCases.cs | 5 +- polaris-gateway/Functions/GetDocumentList.cs | 4 +- polaris-gateway/Functions/GetDocumentNotes.cs | 5 +- .../Functions/GetExhibitProducers.cs | 5 +- .../Functions/GetMaterialTypeList.cs | 5 +- polaris-gateway/Functions/GetOcr.cs | 4 +- polaris-gateway/Functions/GetPdf.cs | 14 +- polaris-gateway/Functions/GetPii.cs | 4 +- polaris-gateway/Functions/GetThumbnail.cs | 3 +- .../Functions/GetWitnessStatements.cs | 5 +- polaris-gateway/Functions/GetWitnesses.cs | 5 +- .../Functions/HouseKeeping/BulkSetUnused.cs | 5 +- .../HouseKeeping/CompleteReclassification.cs | 6 +- .../Functions/HouseKeeping/DiscardMaterial.cs | 6 +- .../HouseKeeping/GetCaseDefendants.cs | 5 +- .../HouseKeeping/GetCaseExhibitProducers.cs | 7 +- .../HouseKeeping/GetCaseHistoryEvent.cs | 5 +- .../Functions/HouseKeeping/GetCaseInfo.cs | 35 +-- .../Functions/HouseKeeping/GetCaseLockInfo.cs | 5 +- .../HouseKeeping/GetCaseMaterials.cs | 286 ++++++++++++------ .../HouseKeeping/GetCaseMaterialsPreview.cs | 9 +- .../HouseKeeping/GetCaseWitnessStatements.cs | 5 +- .../HouseKeeping/GetCaseWitnesses.cs | 5 +- .../HouseKeeping/GetInitialReview.cs | 5 +- .../HouseKeeping/GetMaterialDocuments.cs | 11 +- .../HouseKeeping/GetOffenceChargeById.cs | 206 ++++++------- .../HouseKeeping/GetPCDRequestByPcdId.cs | 5 +- .../HouseKeeping/GetPCDRequestCore.cs | 5 +- .../Functions/HouseKeeping/GetPcdReview.cs | 5 +- .../HouseKeeping/GetPreChargeDecision.cs | 5 +- .../GetPreChargeDecisionByHistoryId.cs | 5 +- .../Functions/HouseKeeping/RenameMaterial.cs | 3 +- .../HouseKeeping/SetMaterialReadStatus.cs | 5 +- .../Functions/HouseKeeping/UmaReclassify.cs | 8 +- .../Functions/HouseKeeping/UpdateExhibit.cs | 6 +- .../Functions/HouseKeeping/UpdateStatement.cs | 8 +- polaris-gateway/Functions/LookupUrn.cs | 5 +- .../Functions/PolarisPipelineCase.cs | 3 +- .../Functions/PolarisPipelineCaseDelete.cs | 4 +- .../Functions/PolarisPipelineCaseSearch.cs | 5 +- .../PolarisPipelineCaseSearchIndexCount.cs | 4 +- .../PolarisPipelineGetCaseTracker.cs | 4 +- .../PolarisPipelineModifyDocument.cs | 4 +- .../PolarisPipelineSaveDocumentRedactions.cs | 4 +- .../Functions/ReclassifyDocument.cs | 4 +- polaris-gateway/Functions/RenameDocument.cs | 4 +- .../Functions/ToggleIsUnusedDocument.cs | 7 +- .../Services/Artefact/Domain/GetPdfRequest.cs | 20 ++ .../Services/Artefact/IPdfArtefactService.cs | 18 +- .../Services/Artefact/OcrArtefactService.cs | 10 +- .../Services/Artefact/PdfArtefactService.cs | 25 +- .../IMdsCaseOrchestrationService.cs | 5 +- .../MdsCaseOrchestrationService.cs | 21 +- .../ReclassifyCaseMaterialServiceRequest.cs | 30 ++ 98 files changed, 1350 insertions(+), 818 deletions(-) create mode 100644 global.json create mode 100644 polaris-gateway/Services/Artefact/Domain/GetPdfRequest.cs create mode 100644 polaris-pipeline/Common/Dto/Request/HouseKeeping/ReclassifyCaseMaterialServiceRequest.cs diff --git a/Cps.Fct.Hk.Ui.Interfaces/IBulkSetUnusedService.cs b/Cps.Fct.Hk.Ui.Interfaces/IBulkSetUnusedService.cs index e73634ca9..8cec49e51 100644 --- a/Cps.Fct.Hk.Ui.Interfaces/IBulkSetUnusedService.cs +++ b/Cps.Fct.Hk.Ui.Interfaces/IBulkSetUnusedService.cs @@ -20,6 +20,7 @@ public interface IBulkSetUnusedService /// The case ID. /// The authentication values for CMS access. /// The materials to reclassify as unused. + /// The cancellation token. /// A task that returns the bulk set response. - Task BulkSetUnusedAsync(int caseId, CmsAuthValues cmsAuthValues, IReadOnlyCollection bulkSetUnusedRequests); + Task BulkSetUnusedAsync(int caseId, CmsAuthValues cmsAuthValues, IReadOnlyCollection bulkSetUnusedRequests, CancellationToken cancellationToken = default); } diff --git a/Cps.Fct.Hk.Ui.Interfaces/ICaseActionPlanService.cs b/Cps.Fct.Hk.Ui.Interfaces/ICaseActionPlanService.cs index b716730ce..24477d087 100644 --- a/Cps.Fct.Hk.Ui.Interfaces/ICaseActionPlanService.cs +++ b/Cps.Fct.Hk.Ui.Interfaces/ICaseActionPlanService.cs @@ -21,6 +21,7 @@ public interface ICaseActionPlanService /// The unique identifier of the case for which an action plan is being created. /// The action plan to create. /// The authentication values used to authorize the request to retrieve communications. + /// The cancellation token. /// A task that represents the asynchronous operation. The task result contains a read-only object. - Task AddCaseActionPlanAsync(string urn, int caseId, AddCaseActionPlanRequest addCaseActionPlanRequest, CmsAuthValues cmsAuthValues); + Task AddCaseActionPlanAsync(string urn, int caseId, AddCaseActionPlanRequest addCaseActionPlanRequest, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default); } diff --git a/Cps.Fct.Hk.Ui.Interfaces/ICaseDefendantsService.cs b/Cps.Fct.Hk.Ui.Interfaces/ICaseDefendantsService.cs index f2815c016..e759a9b23 100644 --- a/Cps.Fct.Hk.Ui.Interfaces/ICaseDefendantsService.cs +++ b/Cps.Fct.Hk.Ui.Interfaces/ICaseDefendantsService.cs @@ -18,6 +18,7 @@ public interface ICaseDefendantsService /// /// Unique identifier of the case to retrieve defendants for. /// The authentication values used to authorize the request to retrieve defendants. + /// Cancelltion token. /// A task representing the asynchronous operation. - Task GetCaseDefendantsAsync(int caseId, CmsAuthValues cmsAuthValues); + Task GetCaseDefendantsAsync(int caseId, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default); } diff --git a/Cps.Fct.Hk.Ui.Interfaces/ICaseInfoService.cs b/Cps.Fct.Hk.Ui.Interfaces/ICaseInfoService.cs index 11ff8e172..9ef50d454 100644 --- a/Cps.Fct.Hk.Ui.Interfaces/ICaseInfoService.cs +++ b/Cps.Fct.Hk.Ui.Interfaces/ICaseInfoService.cs @@ -4,6 +4,7 @@ namespace Cps.Fct.Hk.Ui.Interfaces; +using System.Threading; using System.Threading.Tasks; using Common.Dto.Request; using Common.Dto.Response.HouseKeeping; @@ -18,6 +19,7 @@ public interface ICaseInfoService /// /// The unique identifier of the case for which communications are being retrieved. /// The authentication values used to authorize the request to retrieve communications. + /// A token to cancel the asynchronous operation. Defaults to . /// A task that represents the asynchronous operation. The task result contains a read-only object. - Task GetCaseInfoAsync(int caseId, CmsAuthValues cmsAuthValues); + Task GetCaseInfoAsync(int caseId, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default); } diff --git a/Cps.Fct.Hk.Ui.Interfaces/ICaseLockService.cs b/Cps.Fct.Hk.Ui.Interfaces/ICaseLockService.cs index dff2174f3..f8b2b5ee1 100644 --- a/Cps.Fct.Hk.Ui.Interfaces/ICaseLockService.cs +++ b/Cps.Fct.Hk.Ui.Interfaces/ICaseLockService.cs @@ -18,6 +18,7 @@ public interface ICaseLockService /// /// The ID of the case to be unlocked. /// The CMS authentication values required for the API call. + /// Cancellation token. /// A task that represents the asynchronous operation. The task result contains a read-only string object. - Task CheckCaseLockAsync(int caseId, CmsAuthValues cmsAuthValues); + Task CheckCaseLockAsync(int caseId, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default); } diff --git a/Cps.Fct.Hk.Ui.Interfaces/ICaseMaterialService.cs b/Cps.Fct.Hk.Ui.Interfaces/ICaseMaterialService.cs index 5d2103fd0..9cfd3135f 100644 --- a/Cps.Fct.Hk.Ui.Interfaces/ICaseMaterialService.cs +++ b/Cps.Fct.Hk.Ui.Interfaces/ICaseMaterialService.cs @@ -78,7 +78,6 @@ public interface ICaseMaterialService /// /// The containing collections of unused materials to be mapped. /// - /// Inbox communucations. /// /// A list of objects representing the mapped unused materials. /// Returns an empty list if no materials are available. @@ -90,6 +89,7 @@ public interface ICaseMaterialService /// /// The ID of the case. /// Authentication details for accessing the CMS. + /// A token to cancel the asynchronous operation. Defaults to . /// /// A tuple containing case communications, unused materials, used statements, used exhibits, used MG forms, used other materials and exhibit producers. /// @@ -101,7 +101,7 @@ public interface ICaseMaterialService UsedMgFormsResponse, UsedOtherMaterialsResponse, ExhibitProducersResponse)> - RetrieveCaseMaterialsAsync(int caseId, CmsAuthValues cmsAuthValues); + RetrieveCaseMaterialsAsync(int caseId, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default); /// /// Adds materials to the list of case materials, handling duplicates by removing the existing material and adding the new one. @@ -120,6 +120,7 @@ void AddCaseMaterials(List allCaseMaterials, IEnumerable mat /// /// The unique ID of the case. /// Authorization values for CMS access. + /// A token to cancel the asynchronous operation. Defaults to . /// A representing the result of the asynchronous operation. - public Task GetExhibitProducersAsync(int caseId, CmsAuthValues cmsAuthValues); + public Task GetExhibitProducersAsync(int caseId, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default); } diff --git a/Cps.Fct.Hk.Ui.Interfaces/ICommunicationService.cs b/Cps.Fct.Hk.Ui.Interfaces/ICommunicationService.cs index a25d06ef5..64b8ceece 100644 --- a/Cps.Fct.Hk.Ui.Interfaces/ICommunicationService.cs +++ b/Cps.Fct.Hk.Ui.Interfaces/ICommunicationService.cs @@ -24,48 +24,54 @@ public interface ICommunicationService /// /// The unique identifier of the case for which communications are being retrieved. /// The authentication values used to authorize the request to retrieve communications. + /// cancellation token used to cancel the operation. /// A task that represents the asynchronous operation. The task result contains a read-only collection of objects. - Task> GetCommunicationsAsync(int caseId, CmsAuthValues cmsAuthValues); + Task> GetCommunicationsAsync(int caseId, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default); /// /// Retrieves a collection of used statements for a specific case. /// /// The unique identifier of the case for which used statements are being retrieved. /// The authentication values used to authorize the request to retrieve the used statements. + /// cancellation token used to cancel the operation. /// A task that represents the asynchronous operation. The task result contains a object, which includes details of the used statements. - Task GetUsedStatementsAsync(int caseId, CmsAuthValues cmsAuthValues); + Task GetUsedStatementsAsync(int caseId, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default); /// /// Retrieves a collection of used exhibits for a specific case. /// /// The unique identifier of the case for which used exhibits are being retrieved. /// The authentication values used to authorize the request to retrieve the used exhibits. + /// cancellation token used to cancel the operation. /// A task that represents the asynchronous operation. The task result contains a object, which includes details of the used exhibits. - Task GetUsedExhibitsAsync(int caseId, CmsAuthValues cmsAuthValues); + Task GetUsedExhibitsAsync(int caseId, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default); /// /// Retrieves a collection of used MG forms for a specific case. /// /// The unique identifier of the case for which used MG forms are being retrieved. /// The authentication values used to authorize the request to retrieve the used MG forms. + /// cancellation token used to cancel the operation. /// A task that represents the asynchronous operation. The task result contains a object, which includes details of the used MG forms. - Task GetUsedMgFormsAsync(int caseId, CmsAuthValues cmsAuthValues); + Task GetUsedMgFormsAsync(int caseId, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default); /// /// Retrieves a collection of used other materials for a specific case. /// /// The unique identifier of the case for which used other materials are being retrieved. /// The authentication values used to authorize the request to retrieve the used other materials. + /// cancellation token used to cancel the operation. /// A task that represents the asynchronous operation. The task result contains a object, which includes details of the used other materials. - Task GetUsedOtherMaterialsAsync(int caseId, CmsAuthValues cmsAuthValues); + Task GetUsedOtherMaterialsAsync(int caseId, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default); /// /// Retrieves a collection of unused materials for a specific case. /// /// The unique identifier of the case for which unused materials are being retrieved. /// The authentication values used to authorize the request to retrieve the unused materials. + /// cancellation token used to cancel the operation. /// A task that represents the asynchronous operation. The task result contains a object, which includes details of the unused materials. - Task GetUnusedMaterialsAsync(int caseId, CmsAuthValues cmsAuthValues); + Task GetUnusedMaterialsAsync(int caseId, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default); /// /// Retrieves a collection of attachments for a specific communication. @@ -73,16 +79,18 @@ public interface ICommunicationService /// The unique identifier of the communication for which attachments are being retrieved. /// The subject of the communication for which attachments are being retrieved. /// The authentication values used to authorize the request to retrieve the unused materials. + /// cancellation token used to cancel the operation. /// A task that represents the asynchronous operation. The task result contains a object, which includes attachments of the communication. - Task GetAttachmentsAsync(int communicationId, string communicationSubject, CmsAuthValues cmsAuthValues); + Task GetAttachmentsAsync(int communicationId, string communicationSubject, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default); /// /// Retrieves all attachments for a collection of communications. /// /// The collection of communications to obtain attachments from. /// The authentication values used to authorize the request to retrieve the unused materials. + /// cancellation token used to cancel the operation. /// A task that represents the asynchronous operation. The task result contains a list of objects. - Task> RetrieveAllAttachmentsAsync(IReadOnlyCollection communications, CmsAuthValues cmsAuthValues); + Task> RetrieveAllAttachmentsAsync(IReadOnlyCollection communications, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default); /// /// Maps a list of attachments to a list of objects. @@ -97,16 +105,18 @@ public interface ICommunicationService /// The ID of the case from which communications are retrieved. /// The ID of the material to find the corresponding case material document link. /// Authorization values for CMS access. + /// cancellation token used to cancel the operation. /// An object that contains the communication link if found, or a result indicating that no communication was found. - Task GetCaseMaterialLinkAsync(int caseId, int materialId, CmsAuthValues cmsAuthValues); + Task GetCaseMaterialLinkAsync(int caseId, int materialId, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default); /// /// Retrieves list of exhibit producers required as part of exhibit reclassification for a given case Id. /// /// The unique ID of the case. /// Authorization values for CMS access. + /// cancellation token used to cancel the operation. /// A representing the result of the asynchronous operation. - public Task GetExhibitProducersAsync(int caseId, CmsAuthValues cmsAuthValues); + public Task GetExhibitProducersAsync(int caseId, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default); /// /// Asynchronously rename a material name with given material ID. @@ -116,16 +126,18 @@ public interface ICommunicationService /// New material name to be changed with. /// Authorization values for CMS access. /// correspondenceId. + /// cancellation token used to cancel the operation. /// An object that contains the renamed material id. - Task RenameMaterialAsync(int caseId, int materialId, string subject, CmsAuthValues cmsAuthValues, Guid correspondenceId = default); + Task RenameMaterialAsync(int caseId, int materialId, string subject, CmsAuthValues cmsAuthValues, Guid correspondenceId = default, CancellationToken cancellationToken = default); /// /// Get PCD requests core info by case Id. /// /// Get PCD requests by case id. /// Authorization values for CMS access. + /// cancellation token used to cancel the operation. /// Return collection of PCD requests. - Task> GetPcdRequestCore(int caseId, CmsAuthValues cmsAuthValues); + Task> GetPcdRequestCore(int caseId, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default); /// /// Get PCD Request overview by case Id Pcd id. @@ -133,8 +145,9 @@ public interface ICommunicationService /// Get PCD requests by case id. /// Parameter to get PCD requests by PCD id. /// Authorization values for CMS access. + /// cancellation token used to cancel the operation. /// Return single PCD request information by PCD id. - Task GetPcdRequestByPcdIdAsync(int caseId, int pcdId, CmsAuthValues cmsAuthValues); + Task GetPcdRequestByPcdIdAsync(int caseId, int pcdId, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default); /// /// Get PCD review detail by case Id Pcd id. @@ -144,16 +157,16 @@ public interface ICommunicationService /// Authorization values for CMS access. /// cancellationToken values for downstream systems. /// Return single PCD request information by PCD id. - Task GetPcdReviewDetailAsync(int caseId, int pcdId, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken); + Task GetPcdReviewDetailAsync(int caseId, int pcdId, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default); /// /// Get PCD review items by case Id Pcd id. /// /// Get PCD requests by case id. - /// Authorization values for CMS access. - /// cancellationToken values for downstream systems. + /// Authorization values for CMS access. + /// cancellation token used to cancel the operation. /// Return single PCD request information by PCD id. - Task> GetPcdReviewCoreAsync(int caseId, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken); + Task> GetPcdReviewCoreAsync(int caseId, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default); /// /// Asynchronously discard a material name with given material ID. @@ -164,8 +177,9 @@ public interface ICommunicationService /// Discard reason description for the material. /// Authorization values for CMS access. /// correspondenceId. + /// cancellation token used to cancel the operation. /// An object that contains the discarded material id. - Task DiscardMaterialAsync(int caseId, int materialId, string discardReason, string discardReasonDescription, CmsAuthValues cmsAuthValues, Guid correspondenceId = default); + Task DiscardMaterialAsync(int caseId, int materialId, string discardReason, string discardReasonDescription, CmsAuthValues cmsAuthValues, Guid correspondenceId = default, CancellationToken cancellationToken = default); /// /// Asynchronously sets material read or unread status.. @@ -174,8 +188,9 @@ public interface ICommunicationService /// Material read or unread status. /// Authorization values for CMS access. /// correspondenceId. + /// cancellationToken values for downstream systems. /// An object that contains the renamed material id. - Task SetMaterialReadStatusAsync(int materialId, MaterialReadStatusType action, CmsAuthValues cmsAuthValues, Guid correspondenceId = default); + Task SetMaterialReadStatusAsync(int materialId, MaterialReadStatusType action, CmsAuthValues cmsAuthValues, Guid correspondenceId = default, CancellationToken cancellationToken = default); /// /// Updates exhibit given an exhibit request. @@ -184,8 +199,9 @@ public interface ICommunicationService /// The update exhibit request model. /// Authorization values for CMS access. /// correspondenceId. + /// cancellationToken values for downstream systems. /// A representing the result of the asynchronous operation. - public Task UpdateExhibitAsync(int caseId, UpdateExhibitRequest exhibit, CmsAuthValues cmsAuthValues, Guid correspondenceId = default); + public Task UpdateExhibitAsync(int caseId, UpdateExhibitRequest exhibit, CmsAuthValues cmsAuthValues, Guid correspondenceId = default, CancellationToken cancellationToken = default); /// /// Update statement given a statement request. @@ -194,16 +210,18 @@ public interface ICommunicationService /// The update statement request. /// Authorization values for CMS access. /// correspondenceId. + /// cancellation token used to cancel the operation. /// A representing the result of the asynchronous operation. - public Task UpdateStatementAsync(int caseId, UpdateStatementRequest statement, CmsAuthValues cmsAuthValues, Guid correspondenceId = default); + public Task UpdateStatementAsync(int caseId, UpdateStatementRequest statement, CmsAuthValues cmsAuthValues, Guid correspondenceId = default, CancellationToken cancellationToken = default); /// /// Get First Initial Review Get Case History. /// /// The caseId. /// The CMS authentication values required for the API call. + /// cancellation token used to cancel the operation. /// A representing the asynchronous operation, with a string containing the lock release status. - Task FirstInitialReviewGetCaseHistoryAsync(int caseId, CmsAuthValues cmsAuthValues); + Task FirstInitialReviewGetCaseHistoryAsync(int caseId, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default); /// @@ -212,17 +230,18 @@ public interface ICommunicationService /// Case id. /// History Id. /// The CMS authentication values required for the API call. - /// The cancellationToken for downstream systems. + /// The cancellation token for the operation.ram> /// A representing the asynchronous operation, with a string containing the lock release status. - Task GetInitialReviewByHistoryIdAsync(int caseId, int historyId, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken); + Task GetInitialReviewByHistoryIdAsync(int caseId, int historyId, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default); /// /// GetHistoryEvents. /// /// The caseId. /// The CMS authentication values required for the API call. + /// The cancellation token for the operation. /// A representing the asynchronous operation, with a string containing the lock release status. - Task> GetHistoryEventsAsync(int caseId, CmsAuthValues cmsAuthValues); + Task> GetHistoryEventsAsync(int caseId, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default); /// /// Get Offence Charge. @@ -230,16 +249,18 @@ public interface ICommunicationService /// The caseId. /// History Id. /// The CMS authentication values required for the API call. + /// The cancellation token for the operation. /// A representing the asynchronous operation, with a string containing the lock release status. - Task GetOffenceChargeByHistoryIdAsync(int caseId, int historyId, CmsAuthValues cmsAuthValues); + Task GetOffenceChargeByHistoryIdAsync(int caseId, int historyId, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default); /// /// Get Pre Charge Decision Case History Event Details. /// /// Case Id. /// The CMS authentication values required for the API call. + /// The cancellation token for the operation. /// A representing the asynchronous operation, with a string containing the lock release status. - Task GetPreChargeDecisionCaseHistoryEventDetailsAsync(int caseId, CmsAuthValues cmsAuthValues); + Task GetPreChargeDecisionCaseHistoryEventDetailsAsync(int caseId, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default); /// /// Get Pre Charge Decision By History Id. @@ -247,14 +268,17 @@ public interface ICommunicationService /// Case Id. /// History Id. /// The CMS authentication values required for the API call. + /// The cancellation token for the operation. /// A representing the asynchronous operation, with a string containing the lock release status. - Task GetPreChargeDecisionByHistoryId(int caseId, int historyId, CmsAuthValues cmsAuthValues); + Task GetPreChargeDecisionByHistoryId(int caseId, int historyId, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default); /// /// Get Pcd review. /// /// The case id. - /// The CMS authentication values required for the API call. + /// The CMS authentication values required for the API call.The cancellation token for the operation. /// A representing the asynchronous operation, with a string containing the lock release status. - Task GetPcdReview(int caseId, CmsAuthValues cmsAuthValues); + Task GetPcdReview(int caseId, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default); } + diff --git a/Cps.Fct.Hk.Ui.Interfaces/IConversionService.cs b/Cps.Fct.Hk.Ui.Interfaces/IConversionService.cs index 93900f38c..c8bd38d7f 100644 --- a/Cps.Fct.Hk.Ui.Interfaces/IConversionService.cs +++ b/Cps.Fct.Hk.Ui.Interfaces/IConversionService.cs @@ -17,10 +17,11 @@ public interface IConversionService /// or in a cloud blob container, depending on the implementation. /// /// The file stream result representing the downloaded document. + /// The cancellation token. /// /// A representing the asynchronous operation. The task result is true if the document is successfully saved; otherwise, false. /// - Task SaveDownloadedDocumentToTemporaryStorageAsync(FileStreamResult downloadedDocument); + Task SaveDownloadedDocumentToTemporaryStorageAsync(FileStreamResult downloadedDocument, CancellationToken cancellationToken = default); /// /// Converts the given document (e.g., a raster image or text file) to a PDF and saves the result @@ -28,22 +29,24 @@ public interface IConversionService /// /// The temporary file name of the document to be converted to PDF. /// A flag to indicate if only first page needs to be converted or all pages when set to false. + /// The cancellation token used to cancel the service. /// /// A representing the asynchronous operation. The task result is a string containing /// the URL of the saved PDF document, or null if the conversion or save operation fails. /// - Task ConvertToPdfDocumentAsync(string tmpFileDownloadName, bool firstPageOnly = true); + Task ConvertToPdfDocumentAsync(string tmpFileDownloadName, bool firstPageOnly = true, CancellationToken cancellationToken = default); /// /// Converts a raster image (e.g., a .jpg, .png file) to a PDF document and saves the result /// either to local storage or a cloud blob container. /// /// The temporary file name of the raster image to be converted. + /// The cancellation token used to cancel the service. /// /// A representing the asynchronous operation. The task result is a string containing /// the URL of the saved PDF document, or null if the conversion or save operation fails. /// - Task ConvertRasterImageToPdfDocumentAsync(string tmpFileDownloadName); + Task ConvertRasterImageToPdfDocumentAsync(string tmpFileDownloadName, CancellationToken cancellationToken = default); /// /// Extracts specific pages from a PDF document and saves them as a new PDF file. @@ -51,33 +54,36 @@ public interface IConversionService /// /// The temporary file name of the PDF document to be processed. /// A flag to indicate if only first page needs to be converted or all pages when set to false. + /// The cancellation token used to cancel the service. /// /// A representing the asynchronous operation. The task result is a string containing /// the URL of the saved PDF document, or null if the conversion or save operation fails. /// - Task ConvertPdfToPdfDocumentAsync(string tmpFileDownloadName, bool firstPageOnly = true); + Task ConvertPdfToPdfDocumentAsync(string tmpFileDownloadName, bool firstPageOnly = true, CancellationToken cancellationToken = default); /// /// Converts a text file (e.g., .txt, .csv file) to a PDF document and saves the result /// either to local storage or a cloud blob container. /// /// The temporary file name of the text file to be converted. + /// The cancellation token used to cancel the service. /// /// A representing the asynchronous operation. The task result is a string containing /// the URL of the saved PDF document, or null if the conversion or save operation fails. /// - Task ConvertTxtToPdfDocumentAsync(string tmpFileDownloadName); + Task ConvertTxtToPdfDocumentAsync(string tmpFileDownloadName, CancellationToken cancellationToken = default); /// /// Converts a html file (e.g., .hte, .htm, .html file) to a PDF document and saves the result /// either to local storage or a cloud blob container. /// /// The temporary file name of the text file to be converted. + /// The cancellation token used to cancel the service. /// /// A representing the asynchronous operation. The task result is a string containing /// the URL of the saved PDF document, or null if the conversion or save operation fails. /// - Task ConvertHtmlToPdfDocumentAsync(string tmpFileDownloadName); + Task ConvertHtmlToPdfDocumentAsync(string tmpFileDownloadName, CancellationToken cancellationToken = default); /// /// Converts a doc file (e.g., .doc, .docx, .docm file) to a PDF document and saves the result @@ -85,22 +91,24 @@ public interface IConversionService /// /// The temporary file name of the text file to be converted. /// A flag to indicate if only first page needs to be converted or all pages when set to false. + /// The cancellation token used to cancel the service. /// /// A representing the asynchronous operation. The task result is a string containing /// the URL of the saved PDF document, or null if the conversion or save operation fails. /// - Task ConvertDocToPdfDocumentAsync(string tmpFileDownloadName, bool firstPageOnly = true); + Task ConvertDocToPdfDocumentAsync(string tmpFileDownloadName, bool firstPageOnly = true, CancellationToken cancellationToken = default); /// /// Converts an xml file (e.g., .xml file) to a PDF document and saves the result /// either to local storage or a cloud blob container. /// /// The temporary file name of the text file to be converted. + /// The cancellation token used to cancel the service. /// /// A representing the asynchronous operation. The task result is a string containing /// the URL of the saved PDF document, or null if the conversion or save operation fails. /// - Task ConvertXmlToPdfDocumentAsync(string tmpFileDownloadName); + Task ConvertXmlToPdfDocumentAsync(string tmpFileDownloadName, CancellationToken cancellationToken = default); /// /// Converts an xls file (e.g., .xls, .xlsx file) to a PDF document and saves the result @@ -108,22 +116,24 @@ public interface IConversionService /// /// The temporary file name of the text file to be converted. /// A flag to indicate if only first sheet needs to be converted or all sheets when set to false. + /// The cancellation token used to cancel the service. /// /// A representing the asynchronous operation. The task result is a string containing /// the URL of the saved PDF document, or null if the conversion or save operation fails. /// - Task ConvertXlsToPdfDocumentAsync(string tmpFileDownloadName, bool firstSheetOnly = true); + Task ConvertXlsToPdfDocumentAsync(string tmpFileDownloadName, bool firstSheetOnly = true, CancellationToken cancellationToken = default); /// /// Converts an msg file (e.g., .msg file) to a PDF document and saves the result /// either to local storage or a cloud blob container. /// /// The temporary file name of the text file to be converted. + /// The cancellation token used to cancel the service. /// /// A representing the asynchronous operation. The task result is a string containing /// the URL of the saved PDF document, or null if the conversion or save operation fails. /// - Task ConvertMsgToPdfDocumentAsync(string tmpFileDownloadName); + Task ConvertMsgToPdfDocumentAsync(string tmpFileDownloadName, CancellationToken cancellationToken = default); /// /// Converts an ppt file (e.g., .ppt and pptx file) to a PDF document and saves the result @@ -131,9 +141,10 @@ public interface IConversionService /// /// The temporary file name of the text file to be converted. /// A flag to indicate if only first slide needs to be converted or all slides when set to false.. + /// The cancellation token used to cancel the service. /// /// A representing the asynchronous operation. The task result is a string containing /// the URL of the saved PDF document, or null if the conversion or save operation fails. /// - Task ConvertPptToPdfDocumentAsync(string tmpFileDownloadName, bool firstSlideOnly = true); + Task ConvertPptToPdfDocumentAsync(string tmpFileDownloadName, bool firstSlideOnly = true, CancellationToken cancellationToken = default); } diff --git a/Cps.Fct.Hk.Ui.Interfaces/IDocumentService.cs b/Cps.Fct.Hk.Ui.Interfaces/IDocumentService.cs index a924eed6e..8415117e5 100644 --- a/Cps.Fct.Hk.Ui.Interfaces/IDocumentService.cs +++ b/Cps.Fct.Hk.Ui.Interfaces/IDocumentService.cs @@ -20,6 +20,7 @@ public interface IDocumentService /// The file path of the case material document to be downloaded. /// The authentication values used to authorize the request to retrieve the unused materials. /// A flag to indicate if the request is first page only or full document. + /// The cancellation token used to cancel the operation. /// A task that represents the asynchronous operation. The task result contains a object, the downloaded material. - Task GetMaterialDocumentAsync(string caseId, string link, CmsAuthValues cmsAuthValues, bool firstPageOnly = true); + Task GetMaterialDocumentAsync(string caseId, string link, CmsAuthValues cmsAuthValues, bool firstPageOnly = true, CancellationToken cancellationToken = default); } diff --git a/Cps.Fct.Hk.Ui.Interfaces/IMaterialReclassificationOrchestrationService.cs b/Cps.Fct.Hk.Ui.Interfaces/IMaterialReclassificationOrchestrationService.cs index 02de24f7c..ab09bec55 100644 --- a/Cps.Fct.Hk.Ui.Interfaces/IMaterialReclassificationOrchestrationService.cs +++ b/Cps.Fct.Hk.Ui.Interfaces/IMaterialReclassificationOrchestrationService.cs @@ -20,10 +20,12 @@ public interface IMaterialReclassificationOrchestrationService /// The material id belonging to the case material to reclassify. /// Authorization values for CMS access. /// The complete reclassification request. + /// The cancellation token used to cancel the operation. /// A representing the result of the asynchronous operation. Task CompleteReclassificationAsync( int caseId, int materialId, CmsAuthValues cmsAuthValues, - CompleteReclassificationRequest request); + CompleteReclassificationRequest request, + CancellationToken cancellationToken = default); } diff --git a/Cps.Fct.Hk.Ui.Interfaces/IReclassificationService.cs b/Cps.Fct.Hk.Ui.Interfaces/IReclassificationService.cs index 528e58003..b65c5beac 100644 --- a/Cps.Fct.Hk.Ui.Interfaces/IReclassificationService.cs +++ b/Cps.Fct.Hk.Ui.Interfaces/IReclassificationService.cs @@ -18,16 +18,12 @@ public interface IReclassificationService /// /// Reclassify material to classification type provided. /// - /// The unique identifier of the case. - /// The unique identifier of the material to reclassify. - /// The type of classification to apply. - /// The document type id. - /// Flag to indicate if material is used or unsed. - /// The material subject. + /// The reclassification request containing all material and classification details. /// Authorization values for CMS access. - /// The statement request. - /// Exhibit request. - /// The correspndence identifier. + /// The cancellation token used to cancel the operation. /// A representing the result of the asynchronous operation. - public Task ReclassifyCaseMaterialAsync(int caseId, int materialId, string classification, int documentTypeId, bool used, string subject, CmsAuthValues cmsAuthValues, ReclassifyStatementRequest? statement = null, ReclassifyExhibitRequest? exhibit = null, Guid correspondenceId = default); + public Task ReclassifyCaseMaterialAsync( + ReclassifyCaseMaterialServiceRequest request, + CmsAuthValues cmsAuthValues, + CancellationToken cancellationToken = default); } diff --git a/Cps.Fct.Hk.Ui.Interfaces/IUmaReclassifyService.cs b/Cps.Fct.Hk.Ui.Interfaces/IUmaReclassifyService.cs index a5f9c1d72..0e6fe19f6 100644 --- a/Cps.Fct.Hk.Ui.Interfaces/IUmaReclassifyService.cs +++ b/Cps.Fct.Hk.Ui.Interfaces/IUmaReclassifyService.cs @@ -17,9 +17,10 @@ public interface IUmaReclassifyService /// /// the case Id associated with the communications. /// The collection of communications to be matched. + /// The cancellation token used to cancel the operation. /// /// A task representing the asynchronous operation, /// containing a read-only collection of matched communications. /// - Task> ProcessMatchingRequest(int caseId, IReadOnlyCollection communications); + Task> ProcessMatchingRequest(int caseId, IReadOnlyCollection communications, CancellationToken cancellationToken = default); } diff --git a/Cps.Fct.Hk.Ui.Interfaces/IWitnessService.cs b/Cps.Fct.Hk.Ui.Interfaces/IWitnessService.cs index 7ca0c6296..f09f2b738 100644 --- a/Cps.Fct.Hk.Ui.Interfaces/IWitnessService.cs +++ b/Cps.Fct.Hk.Ui.Interfaces/IWitnessService.cs @@ -18,16 +18,18 @@ public interface IWitnessService /// /// Unique identifier of the case to retrieve witnesses for. /// The authentication values used to authorize the request to retrieve witnesses. + /// The cancellation token used to cancel the operation. /// A task representing the asynchronous operation. - Task GetCaseWitnessesAsync(int caseId, CmsAuthValues cmsAuthValues); + Task GetCaseWitnessesAsync(int caseId, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default); /// /// Service that retrieves statements for a witness. /// /// Unique witness identifier to retrieve statements for. /// The authentication values used to authorize the request to retrieve statements for a witness. + /// The cancellation token used to cancel the operation. /// A representing the asynchronous operation. - Task GetWitnessStatementsAsync(int witnessId, CmsAuthValues cmsAuthValues); + Task GetWitnessStatementsAsync(int witnessId, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default); /// /// Service that adds a case witness. @@ -38,6 +40,7 @@ public interface IWitnessService /// Witness last name. /// The authentication values used to authorize the request to retrieve statements for a witness. /// correspondenceId. + /// The cancellation token used to cancel the operation. /// The Id of the witness added. - Task AddWitnessAsync(string urn, int caseId, string firstName, string lastName, CmsAuthValues cmsAuthValues, Guid correspondenceId = default); + Task AddWitnessAsync(string urn, int caseId, string firstName, string lastName, CmsAuthValues cmsAuthValues, Guid correspondenceId = default, CancellationToken cancellationToken = default); } diff --git a/Cps.Fct.Hk.Ui.Services.Tests/BulkSetUnusedServiceTests.cs b/Cps.Fct.Hk.Ui.Services.Tests/BulkSetUnusedServiceTests.cs index e856b82ec..f5035c8d6 100644 --- a/Cps.Fct.Hk.Ui.Services.Tests/BulkSetUnusedServiceTests.cs +++ b/Cps.Fct.Hk.Ui.Services.Tests/BulkSetUnusedServiceTests.cs @@ -55,8 +55,8 @@ public async Task BulkSetUnusedAsync_AllMaterialsReclassified_ReturnsSuccess() // var cmsAuthValues = new CmsAuthValues(); var cmsAuthValues = new CmsAuthValues("cookies", Guid.NewGuid()); - this.mockApiClient.Setup(client => client.ReclassifyCommunicationAsync(It.IsAny(), It.IsAny())) - .ReturnsAsync((ReclassifyCommunicationRequest req, CmsAuthValues _) => + this.mockApiClient.Setup(client => client.ReclassifyCommunicationAsync(It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync((ReclassifyCommunicationRequest req, CmsAuthValues _, CancellationToken _) => new ReclassificationResponse( new ReclassifyCommunication { Id = req.materialId })); @@ -94,8 +94,8 @@ public async Task BulkSetUnusedAsync_PartialSuccess_ReturnsPartialSuccess() var cmsAuthValues = new CmsAuthValues("cookies", Guid.NewGuid()); #pragma warning disable CS8620 // Argument cannot be used for parameter due to differences in the nullability of reference types. - this.mockApiClient.Setup(client => client.ReclassifyCommunicationAsync(It.IsAny(), cmsAuthValues)) - .ReturnsAsync((ReclassifyCommunicationRequest request, CmsAuthValues authValues) => + this.mockApiClient.Setup(client => client.ReclassifyCommunicationAsync(It.IsAny(), cmsAuthValues, It.IsAny())) + .ReturnsAsync((ReclassifyCommunicationRequest request, CmsAuthValues authValues, CancellationToken cancellationToken) => { if (request.materialId == 1) { @@ -186,7 +186,7 @@ public async Task BulkSetUnusedAsync_ApiThrowsException_ThrowsException() var cmsAuthValues = new CmsAuthValues("cookies", Guid.NewGuid()); - this.mockApiClient.Setup(client => client.ReclassifyCommunicationAsync(It.IsAny(), cmsAuthValues)) + this.mockApiClient.Setup(client => client.ReclassifyCommunicationAsync(It.IsAny(), cmsAuthValues, It.IsAny())) .ThrowsAsync(exception); // Act diff --git a/Cps.Fct.Hk.Ui.Services.Tests/CaseInfoServiceTests.cs b/Cps.Fct.Hk.Ui.Services.Tests/CaseInfoServiceTests.cs index 8de17f7ab..71f1df0e1 100644 --- a/Cps.Fct.Hk.Ui.Services.Tests/CaseInfoServiceTests.cs +++ b/Cps.Fct.Hk.Ui.Services.Tests/CaseInfoServiceTests.cs @@ -7,6 +7,7 @@ namespace Cps.Fct.Hk.Ui.Services.Tests; using Xunit; using Moq; using Microsoft.Extensions.Logging; +using System.Threading; using System.Threading.Tasks; using Cps.Fct.Hk.Ui.Services.Tests.TestUtilities; using DdeiClient.Clients.Interfaces; diff --git a/Cps.Fct.Hk.Ui.Services.Tests/CommunicationServiceTests.cs b/Cps.Fct.Hk.Ui.Services.Tests/CommunicationServiceTests.cs index 19a3b5e2f..65eceb87c 100644 --- a/Cps.Fct.Hk.Ui.Services.Tests/CommunicationServiceTests.cs +++ b/Cps.Fct.Hk.Ui.Services.Tests/CommunicationServiceTests.cs @@ -2862,6 +2862,7 @@ public async Task GetPcdReviewDetailAsync_ShouldPassCancellationToken_ToDownstre // Arrange int caseId = 1234; int pcdId = 5678; + var customCancellationToken = new CancellationTokenSource(TimeSpan.FromSeconds(5)).Token; var cmsAuthValues = new CmsAuthValues( @@ -2878,15 +2879,15 @@ public async Task GetPcdReviewDetailAsync_ShouldPassCancellationToken_ToDownstre var preChargeDecisionOutcome = new ApiClient.PreChargeDecisionOutcome(); this.apiClientMock - .Setup(client => client.GetHistoryEventsAsync(caseId, cmsAuthValues)) + .Setup(client => client.GetHistoryEventsAsync(caseId, cmsAuthValues, It.IsAny())) .ReturnsAsync(historyEvents); this.apiClientMock - .Setup(client => client.GetInitialReviewByHistoryIdAsync(caseId, pcdId, cmsAuthValues, customCancellationToken)) + .Setup(client => client.GetInitialReviewByHistoryIdAsync(caseId, pcdId, cmsAuthValues, It.IsAny())) .ReturnsAsync(pcdAnalysisOutcome); this.apiClientMock - .Setup(client => client.GetPreChargeDecisionByHistoryId(caseId, pcdId + 1, cmsAuthValues)) + .Setup(client => client.GetPreChargeDecisionByHistoryId(caseId, pcdId + 1, cmsAuthValues, It.IsAny())) .ReturnsAsync(preChargeDecisionOutcome); // Act @@ -3261,7 +3262,7 @@ public async Task GetPcdReviewCoreAsync_ShouldPassCancellationToken_ToDownstream // Arrange int caseId = 1234; int pcdId = 5678; - var customCancellationToken = new CancellationTokenSource(TimeSpan.FromSeconds(5)).Token; + var customCancellationToken = new CancellationTokenSource(TimeSpan.FromSeconds(20)).Token; var cmsAuthValues = new CmsAuthValues( "cookies", diff --git a/Cps.Fct.Hk.Ui.Services.Tests/MaterialReclassificationOrchestrationServiceUnitTests.cs b/Cps.Fct.Hk.Ui.Services.Tests/MaterialReclassificationOrchestrationServiceUnitTests.cs index 798115a6a..b63ce96f4 100644 --- a/Cps.Fct.Hk.Ui.Services.Tests/MaterialReclassificationOrchestrationServiceUnitTests.cs +++ b/Cps.Fct.Hk.Ui.Services.Tests/MaterialReclassificationOrchestrationServiceUnitTests.cs @@ -79,7 +79,7 @@ public async Task CompleteReclassificationAsync_ReclassifyingMaterialToStatement .ReturnsAsync(new NoContentResult()); this.mockReclassificationService - .Setup(x => x.ReclassifyCaseMaterialAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + .Setup(x => x.ReclassifyCaseMaterialAsync(It.IsAny(), It.IsAny(), It.IsAny())) .ReturnsAsync(It.IsAny()); this.mockCommunicationService @@ -136,7 +136,7 @@ public async Task CompleteReclassificationAsync_ReclassifyingMaterialToStatement log.Message != null && log.Message.Contains($"{LoggingConstants.HskUiLogPrefix} executing reclassification for MaterialId: [{materialId}]")); this.mockWitnessService.Verify(x => x.AddWitnessAsync(It.IsAny(), caseId, It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), Times.Once()); - this.mockReclassificationService.Verify(x => x.ReclassifyCaseMaterialAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), Times.Once()); + this.mockReclassificationService.Verify(x => x.ReclassifyCaseMaterialAsync(It.IsAny(), It.IsAny(), It.IsAny()), Times.Once()); this.mockActionPlanService.Verify(x => x.AddCaseActionPlanAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), Times.Once()); this.mockCommunicationService.Verify(x => x.RenameMaterialAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), Times.Never()); @@ -178,7 +178,7 @@ public async Task CompleteReclassificationAsync_ReclassifyingMaterialToStatement .ThrowsAsync(exception); this.mockReclassificationService - .Setup(x => x.ReclassifyCaseMaterialAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + .Setup(x => x.ReclassifyCaseMaterialAsync(It.IsAny(), It.IsAny(), It.IsAny())) .ReturnsAsync(It.IsAny()); this.mockCommunicationService @@ -231,7 +231,7 @@ public async Task CompleteReclassificationAsync_ReclassifyingMaterialToStatement log.Message != null && log.Message.Contains($"{LoggingConstants.HskUiLogPrefix} executing reclassification for MaterialId: [{materialId}]")); this.mockWitnessService.Verify(x => x.AddWitnessAsync(It.IsAny(), caseId, It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), Times.Once()); - this.mockReclassificationService.Verify(x => x.ReclassifyCaseMaterialAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), Times.Once()); + this.mockReclassificationService.Verify(x => x.ReclassifyCaseMaterialAsync(It.IsAny(), It.IsAny(), It.IsAny()), Times.Once()); this.mockActionPlanService.Verify(x => x.AddCaseActionPlanAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), Times.Once()); this.mockCommunicationService.Verify(x => x.RenameMaterialAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), Times.Never()); @@ -272,7 +272,7 @@ public async Task CompleteReclassificationAsync_ReclassifyingMaterialToStatement .ThrowsAsync(exception); this.mockReclassificationService - .Setup(x => x.ReclassifyCaseMaterialAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + .Setup(x => x.ReclassifyCaseMaterialAsync(It.IsAny(), It.IsAny(), It.IsAny())) .ThrowsAsync(exception); this.mockCommunicationService @@ -325,7 +325,7 @@ public async Task CompleteReclassificationAsync_ReclassifyingMaterialToStatement log.Message != null && log.Message.Contains($"{LoggingConstants.HskUiLogPrefix} reclassification failed for MaterialId: [{materialId}]")); this.mockWitnessService.Verify(x => x.AddWitnessAsync(It.IsAny(), caseId, It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), Times.Once()); - this.mockReclassificationService.Verify(x => x.ReclassifyCaseMaterialAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), Times.Once()); + this.mockReclassificationService.Verify(x => x.ReclassifyCaseMaterialAsync(It.IsAny(), It.IsAny(), It.IsAny()), Times.Once()); this.mockActionPlanService.Verify(x => x.AddCaseActionPlanAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), Times.Once()); this.mockCommunicationService.Verify(x => x.RenameMaterialAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), Times.Never()); @@ -364,7 +364,7 @@ public async Task CompleteReclassificationAsync_ReclassifyingMaterialToOther_All .ReturnsAsync(new NoContentResult()); this.mockReclassificationService - .Setup(x => x.ReclassifyCaseMaterialAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + .Setup(x => x.ReclassifyCaseMaterialAsync(It.IsAny(), It.IsAny(), It.IsAny())) .ReturnsAsync(It.IsAny()); this.mockCommunicationService @@ -408,7 +408,7 @@ public async Task CompleteReclassificationAsync_ReclassifyingMaterialToOther_All log.Message != null && log.Message.Contains($"{LoggingConstants.HskUiLogPrefix} executing reclassification for MaterialId: [{materialId}]")); this.mockWitnessService.Verify(x => x.AddWitnessAsync(It.IsAny(), caseId, It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), Times.Never()); - this.mockReclassificationService.Verify(x => x.ReclassifyCaseMaterialAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), Times.Once()); + this.mockReclassificationService.Verify(x => x.ReclassifyCaseMaterialAsync(It.IsAny(), It.IsAny(), It.IsAny()), Times.Once()); this.mockActionPlanService.Verify(x => x.AddCaseActionPlanAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), Times.Never()); this.mockCommunicationService.Verify(x => x.RenameMaterialAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), Times.Once()); diff --git a/Cps.Fct.Hk.Ui.Services/BulkSetUnusedService.cs b/Cps.Fct.Hk.Ui.Services/BulkSetUnusedService.cs index 9bfdf05d4..66a4daccd 100644 --- a/Cps.Fct.Hk.Ui.Services/BulkSetUnusedService.cs +++ b/Cps.Fct.Hk.Ui.Services/BulkSetUnusedService.cs @@ -55,7 +55,7 @@ public static string SanitizeSubject(string subject) } /// - public async Task BulkSetUnusedAsync(int caseId, CmsAuthValues cmsAuthValues, IReadOnlyCollection bulkSetUnusedRequests) + public async Task BulkSetUnusedAsync(int caseId, CmsAuthValues cmsAuthValues, IReadOnlyCollection bulkSetUnusedRequests, CancellationToken cancellationToken = default) { string caseIdString = caseId.ToString(CultureInfo.InvariantCulture); var reclassifiedMaterials = new ConcurrentDictionary(); @@ -84,7 +84,7 @@ public async Task BulkSetUnusedAsync(int caseId, CmsAuthV try { - ReclassificationResponse response = await this.apiClient.ReclassifyCommunicationAsync(reclassifyCommunicationRequest, cmsAuthValues).ConfigureAwait(false); + ReclassificationResponse response = await this.apiClient.ReclassifyCommunicationAsync(reclassifyCommunicationRequest, cmsAuthValues, cancellationToken); if (response.ReclassifyCommunication.Id.Equals(bulkSetUnusedRequest.materialId)) { diff --git a/Cps.Fct.Hk.Ui.Services/CaseActionPlanService.cs b/Cps.Fct.Hk.Ui.Services/CaseActionPlanService.cs index a097fde59..337cd067b 100644 --- a/Cps.Fct.Hk.Ui.Services/CaseActionPlanService.cs +++ b/Cps.Fct.Hk.Ui.Services/CaseActionPlanService.cs @@ -30,11 +30,11 @@ public class CaseActionPlanService( private readonly IMasterDataServiceClient apiClient = apiClient; /// - public async Task AddCaseActionPlanAsync(string urn, int caseId, AddCaseActionPlanRequest addCaseActionPlanRequest, CmsAuthValues cmsAuthValues) + public async Task AddCaseActionPlanAsync(string urn, int caseId, AddCaseActionPlanRequest addCaseActionPlanRequest, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default) { string caseIdString = caseId.ToString(CultureInfo.InvariantCulture); - var checkCaeLockStatus = await this.caseLockService.CheckCaseLockAsync(caseId, cmsAuthValues).ConfigureAwait(false); + var checkCaeLockStatus = await this.caseLockService.CheckCaseLockAsync(caseId, cmsAuthValues, cancellationToken).ConfigureAwait(false); if (checkCaeLockStatus.IsLocked && !checkCaeLockStatus.IsLockedByCurrentUser) { throw new CaseLockedException($"{LoggingConstants.HskUiLogPrefix} Attempting to add case action plan for caseId [{caseIdString}] failed as case is locked by [{checkCaeLockStatus.LockedByUser}]."); @@ -78,7 +78,7 @@ public async Task AddCaseActionPlanAsync(string urn, int caseId defendantId: addCaseActionPlanRequest.defendantId, steps: mappedSteps!); - NoContentResult addCaseActionPlanResponse = await this.apiClient.AddCaseActionPlanAsync(caseId, request, cmsAuthValues).ConfigureAwait(false); + NoContentResult addCaseActionPlanResponse = await this.apiClient.AddCaseActionPlanAsync(caseId, request, cmsAuthValues, cancellationToken).ConfigureAwait(false); this.logger.LogInformation(LoggingConstants.AddCaseActionPlanOperationSuccess, LoggingConstants.HskUiLogPrefix, caseIdString); diff --git a/Cps.Fct.Hk.Ui.Services/CaseDefendantsService.cs b/Cps.Fct.Hk.Ui.Services/CaseDefendantsService.cs index 00dbbf6cb..b44db8b97 100644 --- a/Cps.Fct.Hk.Ui.Services/CaseDefendantsService.cs +++ b/Cps.Fct.Hk.Ui.Services/CaseDefendantsService.cs @@ -27,7 +27,7 @@ public class CaseDefendantsService( private readonly IMasterDataServiceClient apiClient = apiClient; /// - public async Task GetCaseDefendantsAsync(int caseId, CmsAuthValues cmsAuthValues) + public async Task GetCaseDefendantsAsync(int caseId, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default) { string caseIdString = caseId.ToString(CultureInfo.InvariantCulture); @@ -37,7 +37,7 @@ public async Task GetCaseDefendantsAsync(int caseId, CmsAuth var request = new ListCaseDefendantsRequest(caseId, Guid.NewGuid()); - DefendantsResponse? defendants = await this.apiClient.GetCaseDefendantsAsync(request, cmsAuthValues).ConfigureAwait(false); + DefendantsResponse? defendants = await this.apiClient.GetCaseDefendantsAsync(request, cmsAuthValues, cancellationToken).ConfigureAwait(false); return defendants ?? throw new InvalidOperationException($"{LoggingConstants.HskUiLogPrefix} No case defendants found for caseId [{caseIdString}]"); } diff --git a/Cps.Fct.Hk.Ui.Services/CaseInfoService.cs b/Cps.Fct.Hk.Ui.Services/CaseInfoService.cs index 6dd32fe98..6a274243c 100644 --- a/Cps.Fct.Hk.Ui.Services/CaseInfoService.cs +++ b/Cps.Fct.Hk.Ui.Services/CaseInfoService.cs @@ -1,10 +1,12 @@ // +// // Copyright (c) The Crown Prosecution Service. All rights reserved. // namespace Cps.Fct.Hk.Ui.Services; using System; +using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Logging; using System.Globalization; @@ -27,7 +29,7 @@ public class CaseInfoService( private readonly IMasterDataServiceClient mdsClient = mdsClient; /// - public async Task GetCaseInfoAsync(int caseId, CmsAuthValues cmsAuthValues) + public async Task GetCaseInfoAsync(int caseId, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default) { string caseIdString = caseId.ToString(CultureInfo.InvariantCulture); @@ -37,7 +39,7 @@ public async Task GetCaseInfoAsync(int caseId, CmsAuthValue var request = new GetCaseSummaryRequest(caseId, Guid.NewGuid()); - CaseSummaryResponse? caseSummary = await this.mdsClient.GetCaseSummaryAsync(request, cmsAuthValues).ConfigureAwait(false); + CaseSummaryResponse? caseSummary = await this.mdsClient.GetCaseSummaryAsync(request, cmsAuthValues, cancellationToken); return caseSummary ?? throw new InvalidOperationException($"{LoggingConstants.HskUiLogPrefix} No case summary found for caseId [{caseIdString}]"); } diff --git a/Cps.Fct.Hk.Ui.Services/CaseLockService.cs b/Cps.Fct.Hk.Ui.Services/CaseLockService.cs index b54fbf25f..c0747f352 100644 --- a/Cps.Fct.Hk.Ui.Services/CaseLockService.cs +++ b/Cps.Fct.Hk.Ui.Services/CaseLockService.cs @@ -27,7 +27,7 @@ public class CaseLockService( private readonly IMasterDataServiceClient apiClient = apiClient; /// - public async Task CheckCaseLockAsync(int caseId, CmsAuthValues cmsAuthValues) + public async Task CheckCaseLockAsync(int caseId, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default) { string caseIdString = caseId.ToString(CultureInfo.InvariantCulture); @@ -35,7 +35,7 @@ public async Task CheckCaseLockAsync(int caseId, CmsAuth { this.logger.LogInformation($"{LoggingConstants.HskUiLogPrefix} Attempting to check case lock status for caseId [{caseIdString}]"); - var checkCaseLockStatusResponse = await this.apiClient.CheckCaseLockAsync(caseId, cmsAuthValues).ConfigureAwait(false); + var checkCaseLockStatusResponse = await this.apiClient.CheckCaseLockAsync(caseId, cmsAuthValues, cancellationToken); this.logger.LogInformation(LoggingConstants.CheckCaseLockOperationSuccess, LoggingConstants.HskUiLogPrefix, caseIdString); diff --git a/Cps.Fct.Hk.Ui.Services/CaseMaterialService.cs b/Cps.Fct.Hk.Ui.Services/CaseMaterialService.cs index e4442e6a2..7381836c7 100644 --- a/Cps.Fct.Hk.Ui.Services/CaseMaterialService.cs +++ b/Cps.Fct.Hk.Ui.Services/CaseMaterialService.cs @@ -356,15 +356,15 @@ public List MapUnusedMaterialsToCaseMaterials(UnusedMaterialsRespo UsedExhibitsResponse, UsedMgFormsResponse, UsedOtherMaterialsResponse, - ExhibitProducersResponse)> RetrieveCaseMaterialsAsync(int caseId, CmsAuthValues cmsAuthValues) + ExhibitProducersResponse)> RetrieveCaseMaterialsAsync(int caseId, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default) { - var communicationsTask = Task.Run(() => this.GetCommunicationsAsync(caseId, cmsAuthValues)); - var unusedMaterialsTask = Task.Run(() => this.GetUnusedMaterialsAsync(caseId, cmsAuthValues)); - var usedStatementsTask = Task.Run(() => this.GetUsedStatementsAsync(caseId, cmsAuthValues)); - var usedExhibitsTask = Task.Run(() => this.GetUsedExhibitsAsync(caseId, cmsAuthValues)); - var usedMgFormsTask = Task.Run(() => this.GetUsedMgFormsAsync(caseId, cmsAuthValues)); - var usedOtherMaterialsTask = Task.Run(() => this.GetUsedOtherMaterialsAsync(caseId, cmsAuthValues)); - var exhibitProducerTask = Task.Run(() => this.GetExhibitProducersAsync(caseId, cmsAuthValues)); + var communicationsTask = this.GetCommunicationsAsync(caseId, cmsAuthValues, cancellationToken); + var unusedMaterialsTask = this.GetUnusedMaterialsAsync(caseId, cmsAuthValues, cancellationToken); + var usedStatementsTask = this.GetUsedStatementsAsync(caseId, cmsAuthValues, cancellationToken); + var usedExhibitsTask = this.GetUsedExhibitsAsync(caseId, cmsAuthValues, cancellationToken); + var usedMgFormsTask = this.GetUsedMgFormsAsync(caseId, cmsAuthValues, cancellationToken); + var usedOtherMaterialsTask = this.GetUsedOtherMaterialsAsync(caseId, cmsAuthValues, cancellationToken); + var exhibitProducerTask = this.GetExhibitProducersAsync(caseId, cmsAuthValues, cancellationToken); await Task .WhenAll( @@ -392,13 +392,14 @@ await usedOtherMaterialsTask.ConfigureAwait(false), /// /// The ID of the case. /// The authorization values. + /// The cancellation token to cancel this operation. /// A task that represents the asynchronous operation. The task result contains a collection of objects. - public async Task> GetCommunicationsAsync(int caseId, CmsAuthValues cmsAuthValues) + public async Task> GetCommunicationsAsync(int caseId, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default) { try { this.logger.LogInformation($"{LoggingConstants.HskUiLogPrefix} Retrieving communications for caseId [{caseId}]..."); - return await this.communicationService.GetCommunicationsAsync(caseId, cmsAuthValues).ConfigureAwait(false); + return await this.communicationService.GetCommunicationsAsync(caseId, cmsAuthValues, cancellationToken).ConfigureAwait(false); } catch (Exception ex) { @@ -413,7 +414,7 @@ public async Task> GetCommunicationsAsync(int /// The ID of the case. /// The authorization values. /// A task that represents the asynchronous operation. The task result contains the . - public async Task GetUnusedMaterialsAsync(int caseId, CmsAuthValues cmsAuthValues) + public async Task GetUnusedMaterialsAsync(int caseId, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default) { try { @@ -432,13 +433,14 @@ public async Task GetUnusedMaterialsAsync(int caseId, C /// /// The ID of the case. /// The authorization values. + /// The cancellation token. /// A task that represents the asynchronous operation. The task result contains the . - public async Task GetUsedStatementsAsync(int caseId, CmsAuthValues cmsAuthValues) + public async Task GetUsedStatementsAsync(int caseId, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default) { try { this.logger.LogInformation($"{LoggingConstants.HskUiLogPrefix} Retrieving used statements for caseId [{caseId}]..."); - return await this.communicationService.GetUsedStatementsAsync(caseId, cmsAuthValues).ConfigureAwait(false); + return await this.communicationService.GetUsedStatementsAsync(caseId, cmsAuthValues, cancellationToken).ConfigureAwait(false); } catch (Exception ex) { @@ -452,13 +454,14 @@ public async Task GetUsedStatementsAsync(int caseId, Cms /// /// The ID of the case. /// The authorization values. + /// The cancellation token. /// A task that represents the asynchronous operation. The task result contains the . - public async Task GetUsedExhibitsAsync(int caseId, CmsAuthValues cmsAuthValues) + public async Task GetUsedExhibitsAsync(int caseId, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default) { try { this.logger.LogInformation($"{LoggingConstants.HskUiLogPrefix} Retrieving used exhibits for caseId [{caseId}]..."); - return await this.communicationService.GetUsedExhibitsAsync(caseId, cmsAuthValues).ConfigureAwait(false); + return await this.communicationService.GetUsedExhibitsAsync(caseId, cmsAuthValues, cancellationToken).ConfigureAwait(false); } catch (Exception ex) { @@ -472,8 +475,9 @@ public async Task GetUsedExhibitsAsync(int caseId, CmsAuth /// /// The ID of the case. /// The authorization values. + /// The cancellation token. /// A task that represents the asynchronous operation. The task result contains the . - public async Task GetUsedMgFormsAsync(int caseId, CmsAuthValues cmsAuthValues) + public async Task GetUsedMgFormsAsync(int caseId, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default) { try { @@ -492,13 +496,14 @@ public async Task GetUsedMgFormsAsync(int caseId, CmsAuthVa /// /// The ID of the case. /// The authorization values. + /// The cancellation token. /// A task that represents the asynchronous operation. The task result contains the . - public async Task GetUsedOtherMaterialsAsync(int caseId, CmsAuthValues cmsAuthValues) + public async Task GetUsedOtherMaterialsAsync(int caseId, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default) { try { this.logger.LogInformation($"{LoggingConstants.HskUiLogPrefix} Retrieving used other materials for caseId [{caseId}]..."); - return await this.communicationService.GetUsedOtherMaterialsAsync(caseId, cmsAuthValues).ConfigureAwait(false); + return await this.communicationService.GetUsedOtherMaterialsAsync(caseId, cmsAuthValues, cancellationToken).ConfigureAwait(false); } catch (Exception ex) { @@ -571,14 +576,15 @@ public void AddCaseMaterials(List allCaseMaterials, IEnumerable /// Asynchronously retrieves exhibit producers based on the case ID and authorization values. /// /// The ID of the case. - /// The authorization values.t + /// The authorization values. + /// The cancellation token. /// A task that represents the asynchronous operation. The task result contains the . - public async Task GetExhibitProducersAsync(int caseId, CmsAuthValues cmsAuthValues) + public async Task GetExhibitProducersAsync(int caseId, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default) { try { this.logger.LogInformation($"{LoggingConstants.HskUiLogPrefix} Retrieving exhibit producers for caseId [{caseId}]..."); - return await this.communicationService.GetExhibitProducersAsync(caseId, cmsAuthValues).ConfigureAwait(false); + return await this.communicationService.GetExhibitProducersAsync(caseId, cmsAuthValues, cancellationToken).ConfigureAwait(false); } catch (Exception ex) { diff --git a/Cps.Fct.Hk.Ui.Services/CommunicationService.cs b/Cps.Fct.Hk.Ui.Services/CommunicationService.cs index 32b67d5a3..54bf37ded 100644 --- a/Cps.Fct.Hk.Ui.Services/CommunicationService.cs +++ b/Cps.Fct.Hk.Ui.Services/CommunicationService.cs @@ -38,7 +38,7 @@ public class CommunicationService( private readonly ICommunicationMapper communicationMapper = communicationMapper; /// - public async Task> GetCommunicationsAsync(int caseId, CmsAuthValues cmsAuthValues) + public async Task> GetCommunicationsAsync(int caseId, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default) { string caseIdString = caseId.ToString(CultureInfo.InvariantCulture); @@ -47,7 +47,7 @@ public async Task> GetCommunicationsAsync(int this.logger.LogInformation($"{LoggingConstants.HskUiLogPrefix} Fetching inbox communications for caseId [{caseIdString}] ..."); var request = new ListCommunicationsHkRequest(caseId, Guid.NewGuid()); - IReadOnlyCollection communications = await this.apiClient.ListCommunicationsHkAsync(request, cmsAuthValues).ConfigureAwait(false); + IReadOnlyCollection communications = await this.apiClient.ListCommunicationsHkAsync(request, cmsAuthValues, cancellationToken).ConfigureAwait(false); // Map the document type to each communication var mappedCommunications = communications.Select(c => @@ -83,7 +83,7 @@ public async Task> GetCommunicationsAsync(int } /// - public async Task GetUsedStatementsAsync(int caseId, CmsAuthValues cmsAuthValues) + public async Task GetUsedStatementsAsync(int caseId, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default) { string caseIdString = caseId.ToString(CultureInfo.InvariantCulture); @@ -92,7 +92,7 @@ public async Task GetUsedStatementsAsync(int caseId, Cms this.logger.LogInformation($"{LoggingConstants.HskUiLogPrefix} Fetching used statements for caseId [{caseIdString}] ..."); var request = new GetUsedStatementsRequest(caseId, Guid.NewGuid()); - UsedStatementsResponse usedStatements = await this.apiClient.GetUsedStatementsAsync(request, cmsAuthValues).ConfigureAwait(false); + UsedStatementsResponse usedStatements = await this.apiClient.GetUsedStatementsAsync(request, cmsAuthValues, cancellationToken).ConfigureAwait(false); return usedStatements; } @@ -105,7 +105,7 @@ public async Task GetUsedStatementsAsync(int caseId, Cms } /// - public async Task GetUsedExhibitsAsync(int caseId, CmsAuthValues cmsAuthValues) + public async Task GetUsedExhibitsAsync(int caseId, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default) { string caseIdString = caseId.ToString(CultureInfo.InvariantCulture); @@ -114,7 +114,7 @@ public async Task GetUsedExhibitsAsync(int caseId, CmsAuth this.logger.LogInformation($"{LoggingConstants.HskUiLogPrefix} Fetching used exhibits for caseId [{caseIdString}] ..."); var request = new GetUsedExhibitsRequest(caseId, Guid.NewGuid()); - UsedExhibitsResponse usedExhibits = await this.apiClient.GetUsedExhibitsAsync(request, cmsAuthValues).ConfigureAwait(false); + UsedExhibitsResponse usedExhibits = await this.apiClient.GetUsedExhibitsAsync(request, cmsAuthValues, cancellationToken).ConfigureAwait(false); return usedExhibits; } @@ -127,16 +127,17 @@ public async Task GetUsedExhibitsAsync(int caseId, CmsAuth } /// - public async Task GetUsedMgFormsAsync(int caseId, CmsAuthValues cmsAuthValues) + public async Task GetUsedMgFormsAsync(int caseId, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default) { string caseIdString = caseId.ToString(CultureInfo.InvariantCulture); try { + this.logger.LogInformation($"{LoggingConstants.HskUiLogPrefix} Fetching used MG forms for caseId [{caseIdString}] ..."); var request = new GetUsedMgFormsRequest(caseId, Guid.NewGuid()); - UsedMgFormsResponse usedMgForms = await this.apiClient.GetUsedMgFormsAsync(request, cmsAuthValues).ConfigureAwait(false); + UsedMgFormsResponse usedMgForms = await this.apiClient.GetUsedMgFormsAsync(request, cmsAuthValues, cancellationToken).ConfigureAwait(false); return usedMgForms; } @@ -149,7 +150,7 @@ public async Task GetUsedMgFormsAsync(int caseId, CmsAuthVa } /// - public async Task GetUsedOtherMaterialsAsync(int caseId, CmsAuthValues cmsAuthValues) + public async Task GetUsedOtherMaterialsAsync(int caseId, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default) { string caseIdString = caseId.ToString(CultureInfo.InvariantCulture); @@ -158,7 +159,7 @@ public async Task GetUsedOtherMaterialsAsync(int cas this.logger.LogInformation($"{LoggingConstants.HskUiLogPrefix} Fetching used other materials for caseId [{caseIdString}] ..."); var request = new GetUsedOtherMaterialsRequest(caseId, Guid.NewGuid()); - UsedOtherMaterialsResponse usedOtherMaterials = await this.apiClient.GetUsedOtherMaterialsAsync(request, cmsAuthValues).ConfigureAwait(false); + UsedOtherMaterialsResponse usedOtherMaterials = await this.apiClient.GetUsedOtherMaterialsAsync(request, cmsAuthValues, cancellationToken); return usedOtherMaterials; } @@ -171,7 +172,7 @@ public async Task GetUsedOtherMaterialsAsync(int cas } /// - public async Task GetUnusedMaterialsAsync(int caseId, CmsAuthValues cmsAuthValues) + public async Task GetUnusedMaterialsAsync(int caseId, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default) { string caseIdString = caseId.ToString(CultureInfo.InvariantCulture); @@ -180,7 +181,7 @@ public async Task GetUnusedMaterialsAsync(int caseId, C this.logger.LogInformation($"{LoggingConstants.HskUiLogPrefix} Fetching unused materials for caseId [{caseIdString}] ..."); var request = new GetUnusedMaterialsRequest(caseId, Guid.NewGuid()); - UnusedMaterialsResponse unusedMaterials = await this.apiClient.GetUnusedMaterialsAsync(request, cmsAuthValues).ConfigureAwait(false); + UnusedMaterialsResponse unusedMaterials = await this.apiClient.GetUnusedMaterialsAsync(request, cmsAuthValues, cancellationToken); return unusedMaterials; } @@ -193,7 +194,7 @@ public async Task GetUnusedMaterialsAsync(int caseId, C } /// - public async Task GetAttachmentsAsync(int communicationId, string communicationSubject, CmsAuthValues cmsAuthValues) + public async Task GetAttachmentsAsync(int communicationId, string communicationSubject, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default) { string communicationIdString = communicationId.ToString(CultureInfo.InvariantCulture); @@ -202,7 +203,7 @@ public async Task GetAttachmentsAsync(int communicationId, this.logger.LogInformation($"{LoggingConstants.HskUiLogPrefix} Fetching attachments for communicationId [{communicationIdString}] ..."); var request = new GetAttachmentsRequest(communicationId, Guid.NewGuid()); - AttachmentsResponse attachments = await this.apiClient.GetAttachmentsAsync(request, cmsAuthValues).ConfigureAwait(false); + AttachmentsResponse attachments = await this.apiClient.GetAttachmentsAsync(request, cmsAuthValues, cancellationToken).ConfigureAwait(false); return attachments; } @@ -215,9 +216,7 @@ public async Task GetAttachmentsAsync(int communicationId, } /// - public async Task> RetrieveAllAttachmentsAsync( - IReadOnlyCollection communications, - CmsAuthValues cmsAuthValues) + public async Task> RetrieveAllAttachmentsAsync(IReadOnlyCollection communications, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default) { try { @@ -228,7 +227,7 @@ public async Task> RetrieveAllAttachmentsAsync( if (communication.HasAttachments) { // Retrieve attachments for the current communication - AttachmentsResponse currentAttachments = await this.GetAttachmentsAsync(communication.Id, communication.Subject, cmsAuthValues).ConfigureAwait(false); + AttachmentsResponse currentAttachments = await this.GetAttachmentsAsync(communication.Id, communication.Subject, cmsAuthValues, cancellationToken).ConfigureAwait(false); if (currentAttachments?.Attachments != null) { @@ -282,7 +281,7 @@ public List MapAttachmentsToCommunications(List attac } /// - public async Task GetCaseMaterialLinkAsync(int caseId, int materialId, CmsAuthValues cmsAuthValues) + public async Task GetCaseMaterialLinkAsync(int caseId, int materialId, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default) { try { @@ -290,12 +289,12 @@ IActionResult GetNotFoundResult() => new NotFoundObjectResult($"{LoggingConstants.HskUiLogPrefix} No case material document found for materialId [{materialId}]"); // Fire off all tasks concurrently - Task> communicationsTask = this.GetCommunicationsAsync(caseId, cmsAuthValues); - Task unusedMaterialsTask = this.GetUnusedMaterialsAsync(caseId, cmsAuthValues); - Task usedStatementsTask = this.GetUsedStatementsAsync(caseId, cmsAuthValues); - Task usedExhibitsTask = this.GetUsedExhibitsAsync(caseId, cmsAuthValues); - Task usedMgFormsTask = this.GetUsedMgFormsAsync(caseId, cmsAuthValues); - Task usedOtherMaterialsTask = this.GetUsedOtherMaterialsAsync(caseId, cmsAuthValues); + Task> communicationsTask = this.GetCommunicationsAsync(caseId, cmsAuthValues, cancellationToken); + Task unusedMaterialsTask = this.GetUnusedMaterialsAsync(caseId, cmsAuthValues, cancellationToken); + Task usedStatementsTask = this.GetUsedStatementsAsync(caseId, cmsAuthValues, cancellationToken); + Task usedExhibitsTask = this.GetUsedExhibitsAsync(caseId, cmsAuthValues, cancellationToken); + Task usedMgFormsTask = this.GetUsedMgFormsAsync(caseId, cmsAuthValues, cancellationToken); + Task usedOtherMaterialsTask = this.GetUsedOtherMaterialsAsync(caseId, cmsAuthValues, cancellationToken); await Task .WhenAll( @@ -363,7 +362,7 @@ await Task } /// - public async Task GetExhibitProducersAsync(int caseId, CmsAuthValues cmsAuthValues) + public async Task GetExhibitProducersAsync(int caseId, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default) { string caseIdString = caseId.ToString(CultureInfo.InvariantCulture); @@ -373,7 +372,7 @@ public async Task GetExhibitProducersAsync(int caseId, var request = new GetExhibitProducersRequest(caseId, Guid.NewGuid()); - ExhibitProducersResponse? producers = await this.apiClient.GetExhibitProducersAsync(request, cmsAuthValues).ConfigureAwait(false); + ExhibitProducersResponse? producers = await this.apiClient.GetExhibitProducersAsync(request, cmsAuthValues, cancellationToken).ConfigureAwait(false); return producers; } @@ -386,14 +385,14 @@ public async Task GetExhibitProducersAsync(int caseId, } /// - public async Task RenameMaterialAsync(int caseId, int materialId, string subject, CmsAuthValues cmsAuthValues, Guid correspondenceId = default) + public async Task RenameMaterialAsync(int caseId, int materialId, string subject, CmsAuthValues cmsAuthValues, Guid correspondenceId = default, CancellationToken cancellationToken = default) { try { this.logger.LogInformation($"{LoggingConstants.HskUiLogPrefix} Attempting to rename material with materialId [{materialId}]"); var request = new RenameMaterialRequest(correspondenceId == default ? Guid.NewGuid() : correspondenceId, materialId, subject); - RenameMaterialResponse renameMaterialResponse = await this.apiClient.RenameMaterialAsync(request, cmsAuthValues).ConfigureAwait(false); + RenameMaterialResponse renameMaterialResponse = await this.apiClient.RenameMaterialAsync(request, cmsAuthValues, cancellationToken); this.logger.LogInformation(LoggingConstants.RenameMaterialOperationSuccess, LoggingConstants.HskUiLogPrefix, caseId, materialId); return renameMaterialResponse; @@ -407,7 +406,7 @@ public async Task RenameMaterialAsync(int caseId, int ma } /// - public async Task> GetPcdRequestCore(int caseId, CmsAuthValues cmsAuthValues) + public async Task> GetPcdRequestCore(int caseId, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default) { string caseIdString = caseId.ToString(CultureInfo.InvariantCulture); @@ -417,7 +416,7 @@ public async Task> GetPcdRequestCore(int cas Guid correlationId = cmsAuthValues.CorrelationId == Guid.Empty ? Guid.NewGuid() : cmsAuthValues.CorrelationId; var request = new GetPcdRequestsCoreRequest(caseId, correlationId); - IReadOnlyCollection unusedMaterials = await this.apiClient.GetPcdRequestCoreAsync(request, cmsAuthValues).ConfigureAwait(false); + IReadOnlyCollection unusedMaterials = await this.apiClient.GetPcdRequestCoreAsync(request, cmsAuthValues, cancellationToken).ConfigureAwait(false); return unusedMaterials; } @@ -430,7 +429,7 @@ public async Task> GetPcdRequestCore(int cas } /// - public async Task GetPcdRequestByPcdIdAsync(int caseId, int pcdId, CmsAuthValues cmsAuthValues) + public async Task GetPcdRequestByPcdIdAsync(int caseId, int pcdId, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default) { string caseIdString = caseId.ToString(CultureInfo.InvariantCulture); @@ -439,7 +438,7 @@ public async Task GetPcdRequestByPcdIdAsync(int caseId, int pcdId this.logger.LogInformation($"{LoggingConstants.HskUiLogPrefix} Fetching PCD Request overview for caseId [{caseIdString}] and PCD ID [{pcdId}]."); Guid correlationId = cmsAuthValues.CorrelationId == Guid.Empty ? Guid.NewGuid() : cmsAuthValues.CorrelationId; var request = new GetPcdRequestByPcdIdCoreRequest(caseId, pcdId, correlationId); - PcdRequestDto unusedMaterials = await this.apiClient.GetPcdRequestByPcdIdAsync(request, cmsAuthValues).ConfigureAwait(false); + PcdRequestDto unusedMaterials = await this.apiClient.GetPcdRequestByPcdIdAsync(request, cmsAuthValues, cancellationToken).ConfigureAwait(false); return unusedMaterials; } @@ -454,10 +453,11 @@ public async Task GetPcdRequestByPcdIdAsync(int caseId, int pcdId /// public async Task GetPcdReviewDetailAsync(int caseId, int pcdId, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken) { + try { this.logger.LogInformation("{HskUiLogPrefix} Fetching case history events with caseId {CaseId}.", LoggingConstants.HskUiLogPrefix, caseId); - var caseHistoryEvents = await this.apiClient.GetHistoryEventsAsync(caseId, cmsAuthValues).ConfigureAwait(false); + var caseHistoryEvents = await this.apiClient.GetHistoryEventsAsync(caseId, cmsAuthValues, cancellationToken).ConfigureAwait(false); var pcdAnalysisDetails = new PcdReviewDetailResponse(); var associatedPreChargeDecisionEvent = caseHistoryEvents @@ -486,7 +486,7 @@ public async Task GetPcdReviewDetailAsync(int caseId, i if (associatedPreChargeDecisionEvent != null) { this.logger.LogInformation("{HskUiLogPrefix} Fetching pre charge decision outcome for caseId {CaseId} and PCD ID {PcdId}.", LoggingConstants.HskUiLogPrefix, caseId, pcdId); - var preChargeDecisionAnalysisOutcome = await this.apiClient.GetPreChargeDecisionByHistoryId(caseId, (int)associatedPreChargeDecisionEvent.Id, cmsAuthValues).ConfigureAwait(false); + var preChargeDecisionAnalysisOutcome = await this.apiClient.GetPreChargeDecisionByHistoryId(caseId, (int)associatedPreChargeDecisionEvent.Id, cmsAuthValues, cancellationToken).ConfigureAwait(false); pcdAnalysisDetails.PreChargeDecisionOutcome = preChargeDecisionAnalysisOutcome; } @@ -500,12 +500,12 @@ public async Task GetPcdReviewDetailAsync(int caseId, i } /// - public async Task> GetPcdReviewCoreAsync(int caseId, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken) + public async Task> GetPcdReviewCoreAsync(int caseId, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default) { try { this.logger.LogInformation("{HskUiLogPrefix} Fetching case history events with caseId {CaseId}.", LoggingConstants.HskUiLogPrefix, caseId); - var caseHistoryEvents = await this.apiClient.GetHistoryEventsAsync(caseId, cmsAuthValues).ConfigureAwait(false); + var caseHistoryEvents = await this.apiClient.GetHistoryEventsAsync(caseId, cmsAuthValues, cancellationToken).ConfigureAwait(false); var pcdAnalysisDetails = new PcdReviewDetailResponse(); var associatedPreChargeDecisionEvent = caseHistoryEvents @@ -535,14 +535,14 @@ public async Task> GetPcdReviewCor } /// - public async Task DiscardMaterialAsync(int caseId, int materialId, string discardReason, string discardReasonDescription, CmsAuthValues cmsAuthValues, Guid correspondenceId = default) + public async Task DiscardMaterialAsync(int caseId, int materialId, string discardReason, string discardReasonDescription, CmsAuthValues cmsAuthValues, Guid correspondenceId = default, CancellationToken cancellationToken = default) { try { this.logger.LogInformation($"{LoggingConstants.HskUiLogPrefix} Attempting to discard material with materialId [{materialId}]"); var request = new DiscardMaterialRequest(correspondenceId == default ? Guid.NewGuid() : correspondenceId, materialId, discardReason, discardReasonDescription); - DiscardMaterialResponse discardMaterialResponse = await this.apiClient.DiscardMaterialAsync(request, cmsAuthValues).ConfigureAwait(false); + DiscardMaterialResponse discardMaterialResponse = await this.apiClient.DiscardMaterialAsync(request, cmsAuthValues, cancellationToken).ConfigureAwait(false); this.logger.LogInformation(LoggingConstants.DiscardMaterialOperationSuccess, LoggingConstants.HskUiLogPrefix, caseId, materialId); return discardMaterialResponse; @@ -556,14 +556,15 @@ public async Task DiscardMaterialAsync(int caseId, int } /// - public async Task SetMaterialReadStatusAsync(int materialId, MaterialReadStatusType action, CmsAuthValues cmsAuthValues, Guid correspondenceId = default) + public async Task SetMaterialReadStatusAsync(int materialId, MaterialReadStatusType action, CmsAuthValues cmsAuthValues, Guid correspondenceId = default, CancellationToken cancellationToken = default) { + cancellationToken.ThrowIfCancellationRequested(); try { this.logger.LogInformation($"{LoggingConstants.HskUiLogPrefix} Attempting to mark read/unread state of material with material id [{materialId}]"); var request = new SetMaterialReadStatusRequest(correspondenceId == default ? Guid.NewGuid() : correspondenceId, materialId, action); - SetMaterialReadStatusResponse renameMaterialResponse = await this.apiClient.SetMaterialReadStatusAsync(request, cmsAuthValues).ConfigureAwait(false); + SetMaterialReadStatusResponse renameMaterialResponse = await this.apiClient.SetMaterialReadStatusAsync(request, cmsAuthValues, cancellationToken).ConfigureAwait(false); this.logger.LogInformation($"{LoggingConstants.HskUiLogPrefix} Successfully marked material read/unread state of material with material id [{materialId}]"); return renameMaterialResponse; @@ -577,8 +578,9 @@ public async Task SetMaterialReadStatusAsync(int } /// - public async Task UpdateExhibitAsync(int caseId, UpdateExhibitRequest exhibit, CmsAuthValues cmsAuthValues, Guid correspondenceId = default) + public async Task UpdateExhibitAsync(int caseId, UpdateExhibitRequest exhibit, CmsAuthValues cmsAuthValues, Guid correspondenceId = default, CancellationToken cancellationToken = default) { + cancellationToken.ThrowIfCancellationRequested(); try { this.logger.LogInformation($"{LoggingConstants.HskUiLogPrefix} Attempting to update exhibit with materialId [{exhibit.MaterialId}]"); @@ -595,7 +597,7 @@ public async Task UpdateExhibitAsync(int caseId, UpdateEx exhibit.NewProducer, exhibit.ExistingProducerOrWitnessId); - UpdateExhibitResponse response = await this.apiClient.UpdateExhibitAsync(request, cmsAuthValues).ConfigureAwait(false); + UpdateExhibitResponse response = await this.apiClient.UpdateExhibitAsync(request, cmsAuthValues, cancellationToken).ConfigureAwait(false); this.logger.LogInformation(LoggingConstants.UpdateExhibitOperationSuccess, LoggingConstants.HskUiLogPrefix, caseId, exhibit.MaterialId); return response; @@ -609,10 +611,11 @@ public async Task UpdateExhibitAsync(int caseId, UpdateEx } /// - public async Task UpdateStatementAsync(int caseId, UpdateStatementRequest statement, CmsAuthValues cmsAuthValues, Guid correspondenceId = default) + public async Task UpdateStatementAsync(int caseId, UpdateStatementRequest statement, CmsAuthValues cmsAuthValues, Guid correspondenceId = default, CancellationToken cancellationToken = default) { try { + cancellationToken.ThrowIfCancellationRequested(); this.logger.LogInformation($"{LoggingConstants.HskUiLogPrefix} Attempting to update statement with materialId [{statement.MaterialId}]"); var request = new UpdateStatementRequest( @@ -624,7 +627,7 @@ public async Task UpdateStatementAsync(int caseId, Upda statement.StatementNumber, statement.Used); - UpdateStatementResponse response = await this.apiClient.UpdateStatementAsync(request, cmsAuthValues).ConfigureAwait(false); + UpdateStatementResponse response = await this.apiClient.UpdateStatementAsync(request, cmsAuthValues, cancellationToken).ConfigureAwait(false); this.logger.LogInformation(LoggingConstants.UpdateStatementOperationSuccess, LoggingConstants.HskUiLogPrefix, caseId, statement.MaterialId); return response; @@ -638,11 +641,12 @@ public async Task UpdateStatementAsync(int caseId, Upda } /// - public async Task FirstInitialReviewGetCaseHistoryAsync(int caseId, CmsAuthValues cmsAuthValues) + public async Task FirstInitialReviewGetCaseHistoryAsync(int caseId, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default) { + cancellationToken.ThrowIfCancellationRequested(); try { - return await this.apiClient.FirstInitialReviewGetCaseHistoryAsync(caseId, cmsAuthValues).ConfigureAwait(false); + return await this.apiClient.FirstInitialReviewGetCaseHistoryAsync(caseId, cmsAuthValues, cancellationToken).ConfigureAwait(false); } catch (Exception ex) { @@ -654,6 +658,7 @@ public async Task UpdateStatementAsync(int caseId, Upda /// public async Task GetInitialReviewByHistoryIdAsync(int caseId, int historyId, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken) { + cancellationToken.ThrowIfCancellationRequested(); try { return await this.apiClient.GetInitialReviewByHistoryIdAsync(caseId, historyId, cmsAuthValues, cancellationToken); @@ -666,11 +671,12 @@ public async Task UpdateStatementAsync(int caseId, Upda } /// - public async Task> GetHistoryEventsAsync(int caseId, CmsAuthValues cmsAuthValues) + public async Task> GetHistoryEventsAsync(int caseId, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default) { + cancellationToken.ThrowIfCancellationRequested(); try { - return await this.apiClient.GetHistoryEventsAsync(caseId, cmsAuthValues); + return await this.apiClient.GetHistoryEventsAsync(caseId, cmsAuthValues, cancellationToken); } catch (Exception ex) { @@ -680,11 +686,12 @@ public async Task UpdateStatementAsync(int caseId, Upda } /// - public async Task GetOffenceChargeByHistoryIdAsync(int caseId, int historyId, CmsAuthValues cmsAuthValues) + public async Task GetOffenceChargeByHistoryIdAsync(int caseId, int historyId, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default) { + try { - return await this.apiClient.GetOffenceChargeByHistoryIdAsync(caseId, historyId, cmsAuthValues); + return await this.apiClient.GetOffenceChargeByHistoryIdAsync(caseId, historyId, cmsAuthValues, cancellationToken); } catch (Exception ex) { @@ -694,11 +701,12 @@ public async Task UpdateStatementAsync(int caseId, Upda } /// - public async Task GetPreChargeDecisionCaseHistoryEventDetailsAsync(int caseId, CmsAuthValues cmsAuthValues) + public async Task GetPreChargeDecisionCaseHistoryEventDetailsAsync(int caseId, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default) { + try { - return await this.apiClient.GetPreChargeDecisionCaseHistoryEventDetailsAsync(caseId, cmsAuthValues); + return await this.apiClient.GetPreChargeDecisionCaseHistoryEventDetailsAsync(caseId, cmsAuthValues, cancellationToken); } catch (Exception ex) { @@ -708,11 +716,12 @@ public async Task UpdateStatementAsync(int caseId, Upda } /// - public async Task GetPreChargeDecisionByHistoryId(int caseId, int historyId, CmsAuthValues cmsAuthValues) + public async Task GetPreChargeDecisionByHistoryId(int caseId, int historyId, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default) { + try { - return await this.apiClient.GetPreChargeDecisionByHistoryId(caseId, historyId, cmsAuthValues); + return await this.apiClient.GetPreChargeDecisionByHistoryId(caseId, historyId, cmsAuthValues, cancellationToken); } catch (Exception ex) { @@ -722,11 +731,12 @@ public async Task UpdateStatementAsync(int caseId, Upda } /// - public async Task GetPcdReview(int caseId, CmsAuthValues cmsAuthValues) + public async Task GetPcdReview(int caseId, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default) { + try { - return await this.apiClient.GetPcdReview(caseId, cmsAuthValues); + return await this.apiClient.GetPcdReview(caseId, cmsAuthValues, cancellationToken); } catch (Exception ex) { diff --git a/Cps.Fct.Hk.Ui.Services/ConversionService.cs b/Cps.Fct.Hk.Ui.Services/ConversionService.cs index 7d42c9aec..0d668a154 100644 --- a/Cps.Fct.Hk.Ui.Services/ConversionService.cs +++ b/Cps.Fct.Hk.Ui.Services/ConversionService.cs @@ -35,7 +35,7 @@ public class ConversionService(ILogger logger, private const string PasswordProtectedMessage = "The document is password protected."; /// - public async Task SaveDownloadedDocumentToTemporaryStorageAsync(FileStreamResult downloadedDocument) + public async Task SaveDownloadedDocumentToTemporaryStorageAsync(FileStreamResult downloadedDocument, CancellationToken cancellationToken = default) { string? blobContainerName = this.configuration[StorageKeys.BlobServiceContainerNameDocuments] ?? string.Empty; @@ -55,7 +55,7 @@ public async Task SaveDownloadedDocumentToTemporaryStorageAsync(FileStream BlobContainerClient containerClient = this.blobServiceClient.GetBlobContainerClient(blobContainerName); // Ensure the container exists (create if it does not) - await containerClient.CreateIfNotExistsAsync().ConfigureAwait(true); + await containerClient.CreateIfNotExistsAsync(cancellationToken: cancellationToken).ConfigureAwait(true); // Get a reference to the blob (file) with the temporary name BlobClient blobClient = containerClient.GetBlobClient(temporaryFileName); @@ -70,10 +70,10 @@ public async Task SaveDownloadedDocumentToTemporaryStorageAsync(FileStream return false; } - await downloadedDocument.FileStream.CopyToAsync(memoryStream).ConfigureAwait(false); + await downloadedDocument.FileStream.CopyToAsync(memoryStream, cancellationToken).ConfigureAwait(false); memoryStream.Position = 0; // Reset stream position - await blobClient.UploadAsync(memoryStream, overwrite: true).ConfigureAwait(false); + await blobClient.UploadAsync(memoryStream, overwrite: true, cancellationToken).ConfigureAwait(false); } this.logger.LogInformation($"{LoggingConstants.HskUiLogPrefix} Downloaded document saved temporarily to Azure Blob Storage as [{temporaryFileName}]"); @@ -89,10 +89,12 @@ public async Task SaveDownloadedDocumentToTemporaryStorageAsync(FileStream } /// - public async Task ConvertToPdfDocumentAsync(string tmpFileDownloadName, bool firstPageOnly = true) + public async Task ConvertToPdfDocumentAsync(string tmpFileDownloadName, bool firstPageOnly = true, CancellationToken cancellationToken = default) { string? pdfFilePath = null; + cancellationToken.ThrowIfCancellationRequested(); + try { // Determine the content type of the file @@ -102,22 +104,22 @@ public async Task SaveDownloadedDocumentToTemporaryStorageAsync(FileStream { pdfFilePath = contentType switch { - var type when this.IsRasterImage(type) => await ConvertToPdfFilePathAsync(() => this.ConvertRasterImageToPdfDocumentAsync(tmpFileDownloadName)).ConfigureAwait(true), - "application/msword" => await ConvertToPdfFilePathAsync(() => this.ConvertDocToPdfDocumentAsync(tmpFileDownloadName, firstPageOnly)).ConfigureAwait(true), // DOC and DOT files - "application/octet-stream" => await ConvertToPdfFilePathAsync(() => this.ConvertHtmlToPdfDocumentAsync(tmpFileDownloadName)).ConfigureAwait(true), // HTE, HTM and HTML files - "application/pdf" => await ConvertToPdfFilePathAsync(() => this.ConvertPdfToPdfDocumentAsync(tmpFileDownloadName, firstPageOnly)).ConfigureAwait(true), - "application/rtf" => await ConvertToPdfFilePathAsync(() => this.ConvertDocToPdfDocumentAsync(tmpFileDownloadName)).ConfigureAwait(true), - "application/vnd.ms-excel" => await ConvertToPdfFilePathAsync(() => this.ConvertXlsToPdfDocumentAsync(tmpFileDownloadName, firstPageOnly)).ConfigureAwait(true), + var type when this.IsRasterImage(type) => await ConvertToPdfFilePathAsync(() => this.ConvertRasterImageToPdfDocumentAsync(tmpFileDownloadName, cancellationToken)).ConfigureAwait(true), + "application/msword" => await ConvertToPdfFilePathAsync(() => this.ConvertDocToPdfDocumentAsync(tmpFileDownloadName, firstPageOnly, cancellationToken)).ConfigureAwait(true), // DOC and DOT files + "application/octet-stream" => await ConvertToPdfFilePathAsync(() => this.ConvertHtmlToPdfDocumentAsync(tmpFileDownloadName, cancellationToken)).ConfigureAwait(true), // HTE, HTM and HTML files + "application/pdf" => await ConvertToPdfFilePathAsync(() => this.ConvertPdfToPdfDocumentAsync(tmpFileDownloadName, firstPageOnly, cancellationToken)).ConfigureAwait(true), + "application/rtf" => await ConvertToPdfFilePathAsync(() => this.ConvertDocToPdfDocumentAsync(tmpFileDownloadName, cancellationToken:cancellationToken)).ConfigureAwait(true), + "application/vnd.ms-excel" => await ConvertToPdfFilePathAsync(() => this.ConvertXlsToPdfDocumentAsync(tmpFileDownloadName, firstPageOnly, cancellationToken)).ConfigureAwait(true), "application/vnd.ms-excel.sheet.macroEnabled.12" => await ConvertToPdfFilePathAsync(() => this.ConvertXlsToPdfDocumentAsync(tmpFileDownloadName, firstPageOnly)).ConfigureAwait(true), - "application/vnd.ms-word.document.macroEnabled.12" => await ConvertToPdfFilePathAsync(() => this.ConvertDocToPdfDocumentAsync(tmpFileDownloadName, firstPageOnly)).ConfigureAwait(true), - "application/vnd.ms-word.template.macroEnabled.12" => await ConvertToPdfFilePathAsync(() => this.ConvertDocToPdfDocumentAsync(tmpFileDownloadName, firstPageOnly)).ConfigureAwait(true), - "application/vnd.ms-outlook" => await ConvertToPdfFilePathAsync(() => this.ConvertMsgToPdfDocumentAsync(tmpFileDownloadName)).ConfigureAwait(true), - "application/vnd.ms-powerpoint" => await ConvertToPdfFilePathAsync(() => this.ConvertPptToPdfDocumentAsync(tmpFileDownloadName, firstPageOnly)).ConfigureAwait(true), + "application/vnd.ms-word.document.macroEnabled.12" => await ConvertToPdfFilePathAsync(() => this.ConvertDocToPdfDocumentAsync(tmpFileDownloadName, firstPageOnly, cancellationToken:cancellationToken)).ConfigureAwait(true), + "application/vnd.ms-word.template.macroEnabled.12" => await ConvertToPdfFilePathAsync(() => this.ConvertDocToPdfDocumentAsync(tmpFileDownloadName, firstPageOnly, cancellationToken:cancellationToken)).ConfigureAwait(true), + "application/vnd.ms-outlook" => await ConvertToPdfFilePathAsync(() => this.ConvertMsgToPdfDocumentAsync(tmpFileDownloadName, cancellationToken: cancellationToken)).ConfigureAwait(true), + "application/vnd.ms-powerpoint" => await ConvertToPdfFilePathAsync(() => this.ConvertPptToPdfDocumentAsync(tmpFileDownloadName, firstPageOnly,cancellationToken)).ConfigureAwait(true), "application/vnd.openxmlformats-officedocument.presentationml.presentation" => await ConvertToPdfFilePathAsync(() => this.ConvertPptToPdfDocumentAsync(tmpFileDownloadName, firstPageOnly)).ConfigureAwait(true), - "application/vnd.openxmlformats-officedocument.wordprocessingml.document" => await ConvertToPdfFilePathAsync(() => this.ConvertDocToPdfDocumentAsync(tmpFileDownloadName, firstPageOnly)).ConfigureAwait(true), - "application/vnd.openxmlformats-officedocument.wordprocessingml.template" => await ConvertToPdfFilePathAsync(() => this.ConvertDocToPdfDocumentAsync(tmpFileDownloadName, firstPageOnly)).ConfigureAwait(true), + "application/vnd.openxmlformats-officedocument.wordprocessingml.document" => await ConvertToPdfFilePathAsync(() => this.ConvertDocToPdfDocumentAsync(tmpFileDownloadName, firstPageOnly, cancellationToken)).ConfigureAwait(true), + "application/vnd.openxmlformats-officedocument.wordprocessingml.template" => await ConvertToPdfFilePathAsync(() => this.ConvertDocToPdfDocumentAsync(tmpFileDownloadName, firstPageOnly, cancellationToken)).ConfigureAwait(true), "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" => await ConvertToPdfFilePathAsync(() => this.ConvertXlsToPdfDocumentAsync(tmpFileDownloadName, firstPageOnly)).ConfigureAwait(true), - "application/xml" => await ConvertToPdfFilePathAsync(() => this.ConvertXmlToPdfDocumentAsync(tmpFileDownloadName)).ConfigureAwait(true), + "application/xml" => await ConvertToPdfFilePathAsync(() => this.ConvertXmlToPdfDocumentAsync(tmpFileDownloadName, cancellationToken: cancellationToken)).ConfigureAwait(true), "text/csv" => await ConvertToPdfFilePathAsync(() => this.ConvertXlsToPdfDocumentAsync(tmpFileDownloadName, firstPageOnly)).ConfigureAwait(true), "text/plain" => await ConvertToPdfFilePathAsync(() => this.ConvertTxtToPdfDocumentAsync(tmpFileDownloadName)).ConfigureAwait(true), "text/xml" => await ConvertToPdfFilePathAsync(() => this.ConvertXmlToPdfDocumentAsync(tmpFileDownloadName)).ConfigureAwait(true), @@ -142,8 +144,10 @@ var type when this.IsRasterImage(type) => await ConvertToPdfFilePathAsync(() => } /// - public async Task ConvertRasterImageToPdfDocumentAsync(string tmpFileDownloadName) + public async Task ConvertRasterImageToPdfDocumentAsync(string tmpFileDownloadName, CancellationToken cancellationToken = default) { + cancellationToken.ThrowIfCancellationRequested(); + string pdfFileName = $"preview_{tmpFileDownloadName}.pdf"; // PDF blob name string? pdfFileUrl = null; // URL to return after upload @@ -199,8 +203,10 @@ var type when this.IsRasterImage(type) => await ConvertToPdfFilePathAsync(() => } /// - public async Task ConvertPdfToPdfDocumentAsync(string tmpFileDownloadName, bool firstPageOnly = true) + public async Task ConvertPdfToPdfDocumentAsync(string tmpFileDownloadName, bool firstPageOnly = true, CancellationToken cancellationToken = default) { + cancellationToken.ThrowIfCancellationRequested(); + string pdfFileName = $"preview_{tmpFileDownloadName}.pdf"; // PDF output blob name string? pdfFileUrl = null; // URL to return after upload @@ -286,8 +292,10 @@ var type when this.IsRasterImage(type) => await ConvertToPdfFilePathAsync(() => } /// - public async Task ConvertTxtToPdfDocumentAsync(string tmpFileDownloadName) + public async Task ConvertTxtToPdfDocumentAsync(string tmpFileDownloadName, CancellationToken cancellationToken = default) { + cancellationToken.ThrowIfCancellationRequested(); + string pdfFileName = $"preview_{tmpFileDownloadName}.pdf"; // Output PDF blob name string? pdfFileUrl = null; // URL to return after upload @@ -355,8 +363,10 @@ var type when this.IsRasterImage(type) => await ConvertToPdfFilePathAsync(() => } /// - public async Task ConvertHtmlToPdfDocumentAsync(string tmpFileDownloadName) + public async Task ConvertHtmlToPdfDocumentAsync(string tmpFileDownloadName, CancellationToken cancellationToken = default) { + cancellationToken.ThrowIfCancellationRequested(); + string pdfFileName = $"preview_{tmpFileDownloadName}.pdf"; // PDF output blob name string? pdfFileUrl = null; // URL to return after upload @@ -416,8 +426,10 @@ var type when this.IsRasterImage(type) => await ConvertToPdfFilePathAsync(() => } /// - public async Task ConvertDocToPdfDocumentAsync(string tmpFileDownloadName, bool firstPageOnly = true) + public async Task ConvertDocToPdfDocumentAsync(string tmpFileDownloadName, bool firstPageOnly = true, CancellationToken cancellationToken = default) { + cancellationToken.ThrowIfCancellationRequested(); + string pdfFileName = $"preview_{tmpFileDownloadName}.pdf"; // PDF output blob name string? pdfFileUrl = null; // URL to return after upload @@ -446,7 +458,7 @@ var type when this.IsRasterImage(type) => await ConvertToPdfFilePathAsync(() => if (document.PageCount > 0) { // Extract pages, convert to PDF, upload to Blob Storage, and get the PDF URL - pdfFileUrl = await ExtractPagesAndUploadPdfAsync(document, containerClient, pdfFileName, convertAllPages); + pdfFileUrl = await ExtractPagesAndUploadPdfAsync(document, containerClient, pdfFileName, convertAllPages, cancellationToken); string firstPageText = !convertAllPages ? "(first page)" : string.Empty; this.logger.LogInformation( @@ -482,8 +494,9 @@ var type when this.IsRasterImage(type) => await ConvertToPdfFilePathAsync(() => } - private static async Task ExtractPagesAndUploadPdfAsync(Aspose.Words.Document document, BlobContainerClient containerClient, string pdfFileName, bool convertAllPages) + private static async Task ExtractPagesAndUploadPdfAsync(Aspose.Words.Document document, BlobContainerClient containerClient, string pdfFileName, bool convertAllPages, CancellationToken cancellationToken) { + cancellationToken.ThrowIfCancellationRequested(); Aspose.Words.Document wordDocument; if (convertAllPages) { @@ -527,8 +540,9 @@ private static async Task ExtractPagesAndUploadPdfAsync(Aspose.Words.Doc } /// - public async Task ConvertXmlToPdfDocumentAsync(string tmpFileDownloadName) + public async Task ConvertXmlToPdfDocumentAsync(string tmpFileDownloadName, CancellationToken cancellationToken = default) { + cancellationToken.ThrowIfCancellationRequested(); string pdfFileName = $"preview_{tmpFileDownloadName}.pdf"; // PDF output blob name string? pdfFileUrl = null; // URL to return after upload @@ -595,8 +609,9 @@ private static async Task ExtractPagesAndUploadPdfAsync(Aspose.Words.Doc } /// - public async Task ConvertXlsToPdfDocumentAsync(string tmpFileDownloadName, bool firstPageOnly = true) + public async Task ConvertXlsToPdfDocumentAsync(string tmpFileDownloadName, bool firstSheetOnly = true, CancellationToken cancellationToken = default) { + cancellationToken.ThrowIfCancellationRequested(); string pdfFileName = $"preview_{tmpFileDownloadName}.pdf"; // Output PDF blob name string? pdfFileUrl = null; // URL to return after upload @@ -620,7 +635,7 @@ private static async Task ExtractPagesAndUploadPdfAsync(Aspose.Words.Doc // Load the XLS file from the downloaded stream using Aspose.Cells var workbook = new Aspose.Cells.Workbook(xlsStream); - var convertAllSheets = firstPageOnly && workbook.Worksheets.Count > 1; + var convertAllSheets = firstSheetOnly && workbook.Worksheets.Count > 1; // Create a PdfSaveOptions object to customize the PDF save behavior var pdfSaveOptions = new Aspose.Cells.PdfSaveOptions(); @@ -672,8 +687,9 @@ private static async Task ExtractPagesAndUploadPdfAsync(Aspose.Words.Doc } /// - public async Task ConvertMsgToPdfDocumentAsync(string tmpFileDownloadName) + public async Task ConvertMsgToPdfDocumentAsync(string tmpFileDownloadName, CancellationToken cancellationToken = default) { + cancellationToken.ThrowIfCancellationRequested(); string pdfFileName = $"preview_{tmpFileDownloadName}.pdf"; // Output PDF blob name string? pdfFileUrl = null; // URL to return after upload @@ -735,8 +751,9 @@ private static async Task ExtractPagesAndUploadPdfAsync(Aspose.Words.Doc } /// - public async Task ConvertPptToPdfDocumentAsync(string tmpFileDownloadName, bool firstPageOnly = true) + public async Task ConvertPptToPdfDocumentAsync(string tmpFileDownloadName, bool firstSlideOnly = true, CancellationToken cancellationToken = default) { + cancellationToken.ThrowIfCancellationRequested(); string pdfFileName = $"preview_{tmpFileDownloadName}.pdf"; // Output PDF blob name string? pdfFileUrl = null; // URL to return after upload @@ -762,9 +779,9 @@ private static async Task ExtractPagesAndUploadPdfAsync(Aspose.Words.Doc using (var presentation = new Aspose.Slides.Presentation(pptxStream)) { // Create a new presentation to hold the first slide - using (var slidePresentation = new Aspose.Slides.Presentation()) + using (var slidePresentation = new Aspose.Slides.Presentation()) { - convertAllslides = firstPageOnly == false && presentation.Slides.Count > 1; + convertAllslides = firstSlideOnly && presentation.Slides.Count > 1; // Check if there are any slides in the original presentation if (presentation.Slides.Count > 0) diff --git a/Cps.Fct.Hk.Ui.Services/DocumentService.cs b/Cps.Fct.Hk.Ui.Services/DocumentService.cs index f368e98b7..1f0a00eb7 100644 --- a/Cps.Fct.Hk.Ui.Services/DocumentService.cs +++ b/Cps.Fct.Hk.Ui.Services/DocumentService.cs @@ -39,7 +39,7 @@ public class DocumentService( private readonly BlobServiceClient? blobServiceClient = blobServiceClient; /// - public async Task GetMaterialDocumentAsync(string caseId, string link, CmsAuthValues cmsAuthValues, bool firstPageOnly = true) + public async Task GetMaterialDocumentAsync(string caseId, string link, CmsAuthValues cmsAuthValues, bool firstPageOnly = true, CancellationToken cancellationToken = default) { string? tmpFileDownloadName = null; string? blobContainerName = this.configuration[StorageKeys.BlobServiceContainerNameDocuments] ?? string.Empty; @@ -67,7 +67,7 @@ public class DocumentService( bool tmpSaved; // Save the document to temporary storage (Blob storage in this case) - tmpSaved = await this.conversionService.SaveDownloadedDocumentToTemporaryStorageAsync(downloadedDocument).ConfigureAwait(true); + tmpSaved = await this.conversionService.SaveDownloadedDocumentToTemporaryStorageAsync(downloadedDocument, cancellationToken).ConfigureAwait(true); if (tmpSaved) { @@ -75,7 +75,7 @@ public class DocumentService( string fileDownloadName = $"{tmpFileDownloadName}.pdf"; // Convert the saved document to a PDF and store it in Blob Storage - string? pdfBlobUrl = await this.conversionService.ConvertToPdfDocumentAsync(tmpFileDownloadName, firstPageOnly).ConfigureAwait(true); + string? pdfBlobUrl = await this.conversionService.ConvertToPdfDocumentAsync(tmpFileDownloadName, firstPageOnly, cancellationToken).ConfigureAwait(true); if (pdfBlobUrl == null) { @@ -89,7 +89,7 @@ public class DocumentService( .GetBlobClient($"preview_{tmpFileDownloadName}.pdf"); var pdfStream = new MemoryStream(); - await blobClient.DownloadToAsync(pdfStream).ConfigureAwait(false); + await blobClient.DownloadToAsync(pdfStream, cancellationToken).ConfigureAwait(false); pdfStream.Position = 0; // Reset stream position for reading return new FileStreamResult(pdfStream, "application/pdf") @@ -131,7 +131,7 @@ public class DocumentService( { if (!string.IsNullOrEmpty(blobContainerName)) { - await this.DeleteBlobAsync(blobContainerName, $"tmp_{tmpFileDownloadName}", "Temporary file").ConfigureAwait(false); + await this.DeleteBlobAsync(blobContainerName, $"tmp_{tmpFileDownloadName}", "Temporary file", cancellationToken).ConfigureAwait(false); await this.DeleteBlobAsync(blobContainerName, $"preview_{tmpFileDownloadName}.pdf", "Temporary preview or full document").ConfigureAwait(false); } } @@ -144,10 +144,11 @@ public class DocumentService( /// The name of the blob container where the blob is stored. /// The name of the blob to be deleted. /// A description of the blob (used in log messages). + /// A token to monitor for cancellation requests. /// A task representing the asynchronous operation. /// Thrown if the blobServiceClient is not initialized. /// Thrown if the blob container name is null or empty. - internal async Task DeleteBlobAsync(string blobContainerName, string blobName, string description) + internal async Task DeleteBlobAsync(string blobContainerName, string blobName, string description, CancellationToken cancellationToken = default) { try { @@ -168,7 +169,7 @@ internal async Task DeleteBlobAsync(string blobContainerName, string blobName, s .GetBlobClient(blobName); // Delete the blob - await blobClient.DeleteIfExistsAsync().ConfigureAwait(false); + await blobClient.DeleteIfExistsAsync(cancellationToken: cancellationToken).ConfigureAwait(false); this.logger.LogInformation($"{LoggingConstants.HskUiLogPrefix} {description} [{blobName}] deleted from Blob Storage."); } diff --git a/Cps.Fct.Hk.Ui.Services/MaterialReclassificationOrchestrationService.cs b/Cps.Fct.Hk.Ui.Services/MaterialReclassificationOrchestrationService.cs index 9ffcdb68a..a5802c551 100644 --- a/Cps.Fct.Hk.Ui.Services/MaterialReclassificationOrchestrationService.cs +++ b/Cps.Fct.Hk.Ui.Services/MaterialReclassificationOrchestrationService.cs @@ -38,7 +38,8 @@ public async Task CompleteReclassificationAsyn int caseId, int materialId, CmsAuthValues cmsAuthValues, - CompleteReclassificationRequest request) + CompleteReclassificationRequest request, + CancellationToken cancellationToken = default) { var transactionId = Guid.NewGuid(); var renameMaterialRequest = new RenameMaterialRequest(transactionId, materialId, request.reclassification.subject); @@ -62,7 +63,7 @@ public async Task CompleteReclassificationAsyn // Add witness task must be executed first when user has selected add witness flow, due to reclassification to Statement having a dependency on a new witness id. if (request!.AddWitness()) { - addWitnessResult = await this.ExecuteAddWitness(request.reclassification.urn, caseId, request.witness!, cmsAuthValues, transactionId).ConfigureAwait(false); + addWitnessResult = await this.ExecuteAddWitness(request.reclassification.urn, caseId, request.witness!, cmsAuthValues, transactionId, cancellationToken).ConfigureAwait(false); if (addWitnessResult.Success) { @@ -74,19 +75,19 @@ public async Task CompleteReclassificationAsyn // Add Action plan task to collection of tasks to be run in parallel if (request.HasActionPlan()) { - actionPlanTask = this.ExecuteAddActionPlan(request.reclassification.urn, caseId, request.actionPlan!, cmsAuthValues, transactionId); + actionPlanTask = this.ExecuteAddActionPlan(request.reclassification.urn, caseId, request.actionPlan!, cmsAuthValues, transactionId, cancellationToken); tasksToRun.Add(actionPlanTask); } // Rename material for all other non statement reclassification. if (!request.HasStatement()) { - renameMaterialTask = this.ExecuteMaterialRename(caseId, renameMaterialRequest, cmsAuthValues, transactionId); + renameMaterialTask = this.ExecuteMaterialRename(caseId, renameMaterialRequest, cmsAuthValues, transactionId, cancellationToken); tasksToRun.Add(renameMaterialTask); } // Add reclassification task to collection of tasks to be run in parallel - reclassificationTask = this.ExecuteReclassificationAsync(caseId, materialId, request.reclassification, cmsAuthValues, transactionId); + reclassificationTask = this.ExecuteReclassificationAsync(caseId, materialId, request.reclassification, cmsAuthValues, transactionId, cancellationToken); tasksToRun.Add(reclassificationTask); // Wait for all operations to complete running in parallel. @@ -127,24 +128,28 @@ private async Task ExecuteReclassificationAsync( int materialId, ReclassifyCaseMaterialRequest request, CmsAuthValues cmsAuthValues, - Guid transactionId) + Guid transactionId, + CancellationToken cancellationToken = default) { try { this.logger.LogInformation( $"{LoggingConstants.HskUiLogPrefix} executing reclassification for MaterialId: [{materialId}], TransactionId: {transactionId}"); - // Call the underlying service method directly + var serviceRequest = new ReclassifyCaseMaterialServiceRequest( + CaseId: caseId, + MaterialId: materialId, + Classification: request.classification, + DocumentTypeId: request.documentTypeId, + Used: request.used, + Subject: request.subject, + Statement: request.Statement, + Exhibit: request.Exhibit); + ReclassificationResponse result = await this.reclassificationService.ReclassifyCaseMaterialAsync( - caseId, - materialId, - request.classification, - request.documentTypeId, - request.used, - request.subject, + serviceRequest, cmsAuthValues, - request.Statement, - request.Exhibit).ConfigureAwait(false); + cancellationToken).ConfigureAwait(false); return new OperationResult( Success: true, @@ -168,7 +173,8 @@ private async Task ExecuteMaterialRename( int caseId, RenameMaterialRequest request, CmsAuthValues cmsAuthValues, - Guid transactionId) + Guid transactionId, + CancellationToken cancellationToken = default) { try { @@ -176,7 +182,7 @@ private async Task ExecuteMaterialRename( $"{LoggingConstants.HskUiLogPrefix} executing rename for MaterialId: [{request.materialId}], TransactionId: [{transactionId}", request.materialId, request.CorrespondenceId); // Call the underlying service method directly - RenameMaterialResponse result = await this.communicationService.RenameMaterialAsync(caseId, request.materialId, request.subject, cmsAuthValues).ConfigureAwait(false); + RenameMaterialResponse result = await this.communicationService.RenameMaterialAsync(caseId, request.materialId, request.subject, cmsAuthValues, cancellationToken: cancellationToken).ConfigureAwait(false); return new OperationResult( Success: true, @@ -201,14 +207,15 @@ private async Task ExecuteAddActionPlan( int caseId, AddCaseActionPlanRequest request, CmsAuthValues cmsAuthValues, - Guid transactionId) + Guid transactionId, + CancellationToken cancellationToken = default) { try { this.logger.LogInformation($"{LoggingConstants.HskUiLogPrefix} executing action plan for URN: [{urn}], TransactionId: [{transactionId}]"); // Call the underlying service method directly - NoContentResult result = await this.caseActionPlanService.AddCaseActionPlanAsync(urn, caseId, request, cmsAuthValues).ConfigureAwait(false); + NoContentResult result = await this.caseActionPlanService.AddCaseActionPlanAsync(urn, caseId, request, cmsAuthValues, cancellationToken).ConfigureAwait(false); return new OperationResult( Success: true, @@ -233,7 +240,8 @@ private async Task ExecuteAddWitness( int caseId, Common.Dto.Request.HouseKeeping.WitnessRequest request, CmsAuthValues cmsAuthValues, - Guid transactionId) + Guid transactionId, + CancellationToken cancellationToken = default) { try { @@ -245,7 +253,8 @@ private async Task ExecuteAddWitness( request.FirstName, request.Surname, cmsAuthValues, - transactionId).ConfigureAwait(false); + transactionId, + cancellationToken); return new OperationResult( Success: true, diff --git a/Cps.Fct.Hk.Ui.Services/ReclassificationService.cs b/Cps.Fct.Hk.Ui.Services/ReclassificationService.cs index 17446f05e..1113299a9 100644 --- a/Cps.Fct.Hk.Ui.Services/ReclassificationService.cs +++ b/Cps.Fct.Hk.Ui.Services/ReclassificationService.cs @@ -26,38 +26,35 @@ public class ReclassificationService( /// public async Task ReclassifyCaseMaterialAsync( - int caseId, - int materialId, - string classification, - int documentTypeId, - bool used, - string subject, + ReclassifyCaseMaterialServiceRequest request, CmsAuthValues cmsAuthValues, - ReclassifyStatementRequest? statement = null, - ReclassifyExhibitRequest? exhibit = null, - Guid correspondenceId = default) + CancellationToken cancellationToken = default) { try { - this.logger.LogInformation($"{LoggingConstants.HskUiLogPrefix} Attempting to reclassify a case material with materidId [{materialId}] associated with case with caseId [{caseId}]"); + this.logger.LogInformation("{Prefix} Attempting to reclassify a case material with materidId [{MaterialId}] associated with case with caseId [{CaseId}]", LoggingConstants.HskUiLogPrefix, request.MaterialId, request.CaseId); // Handle an exception to the rule for 'Defence statement' category that requires a different classification. - if (documentTypeId == -2) - { - classification = "DEFENCESTATEMENT"; - } + var classification = request.DocumentTypeId == -2 ? "DEFENCESTATEMENT" : request.Classification; - var request = new ReclassifyCommunicationRequest(correspondenceId != default ? correspondenceId : Guid.NewGuid(), classification, materialId, documentTypeId, used, subject, statement, exhibit); + var communicationRequest = new ReclassifyCommunicationRequest( + request.CorrespondenceId != Guid.Empty ? request.CorrespondenceId : Guid.NewGuid(), + classification, + request.MaterialId, + request.DocumentTypeId, + request.Used, + request.Subject, + request.Statement, + request.Exhibit); - ReclassificationResponse reclassificationResponse = await this.apiClient.ReclassifyCommunicationAsync(request, cmsAuthValues).ConfigureAwait(false); - this.logger.LogInformation(LoggingConstants.ReclassifyCaseMaterialOperationSuccess, LoggingConstants.HskUiLogPrefix, caseId, materialId); + ReclassificationResponse reclassificationResponse = await this.apiClient.ReclassifyCommunicationAsync(communicationRequest, cmsAuthValues, cancellationToken).ConfigureAwait(false); + this.logger.LogInformation(LoggingConstants.ReclassifyCaseMaterialOperationSuccess, LoggingConstants.HskUiLogPrefix, request.CaseId, request.MaterialId); return reclassificationResponse; } catch (Exception ex) { - this.logger.LogError(ex, LoggingConstants.ReclassifyCaseMaterialOperationFailed, LoggingConstants.HskUiLogPrefix, caseId, materialId); - this.logger.LogError(ex, ex.Message); + this.logger.LogError(ex, LoggingConstants.ReclassifyCaseMaterialOperationFailed, LoggingConstants.HskUiLogPrefix, request.CaseId, request.MaterialId); throw; } } diff --git a/Cps.Fct.Hk.Ui.Services/UmaReclassifyService.cs b/Cps.Fct.Hk.Ui.Services/UmaReclassifyService.cs index 50b3fef49..2e764e5bd 100644 --- a/Cps.Fct.Hk.Ui.Services/UmaReclassifyService.cs +++ b/Cps.Fct.Hk.Ui.Services/UmaReclassifyService.cs @@ -21,8 +21,9 @@ public class UmaReclassifyService(ILogger logger, IUmaServ private readonly IUmaServiceClient umaClient = umaClient; /// - public async Task> ProcessMatchingRequest(int caseId, IReadOnlyCollection communications) + public async Task> ProcessMatchingRequest(int caseId, IReadOnlyCollection communications, CancellationToken cancellationToken = default) { + cancellationToken.ThrowIfCancellationRequested(); ArgumentNullException.ThrowIfNull(communications); try diff --git a/Cps.Fct.Hk.Ui.Services/WitnessService.cs b/Cps.Fct.Hk.Ui.Services/WitnessService.cs index 47340e842..ba0614b8c 100644 --- a/Cps.Fct.Hk.Ui.Services/WitnessService.cs +++ b/Cps.Fct.Hk.Ui.Services/WitnessService.cs @@ -29,7 +29,7 @@ public class WitnessService( private readonly ICaseLockService caseLockService = caseLockService; /// - public async Task GetWitnessStatementsAsync(int witnessId, CmsAuthValues cmsAuthValues) + public async Task GetWitnessStatementsAsync(int witnessId, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default) { string witnessIdString = witnessId.ToString(CultureInfo.InvariantCulture); @@ -39,7 +39,7 @@ public async Task GetWitnessStatementsAsync(int witne var request = new GetWitnessStatementsRequest(witnessId, Guid.NewGuid()); - WitnessStatementsResponse? statements = await this.apiClient.GetWitnessStatementsAsync(request, cmsAuthValues).ConfigureAwait(false); + WitnessStatementsResponse? statements = await this.apiClient.GetWitnessStatementsAsync(request, cmsAuthValues, cancellationToken).ConfigureAwait(false); return statements; } @@ -52,7 +52,7 @@ public async Task GetWitnessStatementsAsync(int witne } /// - public async Task GetCaseWitnessesAsync(int caseId, CmsAuthValues cmsAuthValues) + public async Task GetCaseWitnessesAsync(int caseId, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default) { string caseIdString = caseId.ToString(CultureInfo.InvariantCulture); @@ -61,7 +61,7 @@ public async Task GetCaseWitnessesAsync(int caseId, CmsAuthVa this.logger.LogInformation($"{LoggingConstants.HskUiLogPrefix} Getting witnesses for caseId [{caseIdString}]"); var request = new GetCaseWitnessesRequest(caseId, Guid.NewGuid()); - WitnessesResponse? witnesses = await this.apiClient.GetCaseWitnessesAsync(request, cmsAuthValues).ConfigureAwait(false); + WitnessesResponse? witnesses = await this.apiClient.GetCaseWitnessesAsync(request, cmsAuthValues, cancellationToken).ConfigureAwait(false); return witnesses; } @@ -74,13 +74,13 @@ public async Task GetCaseWitnessesAsync(int caseId, CmsAuthVa } /// - public async Task AddWitnessAsync(string urn, int caseId, string firstName, string lastName, CmsAuthValues cmsAuthValues, Guid correspondenceId = default) + public async Task AddWitnessAsync(string urn, int caseId, string firstName, string lastName, CmsAuthValues cmsAuthValues, Guid correspondenceId = default, CancellationToken cancellationToken = default) { try { this.logger.LogInformation($"{LoggingConstants.HskUiLogPrefix} Attempting to add witness to case with a caseId [{caseId}]"); - var checkCaeLockStatus = await this.caseLockService.CheckCaseLockAsync(caseId, cmsAuthValues).ConfigureAwait(false); + var checkCaeLockStatus = await this.caseLockService.CheckCaseLockAsync(caseId, cmsAuthValues, cancellationToken).ConfigureAwait(false); if (checkCaeLockStatus.IsLocked && !checkCaeLockStatus.IsLockedByCurrentUser) { throw new CaseLockedException($"{LoggingConstants.HskUiLogPrefix} Attempting to add case witness for caseId [{caseId}] is failed as case is locked by [{checkCaeLockStatus.LockedByUser}]."); diff --git a/DdeiClient/Clients/BaseCmsClient.cs b/DdeiClient/Clients/BaseCmsClient.cs index c09d13f46..e4aee3f3e 100644 --- a/DdeiClient/Clients/BaseCmsClient.cs +++ b/DdeiClient/Clients/BaseCmsClient.cs @@ -3,6 +3,7 @@ using System.Net; using Common.Extensions; using System.Text.Json; +using System.Threading; namespace DdeiClient.Clients; @@ -16,29 +17,29 @@ protected BaseCmsClient(IJsonConvertWrapper jsonConvertWrapper) } protected abstract HttpClient GetHttpClient(string cmsAuthValues); - protected virtual async Task CallHttpClientAsync(HttpRequestMessage request, string cmsAuthValues) + protected virtual async Task CallHttpClientAsync(HttpRequestMessage request, string cmsAuthValues, CancellationToken cancellationToken = default) { - using var response = await CallHttpClientAsync(request, cmsAuthValues); - var content = await response.Content.ReadAsStringAsync(); + using var response = await CallHttpClientAsync(request, cmsAuthValues, cancellationToken); + var content = await response.Content.ReadAsStringAsync(cancellationToken); - try - { - return this.JsonConvertWrapper.DeserializeObject(content); - } - catch (JsonException ex) - { - // CMS service returned invalid or incompatible JSON - throw new HttpRequestException( - "Invalid JSON received from cms.", - ex, - HttpStatusCode.BadGateway); + try + { + return this.JsonConvertWrapper.DeserializeObject(content); + } + catch (JsonException ex) + { + // CMS service returned invalid or incompatible JSON + throw new HttpRequestException( + "Invalid JSON received from cms.", + ex, + HttpStatusCode.BadGateway); } } - protected virtual async Task CallHttpClientAsync(HttpRequestMessage request, string cmsAuthValues, params HttpStatusCode[] expectedUnhappyStatusCodes) + protected virtual async Task CallHttpClientAsync(HttpRequestMessage request, string cmsAuthValues, CancellationToken cancellationToken = default, params HttpStatusCode[] expectedUnhappyStatusCodes) { var httpClient = GetHttpClient(cmsAuthValues); - var response = await httpClient.SendAsync(request); + var response = await httpClient.SendAsync(request, cancellationToken); try { if (response.IsSuccessStatusCode || expectedUnhappyStatusCodes.Contains(response.StatusCode)) @@ -46,7 +47,7 @@ protected virtual async Task CallHttpClientAsync(HttpReques return response; } - var content = await response.Content.ReadAsStringAsync(); + var content = await response.Content.ReadAsStringAsync(cancellationToken); throw new HttpRequestException(content); } catch (HttpRequestException exception) diff --git a/DdeiClient/Clients/Interfaces/IMasterDataServiceClient.cs b/DdeiClient/Clients/Interfaces/IMasterDataServiceClient.cs index d20b14fed..b35e0dbfd 100644 --- a/DdeiClient/Clients/Interfaces/IMasterDataServiceClient.cs +++ b/DdeiClient/Clients/Interfaces/IMasterDataServiceClient.cs @@ -25,103 +25,115 @@ public interface IMasterDataServiceClient /// /// If the case summary is not found, the method returns null. The caller should handle the null return value accordingly. /// - Task GetCaseSummaryAsync(GetCaseSummaryRequest request, CmsAuthValues cmsAuthValues); + Task GetCaseSummaryAsync(GetCaseSummaryRequest request, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default); /// /// Lists the communications for a case identifier. /// /// The request to list communications. /// CMS authentication values including cookies and tokens. + /// A token to cancel the operation. /// A list of communications for a case identifier. - Task> ListCommunicationsHkAsync(ListCommunicationsHkRequest request, CmsAuthValues cmsAuthValues); + Task> ListCommunicationsHkAsync(ListCommunicationsHkRequest request, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default); /// /// Lists the used statements for a case identifier. /// /// The request to list used statements. /// CMS authentication values including cookies and tokens. + /// A token to cancel the operation. /// A list of used statements for a case identifier. - Task GetUsedStatementsAsync(GetUsedStatementsRequest request, CmsAuthValues cmsAuthValues); + Task GetUsedStatementsAsync(GetUsedStatementsRequest request, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default); /// /// Lists the used exhibits for a case identifier. /// /// The request to list used exhibits. /// CMS authentication values including cookies and tokens. + /// A token to cancel the operation. /// A list of used exhibits for a case identifier. - Task GetUsedExhibitsAsync(GetUsedExhibitsRequest request, CmsAuthValues cmsAuthValues); + Task GetUsedExhibitsAsync(GetUsedExhibitsRequest request, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default); /// /// Lists the used MG forms for a case identifier. /// /// The request to list used MG forms. /// CMS authentication values including cookies and tokens. + /// A token to cancel the operation. /// A list of used MG forms for a case identifier. - Task GetUsedMgFormsAsync(GetUsedMgFormsRequest request, CmsAuthValues cmsAuthValues); + Task GetUsedMgFormsAsync(GetUsedMgFormsRequest request, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default); /// /// Lists the used other materials for a case identifier. /// /// The request to list used other materials. /// CMS authentication values including cookies and tokens. + /// A token to cancel the operation. /// A list of used other materials for a case identifier. - Task GetUsedOtherMaterialsAsync(GetUsedOtherMaterialsRequest request, CmsAuthValues cmsAuthValues); + Task GetUsedOtherMaterialsAsync(GetUsedOtherMaterialsRequest request, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default); /// /// Lists the unused materials for a case identifier. /// /// The request to list unused materials. /// CMS authentication values including cookies and tokens. + /// A token to cancel the operation. /// A list of unused materials for a case identifier. - Task GetUnusedMaterialsAsync(GetUnusedMaterialsRequest request, CmsAuthValues cmsAuthValues); + Task GetUnusedMaterialsAsync(GetUnusedMaterialsRequest request, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default); /// /// Gets exhibit producers for a given case Id. /// /// The request for exhibit producers. /// CMS authentication values including cookies and tokens. + /// A token to cancel the operation. /// A list of exhibit producers - Task GetExhibitProducersAsync(GetExhibitProducersRequest request, CmsAuthValues cmsAuthValues); + Task GetExhibitProducersAsync(GetExhibitProducersRequest request, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default); /// /// Asynchronously retrieves the attachments for a given communication identifier. /// /// The request containing the parameters required to fetch the attachments. /// CMS authentication values including cookies and tokens. + /// A token to cancel the operation. /// A task representing the asynchronous operation, which returns the attachments response. - Task GetAttachmentsAsync(GetAttachmentsRequest request, CmsAuthValues cmsAuthValues); + Task GetAttachmentsAsync(GetAttachmentsRequest request, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default); /// /// Asynchronously retrieves the material document for the specified request. /// /// The request containing the document parameters. /// CMS authentication values including cookies and tokens. + /// A token to cancel the operation. /// A task representing the asynchronous operation, which returns a if the document is found; otherwise, null. - Task GetMaterialDocumentAsync(GetDocumentRequest request, CmsAuthValues cmsAuthValues); + Task GetMaterialDocumentAsync(GetDocumentRequest request, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default); /// /// Gets case defendants. /// /// The request to list defendants. /// CMS authentication values including cookies and tokens. + /// A token to cancel the operation. /// A list of defendants for a case identifier. - Task GetCaseDefendantsAsync(ListCaseDefendantsRequest request, CmsAuthValues cmsAuthValues); + Task GetCaseDefendantsAsync(ListCaseDefendantsRequest request, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default); /// /// Gets witnesses belonging to the case. /// /// GetWitnessRequest. /// CMS authentication values including cookies and tokens. + /// A token to cancel the operation. /// List of witnesses. - Task GetCaseWitnessesAsync(GetCaseWitnessesRequest request, CmsAuthValues cmsAuthValues); + Task GetCaseWitnessesAsync(GetCaseWitnessesRequest request, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default); /// /// Gets statements for a witness. /// /// The request object. /// CMS authentication values including cookies and tokens. + /// A token to cancel the operation. /// representing the asynchronous operation. - Task GetWitnessStatementsAsync(GetWitnessStatementsRequest request, CmsAuthValues cmsAuthValues); + Task GetWitnessStatementsAsync(GetWitnessStatementsRequest request, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default); /// /// Adds a case action plan for a given case Id. @@ -129,96 +141,108 @@ public interface IMasterDataServiceClient /// The case Id. /// The request object. /// CMS authentication values including cookies and tokens. + /// A token to cancel the operation. /// A representing the asynchronous operation, with a indicating success without a specific content body. - Task AddCaseActionPlanAsync(int caseId, AddActionPlanRequest request, CmsAuthValues cmsAuthValues); + Task AddCaseActionPlanAsync(int caseId, AddActionPlanRequest request, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default); /// /// Asynchronously adds a new case witness. /// /// The request to add a witness. /// CMS authentication values including cookies and tokens. + /// A token to cancel the operation. /// A representing the asynchronous operation, with a indicating success without a specific content body. - Task AddWitnessAsync(AddWitnessRequest request, CmsAuthValues cmsAuthValues); + Task AddWitnessAsync(AddWitnessRequest request, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default); /// /// Asynchronously renames a material name using material id. /// /// The request to add a witness. /// CMS authentication values including cookies and tokens. + /// A token to cancel the operation. /// RenameMaterialResponse object. - Task RenameMaterialAsync(RenameMaterialRequest request, CmsAuthValues cmsAuthValues); + Task RenameMaterialAsync(RenameMaterialRequest request, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default); /// /// Reclassifies a communication for a material identifier. /// /// The request to add a witness. /// CMS authentication values including cookies and tokens. + /// A token to cancel the operation. /// ReclassificationResponse object. - Task ReclassifyCommunicationAsync(ReclassifyCommunicationRequest request, CmsAuthValues cmsAuthValues); + Task ReclassifyCommunicationAsync(ReclassifyCommunicationRequest request, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default); /// /// Asynchronously check case lock status. /// /// The ID of the case to be unlocked. /// The CMS authentication values required for the API call. + /// A token to cancel the operation. /// A representing the asynchronous operation, with a string containing the lock release status. - Task CheckCaseLockAsync(int caseId, CmsAuthValues cmsAuthValues); + Task CheckCaseLockAsync(int caseId, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default); /// /// Asynchronously discards a material using material id. /// /// The discard material request. /// The CMS authentication values required for the API call. + /// A token to cancel the operation. /// A representing the asynchronous operation, with a string containing the lock release status. - Task DiscardMaterialAsync(DiscardMaterialRequest request, CmsAuthValues cmsAuthValues); + Task DiscardMaterialAsync(DiscardMaterialRequest request, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default); /// /// Asynchronously discards a material using material id. /// /// The discard material request. /// The CMS authentication values required for the API call. + /// A token to cancel the operation. /// A representing the asynchronous operation, with a string containing the lock release status. - Task SetMaterialReadStatusAsync(SetMaterialReadStatusRequest request, CmsAuthValues cmsAuthValues); + Task SetMaterialReadStatusAsync(SetMaterialReadStatusRequest request, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default); /// /// Get PCD Requests core/basic info by case id. /// /// The GetPcdRequestsCore request. /// The CMS authentication values required for the API call. + /// A token to cancel the operation. /// A representing the asynchronous operation, with a string containing the lock release status. - Task> GetPcdRequestCoreAsync(GetPcdRequestsCoreRequest request, CmsAuthValues cmsAuthValues); + Task> GetPcdRequestCoreAsync(GetPcdRequestsCoreRequest request, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default); /// /// Get PCD request overview by case id and PCD id. /// /// The GetPcdRequestByPcdIdCore request. /// The CMS authentication values required for the API call. + /// A token to cancel the operation. /// A representing the asynchronous operation, with a string containing the lock release status. - Task GetPcdRequestByPcdIdAsync(GetPcdRequestByPcdIdCoreRequest request, CmsAuthValues cmsAuthValues); + Task GetPcdRequestByPcdIdAsync(GetPcdRequestByPcdIdCoreRequest request, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default); /// /// Asynchronously updates statemenet. /// /// The statement request. /// The CMS authentication values required for the API call. + /// A token to cancel the operation. /// A representing the asynchronous operation, with a string containing the lock release status. - Task UpdateStatementAsync(UpdateStatementRequest request, CmsAuthValues cmsAuthValues); + Task UpdateStatementAsync(UpdateStatementRequest request, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default); /// /// Asynchronously updates exhibit. /// /// The exhibit request. /// The CMS authentication values required for the API call. + /// A token to cancel the operation. /// A representing the asynchronous operation, with a string containing the lock release status. - Task UpdateExhibitAsync(UpdateExhibitRequest request, CmsAuthValues cmsAuthValues); + Task UpdateExhibitAsync(UpdateExhibitRequest request, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default); /// /// Get First Initial Review Get Case History. /// /// The caseId. /// The CMS authentication values required for the API call. + /// A token to cancel the operation. /// A representing the asynchronous operation, with a string containing the lock release status. - Task FirstInitialReviewGetCaseHistoryAsync(int caseId, CmsAuthValues cmsAuthValues); + Task FirstInitialReviewGetCaseHistoryAsync(int caseId, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default); /// /// Get Initial Review ByHistoryId. @@ -228,7 +252,7 @@ public interface IMasterDataServiceClient /// The CMS authentication values required for the API call. /// The cancellationToken required for the API call. /// A representing the asynchronous operation, with a string containing the lock release status. - Task GetInitialReviewByHistoryIdAsync(int caseId, int historyId, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken); + Task GetInitialReviewByHistoryIdAsync(int caseId, int historyId, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default); /// /// Get PCD Analysis ByHistoryId. @@ -238,15 +262,16 @@ public interface IMasterDataServiceClient /// The CMS authentication values required for the API call. /// The cancellationToken required for the API call. /// A representing the asynchronous operation, with a string containing the lock release status. - Task GetPcdAnalysisByIdAsync(int caseId, int historyId, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken); + Task GetPcdAnalysisByIdAsync(int caseId, int historyId, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default); /// /// GetHistoryEvents. /// /// The caseId. /// The CMS authentication values required for the API call. + /// A token to cancel the operation. /// A representing the asynchronous operation, with a string containing the lock release status. - Task> GetHistoryEventsAsync(int caseId, CmsAuthValues cmsAuthValues); + Task> GetHistoryEventsAsync(int caseId, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default); /// /// Get Offence Charge. @@ -254,16 +279,18 @@ public interface IMasterDataServiceClient /// The caseId. /// History Id. /// The CMS authentication values required for the API call. + /// A token to cancel the operation. /// A representing the asynchronous operation, with a string containing the lock release status. - Task GetOffenceChargeByHistoryIdAsync(int caseId, int historyId, CmsAuthValues cmsAuthValues); + Task GetOffenceChargeByHistoryIdAsync(int caseId, int historyId, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default); /// /// Get Pre Charge Decision Case History Event Details. /// /// Case Id. /// The CMS authentication values required for the API call. + /// A token to cancel the operation. /// A representing the asynchronous operation, with a string containing the lock release status. - Task GetPreChargeDecisionCaseHistoryEventDetailsAsync(int caseId, CmsAuthValues cmsAuthValues); + Task GetPreChargeDecisionCaseHistoryEventDetailsAsync(int caseId, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default); /// /// Get Pre Charge Decision By History Id. @@ -271,15 +298,17 @@ public interface IMasterDataServiceClient /// Case Id. /// History Id. /// The CMS authentication values required for the API call. + /// A token to cancel the operation. /// A representing the asynchronous operation, with a string containing the lock release status. - Task GetPreChargeDecisionByHistoryId(int caseId, int historyId, CmsAuthValues cmsAuthValues); + Task GetPreChargeDecisionByHistoryId(int caseId, int historyId, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default); /// /// Get Pcd review. /// /// The case id. /// The CMS authentication values required for the API call. + /// A token to cancel the operation. /// A representing the asynchronous operation, with a string containing the lock release status. - Task GetPcdReview(int caseId, CmsAuthValues cmsAuthValues); + Task GetPcdReview(int caseId, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default); } } \ No newline at end of file diff --git a/DdeiClient/Clients/Interfaces/IMdsClient.cs b/DdeiClient/Clients/Interfaces/IMdsClient.cs index 5a88e38d8..94a2cbc8f 100644 --- a/DdeiClient/Clients/Interfaces/IMdsClient.cs +++ b/DdeiClient/Clients/Interfaces/IMdsClient.cs @@ -7,52 +7,53 @@ using DdeiClient.Domain.Args; using Ddei.Domain.Response.Document; using Ddei.Domain.Response; +using System.Threading; namespace DdeiClient.Clients.Interfaces; public interface IMdsClient { - Task GetUrnFromCaseIdAsync(MdsCaseIdOnlyArgDto arg); + Task GetUrnFromCaseIdAsync(MdsCaseIdOnlyArgDto arg, CancellationToken cancellationToken = default); - Task GetCaseSummaryAsync(MdsCaseIdOnlyArgDto arg); + Task GetCaseSummaryAsync(MdsCaseIdOnlyArgDto arg, CancellationToken cancellationToken = default); - Task> GetPcdRequestsCoreAsync(MdsCaseIdentifiersArgDto arg); + Task> GetPcdRequestsCoreAsync(MdsCaseIdentifiersArgDto arg, CancellationToken cancellationToken = default); - Task> GetPcdRequestsAsync(MdsCaseIdentifiersArgDto arg); + Task> GetPcdRequestsAsync(MdsCaseIdentifiersArgDto arg, CancellationToken cancellationToken = default); - Task GetPcdRequestAsync(MdsPcdArgDto arg); + Task GetPcdRequestAsync(MdsPcdArgDto arg, CancellationToken cancellationToken = default); - Task GetDefendantAndChargesAsync(MdsCaseIdentifiersArgDto arg); + Task GetDefendantAndChargesAsync(MdsCaseIdentifiersArgDto arg, CancellationToken cancellationToken = default); - Task> ListDocumentsAsync(MdsCaseIdentifiersArgDto arg); + Task> ListDocumentsAsync(MdsCaseIdentifiersArgDto arg, CancellationToken cancellationToken = default); - Task GetDocumentAsync(MdsMaterialIdAndDocumentIdArgDto arg); + Task GetDocumentAsync(MdsMaterialIdAndDocumentIdArgDto arg, CancellationToken cancellationToken = default); - Task CheckoutDocumentAsync(MdsMaterialIdAndDocumentIdArgDto arg); + Task CheckoutDocumentAsync(MdsMaterialIdAndDocumentIdArgDto arg, CancellationToken cancellationToken = default); - Task CancelCheckoutDocumentAsync(MdsMaterialIdAndDocumentIdArgDto arg); + Task CancelCheckoutDocumentAsync(MdsMaterialIdAndDocumentIdArgDto arg, CancellationToken cancellationToken = default); - Task UploadPdfAsync(MdsMaterialIdAndDocumentIdArgDto arg, Stream stream); + Task UploadPdfAsync(MdsMaterialIdAndDocumentIdArgDto arg, Stream stream, CancellationToken cancellationToken = default); - Task> GetDocumentNotesAsync(MdsDocumentArgDto arg); + Task> GetDocumentNotesAsync(MdsDocumentArgDto arg, CancellationToken cancellationToken = default); - Task AddDocumentNoteAsync(MdsAddDocumentNoteArgDto arg); + Task AddDocumentNoteAsync(MdsAddDocumentNoteArgDto arg, CancellationToken cancellationToken = default); - Task RenameDocumentAsync(MdsRenameDocumentArgDto arg); + Task RenameDocumentAsync(MdsRenameDocumentArgDto arg, CancellationToken cancellationToken = default); - Task RenameExhibitAsync(MdsRenameDocumentArgDto arg); + Task RenameExhibitAsync(MdsRenameDocumentArgDto arg, CancellationToken cancellationToken = default); - Task ReclassifyCommunicationAsync(MdsReclassifyCommunicationArgDto arg); + Task ReclassifyCommunicationAsync(MdsReclassifyCommunicationArgDto arg, CancellationToken cancellationToken = default); - Task> GetExhibitProducersAsync(MdsCaseIdentifiersArgDto arg); + Task> GetExhibitProducersAsync(MdsCaseIdentifiersArgDto arg, CancellationToken cancellationToken = default); - Task> GetWitnessesAsync(MdsCaseIdentifiersArgDto arg); + Task> GetWitnessesAsync(MdsCaseIdentifiersArgDto arg, CancellationToken cancellationToken = default); - Task> GetMaterialTypeListAsync(CmsBaseArgDto arg); + Task> GetMaterialTypeListAsync(CmsBaseArgDto arg, CancellationToken cancellationToken = default); - Task> GetWitnessStatementsAsync(MdsWitnessStatementsArgDto arg); + Task> GetWitnessStatementsAsync(MdsWitnessStatementsArgDto arg, CancellationToken cancellationToken = default); - Task ToggleIsUnusedDocumentAsync(MdsToggleIsUnusedDocumentDto toggleIsUnusedDocumentDto); + Task ToggleIsUnusedDocumentAsync(MdsToggleIsUnusedDocumentDto toggleIsUnusedDocumentDto, CancellationToken cancellationToken = default); - Task> ListCaseIdsAsync(MdsUrnArgDto arg); + Task> ListCaseIdsAsync(MdsUrnArgDto arg, CancellationToken cancellationToken = default); } \ No newline at end of file diff --git a/DdeiClient/Clients/MasterDataServiceClient.cs b/DdeiClient/Clients/MasterDataServiceClient.cs index f2884994a..b9bd271a4 100644 --- a/DdeiClient/Clients/MasterDataServiceClient.cs +++ b/DdeiClient/Clients/MasterDataServiceClient.cs @@ -32,7 +32,7 @@ public class MasterDataServiceClient(IMasterDataServiceApiClientFactory mdsApiCl private readonly ILogger logger = loggerFactory.CreateLogger(); /// - public async Task GetCaseSummaryAsync(GetCaseSummaryRequest request, CmsAuthValues cmsAuthValues) + public async Task GetCaseSummaryAsync(GetCaseSummaryRequest request, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default) { Requires.NotNull(request); Requires.NotNull(cmsAuthValues.CmsAuthFullValue); @@ -47,7 +47,7 @@ public async Task GetCaseSummaryAsync(GetCaseSummaryRequest { var client = this.mdsApiClientFactory.Create(cmsAuthValues.CmsAuthFullValue); - var data = await client.GetCaseSummaryAsync(request.CaseId); + var data = await client.GetCaseSummaryAsync(request.CaseId, cancellationToken); if (data?.Urn is not null) { @@ -72,7 +72,7 @@ public async Task GetCaseSummaryAsync(GetCaseSummaryRequest } /// - public async Task GetUnusedMaterialsAsync(GetUnusedMaterialsRequest request, CmsAuthValues cmsAuthValues) + public async Task GetUnusedMaterialsAsync(GetUnusedMaterialsRequest request, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default) { Requires.NotNull(request); Requires.NotNull(cmsAuthValues.CmsAuthFullValue); @@ -83,11 +83,11 @@ public async Task GetUnusedMaterialsAsync(GetUnusedMate try { - UnusedMaterialsResponse results = new (); + UnusedMaterialsResponse results = new(); var client = this.mdsApiClientFactory.Create(cmsAuthValues.CmsAuthFullValue); string additionalInfo = $"received #0 unused materials"; - var data = await client.GetUnusedMaterialsAsync(request.CaseId); + var data = await client.GetUnusedMaterialsAsync(request.CaseId, cancellationToken); if (data is not null) { @@ -153,7 +153,7 @@ public async Task GetUnusedMaterialsAsync(GetUnusedMate } /// - public async Task GetUsedExhibitsAsync(GetUsedExhibitsRequest request, CmsAuthValues cmsAuthValues) + public async Task GetUsedExhibitsAsync(GetUsedExhibitsRequest request, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default) { Requires.NotNull(request); Requires.NotNull(cmsAuthValues.CmsAuthFullValue); @@ -163,12 +163,12 @@ public async Task GetUsedExhibitsAsync(GetUsedExhibitsRequ try { - UsedExhibitsResponse results = new () { Exhibits = new List() }; + UsedExhibitsResponse results = new() { Exhibits = new List() }; var client = this.mdsApiClientFactory.Create(cmsAuthValues.CmsAuthFullValue); string additionalInfo = $"received #0 used exhibits"; - var data = await client.GetUsedExhibitsAsync(request.CaseId); + var data = await client.GetUsedExhibitsAsync(request.CaseId, cancellationToken); if (data?.Exhibits is not null) { @@ -204,7 +204,7 @@ public async Task GetUsedExhibitsAsync(GetUsedExhibitsRequ } /// - public async Task GetUsedMgFormsAsync(GetUsedMgFormsRequest request, CmsAuthValues cmsAuthValues) + public async Task GetUsedMgFormsAsync(GetUsedMgFormsRequest request, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default) { Requires.NotNull(request); Requires.NotNull(cmsAuthValues.CmsAuthFullValue); @@ -214,10 +214,10 @@ public async Task GetUsedMgFormsAsync(GetUsedMgFormsRequest try { - UsedMgFormsResponse results = new () { MgForms = new List() }; + UsedMgFormsResponse results = new() { MgForms = new List() }; var client = this.mdsApiClientFactory.Create(cmsAuthValues.CmsAuthFullValue); - var data = await client.GetUsedMgFormsAsync(request.CaseId); + var data = await client.GetUsedMgFormsAsync(request.CaseId, cancellationToken); if (data?.MgForms is not null) { @@ -250,7 +250,7 @@ public async Task GetUsedMgFormsAsync(GetUsedMgFormsRequest } /// - public async Task GetUsedOtherMaterialsAsync(GetUsedOtherMaterialsRequest request, CmsAuthValues cmsAuthValues) + public async Task GetUsedOtherMaterialsAsync(GetUsedOtherMaterialsRequest request, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default) { Requires.NotNull(request); Requires.NotNull(cmsAuthValues.CmsAuthFullValue); @@ -260,10 +260,10 @@ public async Task GetUsedOtherMaterialsAsync(GetUsed try { - UsedOtherMaterialsResponse results = new () { MgForms = new List() }; + UsedOtherMaterialsResponse results = new() { MgForms = new List() }; var client = this.mdsApiClientFactory.Create(cmsAuthValues.CmsAuthFullValue); - var data = await client.GetUsedOtherMaterialsAsync(request.CaseId); + var data = await client.GetUsedOtherMaterialsAsync(request.CaseId, cancellationToken); if (data?.MgForms is not null) { @@ -295,7 +295,7 @@ public async Task GetUsedOtherMaterialsAsync(GetUsed } /// - public async Task GetUsedStatementsAsync(GetUsedStatementsRequest request, CmsAuthValues cmsAuthValues) + public async Task GetUsedStatementsAsync(GetUsedStatementsRequest request, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default) { Requires.NotNull(request); Requires.NotNull(cmsAuthValues.CmsAuthFullValue); @@ -305,12 +305,12 @@ public async Task GetUsedStatementsAsync(GetUsedStatemen try { - UsedStatementsResponse results = new () { Statements = new List() }; + UsedStatementsResponse results = new() { Statements = new List() }; var client = this.mdsApiClientFactory.Create(cmsAuthValues.CmsAuthFullValue); string additionalInfo = $"received #0 used statements"; - var data = await client.GetUsedStatementsAsync(request.CaseId); + var data = await client.GetUsedStatementsAsync(request.CaseId, cancellationToken); if (data?.Statements is not null) { @@ -346,7 +346,7 @@ public async Task GetUsedStatementsAsync(GetUsedStatemen } /// - public async Task> ListCommunicationsHkAsync(ListCommunicationsHkRequest request, CmsAuthValues cmsAuthValues) + public async Task> ListCommunicationsHkAsync(ListCommunicationsHkRequest request, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default) { Requires.NotNull(request); Requires.NotNull(cmsAuthValues.CmsAuthFullValue); @@ -356,11 +356,11 @@ public async Task> ListCommunicationsHkAsync( try { - List results = new (); + List results = new(); var client = this.mdsApiClientFactory.Create(cmsAuthValues.CmsAuthFullValue); string additionalInfo = $"received #0 communications"; - var data = await client.ListCommunicationsHkAsync(request.CaseId); + var data = await client.ListCommunicationsHkAsync(request.CaseId, cancellationToken); if (data is not null) { @@ -399,21 +399,21 @@ public async Task> ListCommunicationsHkAsync( } /// - public async Task GetAttachmentsAsync(GetAttachmentsRequest request, CmsAuthValues cmsAuthValues) + public async Task GetAttachmentsAsync(GetAttachmentsRequest request, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default) { Requires.NotNull(request); Requires.NotNull(cmsAuthValues.CmsAuthFullValue); var stopwatch = Stopwatch.StartNew(); const string OperationName = "GetAttachments"; - AttachmentsResponse results = new (); + AttachmentsResponse results = new(); try { var client = this.mdsApiClientFactory.Create(cmsAuthValues.CmsAuthFullValue); string additionalInfo = $"received #0 attachments"; - var data = await client.GetAttachmentsAsync(request.CommunicationId); + var data = await client.GetAttachmentsAsync(request.CommunicationId, cancellationToken); if (data?.Attachments is not null) { results = new AttachmentsResponse @@ -454,7 +454,7 @@ public async Task GetAttachmentsAsync(GetAttachmentsRequest } /// - public async Task GetMaterialDocumentAsync(GetDocumentRequest request, CmsAuthValues cmsAuthValues) + public async Task GetMaterialDocumentAsync(GetDocumentRequest request, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default) { Requires.NotNull(request); Requires.NotNull(cmsAuthValues.CmsAuthFullValue); @@ -469,7 +469,7 @@ public async Task GetAttachmentsAsync(GetAttachmentsRequest int caseId = int.Parse(request.CaseId); - var data = await client.GetMaterialDocumentAsync(caseId, request.FilePath); + var data = await client.GetMaterialDocumentAsync(caseId, request.FilePath, cancellationToken); string fileDownloadName = Path.GetFileName(request.FilePath); string? contentType = FileUtils.GetMimeType(fileDownloadName) ?? @@ -493,14 +493,14 @@ public async Task GetAttachmentsAsync(GetAttachmentsRequest } /// - public async Task GetExhibitProducersAsync(GetExhibitProducersRequest request, CmsAuthValues cmsAuthValues) + public async Task GetExhibitProducersAsync(GetExhibitProducersRequest request, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default) { Requires.NotNull(request); Requires.NotNull(cmsAuthValues.CmsAuthFullValue); var stopwatch = Stopwatch.StartNew(); const string OperationName = "GetExhibitProducers"; - ExhibitProducersResponse results = new (); + ExhibitProducersResponse results = new(); try { @@ -508,7 +508,7 @@ public async Task GetExhibitProducersAsync(GetExhibitP string additionalInfo = "received #0 producers"; - var data = await client.GetExhibitProducersAsync(request.CaseId); + var data = await client.GetExhibitProducersAsync(request.CaseId, cancellationToken); if (data != null) { @@ -538,20 +538,20 @@ public async Task GetExhibitProducersAsync(GetExhibitP } /// - public async Task GetCaseDefendantsAsync(ListCaseDefendantsRequest request, CmsAuthValues cmsAuthValues) + public async Task GetCaseDefendantsAsync(ListCaseDefendantsRequest request, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default) { Requires.NotNull(request); Requires.NotNull(cmsAuthValues.CmsAuthFullValue); var stopwatch = Stopwatch.StartNew(); const string OperationName = "ListCaseDefendants"; - List results = new (); + List results = new(); try { var client = this.mdsApiClientFactory.Create(cmsAuthValues.CmsAuthFullValue); - var data = await client.ListCaseDefendantsAsync(request.CaseId); + var data = await client.ListCaseDefendantsAsync(request.CaseId, cancellationToken); var listCaseDefendantsResponse = new DefendantsResponse { @@ -590,7 +590,7 @@ public async Task GetCaseDefendantsAsync(ListCaseDefendantsR } /// - public async Task GetCaseWitnessesAsync(GetCaseWitnessesRequest request, CmsAuthValues cmsAuthValues) + public async Task GetCaseWitnessesAsync(GetCaseWitnessesRequest request, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default) { Requires.NotNull(request); Requires.NotNull(cmsAuthValues.CmsAuthFullValue); @@ -598,13 +598,13 @@ public async Task GetCaseWitnessesAsync(GetCaseWitnessesReque var stopwatch = Stopwatch.StartNew(); const string OperationName = "ListCaseWitnesses"; string additionalInfo = $"received #0 witnesses"; - WitnessesResponse results = new (); + WitnessesResponse results = new(); try { var client = this.mdsApiClientFactory.Create(cmsAuthValues.CmsAuthFullValue); - var data = await client.ListCaseWitnessesAsync(request.CaseId); + var data = await client.ListCaseWitnessesAsync(request.CaseId, null, null, cancellationToken); if (data is not null) { @@ -632,7 +632,7 @@ public async Task GetCaseWitnessesAsync(GetCaseWitnessesReque } /// - public async Task GetWitnessStatementsAsync(GetWitnessStatementsRequest request, CmsAuthValues cmsAuthValues) + public async Task GetWitnessStatementsAsync(GetWitnessStatementsRequest request, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default) { Requires.NotNull(request); Requires.NotNull(cmsAuthValues.CmsAuthFullValue); @@ -641,13 +641,13 @@ public async Task GetWitnessStatementsAsync(GetWitnes const string OperationName = "GetStatementsForWitness"; string additionalInfo = "received #0 statements"; - WitnessStatementsResponse results = new (); + WitnessStatementsResponse results = new(); try { var client = this.mdsApiClientFactory.Create(cmsAuthValues.CmsAuthFullValue); - var data = await client.GetStatementsForWitnessAsync(request.WitnessId); + var data = await client.GetStatementsForWitnessAsync(request.WitnessId, cancellationToken); if (data?.StatementsForWitness is not null) { @@ -670,7 +670,7 @@ public async Task GetWitnessStatementsAsync(GetWitnes } /// - public async Task AddCaseActionPlanAsync(int caseId, AddActionPlanRequest request, CmsAuthValues cmsAuthValues) + public async Task AddCaseActionPlanAsync(int caseId, AddActionPlanRequest request, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default) { Requires.NotNull(request); Requires.NotNull(cmsAuthValues.CmsAuthFullValue); @@ -684,7 +684,7 @@ public async Task AddCaseActionPlanAsync(int caseId, AddActionP var mdsRequest = MapApAction(request); - await client.AddActionPlanAsync(caseId, mdsRequest); + await client.AddActionPlanAsync(caseId, mdsRequest, cancellationToken); this.LogOperationCompletedEvent(OperationName, request, stopwatch.Elapsed, string.Empty); return new NoContentResult(); @@ -697,7 +697,7 @@ public async Task AddCaseActionPlanAsync(int caseId, AddActionP } /// - public async Task AddWitnessAsync(AddWitnessRequest request, CmsAuthValues cmsAuthValues) + public async Task AddWitnessAsync(AddWitnessRequest request, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default) { Requires.NotNull(request); Requires.NotNull(request.caseId); @@ -718,7 +718,7 @@ public async Task AddWitnessAsync(AddWitnessRequest request, Cm FirstName = request.FirstName, }; - await client.AddWitnessAsync(request.caseId, mdsRequest); + await client.AddWitnessAsync(request.caseId, mdsRequest, cancellationToken); this.LogOperationCompletedEvent(OperationName, request, stopwatch.Elapsed, string.Empty); return new NoContentResult(); } @@ -730,7 +730,7 @@ public async Task AddWitnessAsync(AddWitnessRequest request, Cm } /// - public async Task RenameMaterialAsync(RenameMaterialRequest request, CmsAuthValues cmsAuthValues) + public async Task RenameMaterialAsync(RenameMaterialRequest request, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default) { Requires.NotNull(request); Requires.NotNull(request.materialId); @@ -749,14 +749,14 @@ public async Task RenameMaterialAsync(RenameMaterialRequ Subject = request.subject, }; - var data = await client.RenameMaterialAsync(request.materialId, mdsRequest); + var data = await client.RenameMaterialAsync(request.materialId, mdsRequest, cancellationToken); if (data?.UpdateCommunication?.Id == null) { return default; } - RenameMaterialResponse result = new (new RenameMaterialData { Id = data.UpdateCommunication.Id }); + RenameMaterialResponse result = new(new RenameMaterialData { Id = data.UpdateCommunication.Id }); this.LogOperationCompletedEvent(OperationName, request, stopwatch.Elapsed, string.Empty); @@ -770,7 +770,7 @@ public async Task RenameMaterialAsync(RenameMaterialRequ } /// - public async Task ReclassifyCommunicationAsync(ReclassifyCommunicationRequest request, CmsAuthValues cmsAuthValues) + public async Task ReclassifyCommunicationAsync(ReclassifyCommunicationRequest request, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default) { Requires.NotNull(request); Requires.NotNull(cmsAuthValues.CmsAuthFullValue); @@ -793,7 +793,7 @@ public async Task ReclassifyCommunicationAsync(Reclass Exhibit = MapExhibit(request.Exhibit), }; - var data = await client.ReclassifyCommunicationAsync(mdsRequest); + var data = await client.ReclassifyCommunicationAsync(mdsRequest, cancellationToken); if (data?.ReclassifyCommunication?.Id == null) { @@ -813,7 +813,7 @@ public async Task ReclassifyCommunicationAsync(Reclass } /// - public async Task CheckCaseLockAsync(int caseId, CmsAuthValues cmsAuthValues) + public async Task CheckCaseLockAsync(int caseId, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default) { if (caseId <= 0) { @@ -831,7 +831,7 @@ public async Task CheckCaseLockAsync(int caseId, CmsAuth { var client = this.mdsApiClientFactory.Create(cmsAuthValues.CmsAuthFullValue); - var data = await client.GetCaseLockStatusAsync(caseId); + var data = await client.GetCaseLockStatusAsync(caseId, cancellationToken); var result = new CaseLockedStatusResult { @@ -851,7 +851,7 @@ public async Task CheckCaseLockAsync(int caseId, CmsAuth } /// - public async Task DiscardMaterialAsync(DiscardMaterialRequest request, CmsAuthValues cmsAuthValues) + public async Task DiscardMaterialAsync(DiscardMaterialRequest request, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default) { Requires.NotNull(request); Requires.NotNull(request.materialId); @@ -871,7 +871,7 @@ public async Task DiscardMaterialAsync(DiscardMaterialR DiscardReasonDescription = request.discardReasonDescription, }; - var data = await client.DiscardMaterialAsync(request.materialId, mdsReqest); + var data = await client.DiscardMaterialAsync(request.materialId, mdsReqest, cancellationToken); this.LogOperationCompletedEvent(OperationName, request, stopwatch.Elapsed, string.Empty); if (data?.DiscardMaterial?.Id == null) @@ -890,7 +890,7 @@ public async Task DiscardMaterialAsync(DiscardMaterialR } /// - public async Task SetMaterialReadStatusAsync(SetMaterialReadStatusRequest request, CmsAuthValues cmsAuthValues) + public async Task SetMaterialReadStatusAsync(SetMaterialReadStatusRequest request, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default) { Requires.NotNull(request); Requires.NotNull(request.materialId); @@ -908,7 +908,7 @@ public async Task SetMaterialReadStatusAsync(SetM State = (ApiClient.MaterialReadStateRequestState)request.state, }; - var data = await client.SetMaterialReadStateAsync(request.materialId, mdsReqest); + var data = await client.SetMaterialReadStateAsync(request.materialId, mdsReqest, cancellationToken); if (data?.CompleteCommunication?.Id == null) { @@ -929,7 +929,7 @@ public async Task SetMaterialReadStatusAsync(SetM } /// - public async Task> GetPcdRequestCoreAsync(GetPcdRequestsCoreRequest request, CmsAuthValues cmsAuthValues) + public async Task> GetPcdRequestCoreAsync(GetPcdRequestsCoreRequest request, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default) { Requires.NotNull(request); Requires.NotNull(cmsAuthValues.CmsAuthFullValue); @@ -937,12 +937,12 @@ public async Task> GetPcdRequestCoreAsync(GetPcdRequestsCor var stopwatch = Stopwatch.StartNew(); const string OperationName = "PcdRequestCore"; - List results = new (); + List results = new(); try { var client = this.mdsApiClientFactory.Create(cmsAuthValues.CmsAuthFullValue); - var data = await client.GetCasePcdRequestCoreAsync(request.caseId); + var data = await client.GetCasePcdRequestCoreAsync(request.caseId, cancellationToken); if (data is not null) { @@ -967,7 +967,7 @@ public async Task> GetPcdRequestCoreAsync(GetPcdRequestsCor } /// - public async Task GetPcdRequestByPcdIdAsync(GetPcdRequestByPcdIdCoreRequest request, CmsAuthValues cmsAuthValues) + public async Task GetPcdRequestByPcdIdAsync(GetPcdRequestByPcdIdCoreRequest request, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default) { Requires.NotNull(request); Requires.NotNull(cmsAuthValues.CmsAuthFullValue); @@ -981,7 +981,7 @@ public async Task GetPcdRequestByPcdIdAsync(GetPcdRequestByPcdIdC { var client = this.mdsApiClientFactory.Create(cmsAuthValues.CmsAuthFullValue); - var data = await client.GetCasePcdRequestByPcdIdAsync(request.caseId, request.pcdId); + var data = await client.GetCasePcdRequestByPcdIdAsync(request.caseId, request.pcdId, cancellationToken); if (data is not null) { @@ -1039,7 +1039,7 @@ public async Task GetPcdRequestByPcdIdAsync(GetPcdRequestByPcdIdC } /// - public async Task UpdateStatementAsync(UpdateStatementRequest request, CmsAuthValues cmsAuthValues) + public async Task UpdateStatementAsync(UpdateStatementRequest request, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default) { Requires.NotNull(request); Requires.NotNull(request.MaterialId); @@ -1065,7 +1065,7 @@ public async Task UpdateStatementAsync(UpdateStatementR Used = request.Used, }; - var data = await client.UpdateStatementAsync(request.CaseId, request.MaterialId, mdsRequest); + var data = await client.UpdateStatementAsync(request.CaseId, request.MaterialId, mdsRequest, cancellationToken); if (data?.UpdateStatement?.Id == null) { @@ -1084,7 +1084,7 @@ public async Task UpdateStatementAsync(UpdateStatementR } /// - public async Task UpdateExhibitAsync(UpdateExhibitRequest request, CmsAuthValues cmsAuthValues) + public async Task UpdateExhibitAsync(UpdateExhibitRequest request, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default) { Requires.NotNull(request); Requires.NotNull(request.CaseId); @@ -1115,7 +1115,7 @@ public async Task UpdateExhibitAsync(UpdateExhibitRequest Used = request.Used, }; - var data = await client.UpdateExhibitAsync(request.CaseId, request.MaterialId, mdsRequest); + var data = await client.UpdateExhibitAsync(request.CaseId, request.MaterialId, mdsRequest, cancellationToken); if (data?.UpdateExhibit?.Id == null) { @@ -1135,7 +1135,7 @@ public async Task UpdateExhibitAsync(UpdateExhibitRequest } /// - public async Task FirstInitialReviewGetCaseHistoryAsync(int caseId, CmsAuthValues cmsAuthValues) + public async Task FirstInitialReviewGetCaseHistoryAsync(int caseId, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default) { Requires.NotNull(caseId); Requires.NotNull(cmsAuthValues.CmsAuthFullValue); @@ -1147,7 +1147,7 @@ public async Task UpdateExhibitAsync(UpdateExhibitRequest { var client = this.mdsApiClientFactory.Create(cmsAuthValues.CmsAuthFullValue); - var data = await client.FirstInitialReviewGetCaseHistoryAsync(caseId); + var data = await client.FirstInitialReviewGetCaseHistoryAsync(caseId, cancellationToken); return data; } catch (Exception exception) @@ -1199,7 +1199,7 @@ public async Task UpdateExhibitAsync(UpdateExhibitRequest { var client = this.mdsApiClientFactory.Create(cmsAuthValues.CmsAuthFullValue); - var data = await client.GetPcdAnalysisByIdAsync(caseId, historyId); + var data = await client.GetPcdAnalysisByIdAsync(caseId, historyId, cancellationToken); return data; } catch (Exception exception) @@ -1210,7 +1210,7 @@ public async Task UpdateExhibitAsync(UpdateExhibitRequest } /// - public async Task> GetHistoryEventsAsync(int caseId, CmsAuthValues cmsAuthValues) + public async Task> GetHistoryEventsAsync(int caseId, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default) { Requires.NotNull(caseId); Requires.NotNull(cmsAuthValues.CmsAuthFullValue); @@ -1222,7 +1222,7 @@ public async Task UpdateExhibitAsync(UpdateExhibitRequest { var client = this.mdsApiClientFactory.Create(cmsAuthValues.CmsAuthFullValue); - var data = await client.GetCaseHistoryEventsAsync(caseId); + var data = await client.GetCaseHistoryEventsAsync(caseId, null, cancellationToken); return data; } catch (Exception exception) @@ -1233,7 +1233,7 @@ public async Task UpdateExhibitAsync(UpdateExhibitRequest } /// - public async Task GetOffenceChargeByHistoryIdAsync(int caseId, int historyId, CmsAuthValues cmsAuthValues) + public async Task GetOffenceChargeByHistoryIdAsync(int caseId, int historyId, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default) { Requires.NotNull(caseId); Requires.NotNull(historyId); @@ -1246,7 +1246,7 @@ public async Task UpdateExhibitAsync(UpdateExhibitRequest { var client = this.mdsApiClientFactory.Create(cmsAuthValues.CmsAuthFullValue); - var data = await client.GetOffenceChangeByIdAsync(caseId, historyId); + var data = await client.GetOffenceChangeByIdAsync(caseId, historyId, cancellationToken); return data; } catch (Exception exception) @@ -1257,7 +1257,7 @@ public async Task UpdateExhibitAsync(UpdateExhibitRequest } /// - public async Task GetPreChargeDecisionCaseHistoryEventDetailsAsync(int caseId, CmsAuthValues cmsAuthValues) + public async Task GetPreChargeDecisionCaseHistoryEventDetailsAsync(int caseId, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default) { Requires.NotNull(caseId); Requires.NotNull(cmsAuthValues.CmsAuthFullValue); @@ -1269,7 +1269,7 @@ public async Task UpdateExhibitAsync(UpdateExhibitRequest { var client = this.mdsApiClientFactory.Create(cmsAuthValues.CmsAuthFullValue); - var data = await client.GetPreChargeDecisionOutcomesAsync(caseId); + var data = await client.GetPreChargeDecisionOutcomesAsync(caseId, cancellationToken); return data; } catch (Exception exception) @@ -1280,7 +1280,7 @@ public async Task UpdateExhibitAsync(UpdateExhibitRequest } /// - public async Task GetPreChargeDecisionByHistoryId(int caseId, int historyId, CmsAuthValues cmsAuthValues) + public async Task GetPreChargeDecisionByHistoryId(int caseId, int historyId, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default) { Requires.NotNull(caseId); Requires.NotNull(historyId); @@ -1293,7 +1293,7 @@ public async Task UpdateExhibitAsync(UpdateExhibitRequest { var client = this.mdsApiClientFactory.Create(cmsAuthValues.CmsAuthFullValue); - var data = await client.GetPreChargeDecisionByIdAsync(caseId, historyId); + var data = await client.GetPreChargeDecisionByIdAsync(caseId, historyId, cancellationToken); return data; } catch (Exception exception) @@ -1304,7 +1304,7 @@ public async Task UpdateExhibitAsync(UpdateExhibitRequest } /// - public async Task GetPcdReview(int caseId, CmsAuthValues cmsAuthValues) + public async Task GetPcdReview(int caseId, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default) { Requires.NotNull(caseId); Requires.NotNull(cmsAuthValues.CmsAuthFullValue); @@ -1316,7 +1316,7 @@ public async Task UpdateExhibitAsync(UpdateExhibitRequest { var client = this.mdsApiClientFactory.Create(cmsAuthValues.CmsAuthFullValue); - var data = await client.GetPcdReviewAsync(caseId); + var data = await client.GetPcdReviewAsync(caseId, cancellationToken); return data; } catch (Exception exception) @@ -1652,4 +1652,4 @@ private string BuildAdditionalInfo(UnusedMaterialsResponse results) return additionalInfo; } -} +} \ No newline at end of file diff --git a/DdeiClient/Clients/MdsClient.cs b/DdeiClient/Clients/MdsClient.cs index 7cc55892d..28ac524dd 100644 --- a/DdeiClient/Clients/MdsClient.cs +++ b/DdeiClient/Clients/MdsClient.cs @@ -19,6 +19,7 @@ using DdeiClient.Factories; using Microsoft.Extensions.Logging; using System.Net; +using System.Threading; namespace DdeiClient.Clients; @@ -68,158 +69,158 @@ public MdsClient( _jsonConvertWrapper = jsonConvertWrapper.ExceptionIfNull(); } - public async Task GetUrnFromCaseIdAsync(MdsCaseIdOnlyArgDto arg) + public async Task GetUrnFromCaseIdAsync(MdsCaseIdOnlyArgDto arg, CancellationToken cancellationToken = default) { - var mdsCaseIdentifiersDto = await CallHttpClientAsync(_mdsClientRequestFactory.CreateUrnLookupRequest(arg), arg.CmsAuthValues); + var mdsCaseIdentifiersDto = await CallHttpClientAsync(_mdsClientRequestFactory.CreateUrnLookupRequest(arg), arg.CmsAuthValues, cancellationToken); return _caseIdentifiersMapper.MapCaseIdentifiers(mdsCaseIdentifiersDto); } - public async Task GetCaseSummaryAsync(MdsCaseIdOnlyArgDto arg) + public async Task GetCaseSummaryAsync(MdsCaseIdOnlyArgDto arg, CancellationToken cancellationToken = default) { - var mdsResult = await CallHttpClientAsync(_mdsClientRequestFactory.CreateGetCaseSummary(arg), arg.CmsAuthValues); + var mdsResult = await CallHttpClientAsync(_mdsClientRequestFactory.CreateGetCaseSummary(arg), arg.CmsAuthValues, cancellationToken); return _caseDetailsMapper.Map(mdsResult); } - public async Task> GetPcdRequestsCoreAsync(MdsCaseIdentifiersArgDto arg) + public async Task> GetPcdRequestsCoreAsync(MdsCaseIdentifiersArgDto arg, CancellationToken cancellationToken = default) { - var pcdRequests = await CallHttpClientAsync>(_mdsClientRequestFactory.CreateGetPcdRequestsRequest(arg), arg.CmsAuthValues); + var pcdRequests = await CallHttpClientAsync>(_mdsClientRequestFactory.CreateGetPcdRequestsRequest(arg), arg.CmsAuthValues, cancellationToken); return _caseDetailsMapper.MapCorePreChargeDecisionRequests(pcdRequests); } - public async Task> GetPcdRequestsAsync(MdsCaseIdentifiersArgDto arg) + public async Task> GetPcdRequestsAsync(MdsCaseIdentifiersArgDto arg, CancellationToken cancellationToken = default) { - var pcdRequests = await CallHttpClientAsync>(_mdsClientRequestFactory.CreateGetPcdRequestsRequest(arg), arg.CmsAuthValues); + var pcdRequests = await CallHttpClientAsync>(_mdsClientRequestFactory.CreateGetPcdRequestsRequest(arg), arg.CmsAuthValues, cancellationToken); return _caseDetailsMapper.MapPreChargeDecisionRequests(pcdRequests); } - public async Task GetPcdRequestAsync(MdsPcdArgDto arg) + public async Task GetPcdRequestAsync(MdsPcdArgDto arg, CancellationToken cancellationToken = default) { - var pcdRequest = await CallHttpClientAsync(_mdsClientRequestFactory.CreateGetPcdRequest(arg), arg.CmsAuthValues); + var pcdRequest = await CallHttpClientAsync(_mdsClientRequestFactory.CreateGetPcdRequest(arg), arg.CmsAuthValues, cancellationToken); return _caseDetailsMapper.MapPreChargeDecisionRequest(pcdRequest); } - public async Task GetDefendantAndChargesAsync(MdsCaseIdentifiersArgDto arg) + public async Task GetDefendantAndChargesAsync(MdsCaseIdentifiersArgDto arg, CancellationToken cancellationToken = default) { - var response = await CallHttpClientAsync(_mdsClientRequestFactory.CreateGetDefendantAndChargesRequest(arg), arg.CmsAuthValues); - var content = await response.Content.ReadAsStringAsync(); + var response = await CallHttpClientAsync(_mdsClientRequestFactory.CreateGetDefendantAndChargesRequest(arg), arg.CmsAuthValues, cancellationToken); + var content = await response.Content.ReadAsStringAsync(cancellationToken); var defendantAndCharges = _jsonConvertWrapper.DeserializeObject>(content); var etag = response.Headers.ETag?.Tag; return _caseDetailsMapper.MapDefendantsAndCharges(defendantAndCharges, arg.CaseId, etag); } - public async Task> ListDocumentsAsync(MdsCaseIdentifiersArgDto arg) + public async Task> ListDocumentsAsync(MdsCaseIdentifiersArgDto arg, CancellationToken cancellationToken = default) { - var mdsResults = await CallHttpClientAsync>(_mdsClientRequestFactory.CreateListCaseDocumentsRequest(arg), arg.CmsAuthValues); + var mdsResults = await CallHttpClientAsync>(_mdsClientRequestFactory.CreateListCaseDocumentsRequest(arg), arg.CmsAuthValues, cancellationToken); return mdsResults.Select(mdsResult => _caseDocumentMapper.Map(mdsResult)); } - public async Task GetDocumentAsync(MdsMaterialIdAndDocumentIdArgDto arg) + public async Task GetDocumentAsync(MdsMaterialIdAndDocumentIdArgDto arg, CancellationToken cancellationToken = default) { - var response = await CallHttpClientAsync(_mdsClientRequestFactory.CreateGetDocumentRequest(arg), arg.CmsAuthValues); + var response = await CallHttpClientAsync(_mdsClientRequestFactory.CreateGetDocumentRequest(arg), arg.CmsAuthValues, cancellationToken); var fileName = response.Content.Headers.GetValues("Content-Disposition").ToList()[0]; return new FileResult { - Stream = await response.Content.ReadAsStreamAsync(), + Stream = await response.Content.ReadAsStreamAsync(cancellationToken), FileName = fileName, }; } - public async Task CheckoutDocumentAsync(MdsMaterialIdAndDocumentIdArgDto arg) + public async Task CheckoutDocumentAsync(MdsMaterialIdAndDocumentIdArgDto arg, CancellationToken cancellationToken = default) { await CallHttpClientAsync( - _mdsClientRequestFactory.CreateCheckoutDocumentRequest(arg), arg.CmsAuthValues); + _mdsClientRequestFactory.CreateCheckoutDocumentRequest(arg), arg.CmsAuthValues, cancellationToken); return new CheckoutDocumentDto { IsSuccess = true }; } - public async Task CancelCheckoutDocumentAsync(MdsMaterialIdAndDocumentIdArgDto arg) + public async Task CancelCheckoutDocumentAsync(MdsMaterialIdAndDocumentIdArgDto arg, CancellationToken cancellationToken = default) { - await CallHttpClientAsync(_mdsClientRequestFactory.CreateCancelCheckoutDocumentRequest(arg), arg.CmsAuthValues); + await CallHttpClientAsync(_mdsClientRequestFactory.CreateCancelCheckoutDocumentRequest(arg), arg.CmsAuthValues, cancellationToken); } - public async Task UploadPdfAsync(MdsMaterialIdAndDocumentIdArgDto arg, Stream stream) + public async Task UploadPdfAsync(MdsMaterialIdAndDocumentIdArgDto arg, Stream stream, CancellationToken cancellationToken = default) { - return await CallHttpClientAsync(_mdsClientRequestFactory.CreateUploadPdfRequest(arg, stream), arg.CmsAuthValues, + return await CallHttpClientAsync(_mdsClientRequestFactory.CreateUploadPdfRequest(arg, stream), arg.CmsAuthValues, cancellationToken, [ HttpStatusCode.Gone, HttpStatusCode.RequestEntityTooLarge ]); } - public async Task> GetDocumentNotesAsync(MdsDocumentArgDto arg) + public async Task> GetDocumentNotesAsync(MdsDocumentArgDto arg, CancellationToken cancellationToken = default) { - var mdsResults = await CallHttpClientAsync>(_mdsClientRequestFactory.CreateGetDocumentNotesRequest(arg), arg.CmsAuthValues); + var mdsResults = await CallHttpClientAsync>(_mdsClientRequestFactory.CreateGetDocumentNotesRequest(arg), arg.CmsAuthValues, cancellationToken); return mdsResults.Select(mdsResult => _caseDocumentNoteMapper.Map(mdsResult)).ToArray(); } - public async Task AddDocumentNoteAsync(MdsAddDocumentNoteArgDto arg) + public async Task AddDocumentNoteAsync(MdsAddDocumentNoteArgDto arg, CancellationToken cancellationToken = default) { - var response = await CallHttpClientAsync(_mdsClientRequestFactory.CreateAddDocumentNoteRequest(arg), arg.CmsAuthValues); + var response = await CallHttpClientAsync(_mdsClientRequestFactory.CreateAddDocumentNoteRequest(arg), arg.CmsAuthValues, cancellationToken); return _caseDocumentNoteResultMapper.Map(response); } - public async Task RenameDocumentAsync(MdsRenameDocumentArgDto arg) + public async Task RenameDocumentAsync(MdsRenameDocumentArgDto arg, CancellationToken cancellationToken = default) { - var response = await CallHttpClientAsync(_mdsClientRequestFactory.CreateRenameDocumentRequest(arg), arg.CmsAuthValues); + var response = await CallHttpClientAsync(_mdsClientRequestFactory.CreateRenameDocumentRequest(arg), arg.CmsAuthValues, cancellationToken); return new DocumentRenamedResultDto { Id = response.UpdateCommunication.Id }; } - public async Task RenameExhibitAsync(MdsRenameDocumentArgDto arg) + public async Task RenameExhibitAsync(MdsRenameDocumentArgDto arg, CancellationToken cancellationToken = default) { - var response = await CallHttpClientAsync(_mdsClientRequestFactory.CreateRenameExhibitRequest(arg), arg.CmsAuthValues); + var response = await CallHttpClientAsync(_mdsClientRequestFactory.CreateRenameExhibitRequest(arg), arg.CmsAuthValues, cancellationToken); return new DocumentRenamedResultDto { Id = response.UpdateCommunicationDescription.Id }; } - public async Task ReclassifyCommunicationAsync(MdsReclassifyCommunicationArgDto arg) + public async Task ReclassifyCommunicationAsync(MdsReclassifyCommunicationArgDto arg, CancellationToken cancellationToken = default) { - return await CallHttpClientAsync(_mdsClientRequestFactory.CreateReclassifyCommunicationRequest(arg), arg.CmsAuthValues); + return await CallHttpClientAsync(_mdsClientRequestFactory.CreateReclassifyCommunicationRequest(arg), arg.CmsAuthValues, cancellationToken); } - public async Task> GetExhibitProducersAsync(MdsCaseIdentifiersArgDto arg) + public async Task> GetExhibitProducersAsync(MdsCaseIdentifiersArgDto arg, CancellationToken cancellationToken = default) { - var mdsResults = await CallHttpClientAsync(_mdsClientRequestFactory.CreateGetExhibitProducersRequest(arg), arg.CmsAuthValues); + var mdsResults = await CallHttpClientAsync(_mdsClientRequestFactory.CreateGetExhibitProducersRequest(arg), arg.CmsAuthValues, cancellationToken); return mdsResults.ExhibitProducers.Select(_caseExhibitProducerMapper.Map); } - public async Task> GetWitnessesAsync(MdsCaseIdentifiersArgDto arg) + public async Task> GetWitnessesAsync(MdsCaseIdentifiersArgDto arg, CancellationToken cancellationToken = default) { - var mdsResults = await CallHttpClientAsync>(_mdsClientRequestFactory.CreateCaseWitnessesRequest(arg), arg.CmsAuthValues); + var mdsResults = await CallHttpClientAsync>(_mdsClientRequestFactory.CreateCaseWitnessesRequest(arg), arg.CmsAuthValues, cancellationToken); return mdsResults; } - public async Task> GetMaterialTypeListAsync(CmsBaseArgDto arg) + public async Task> GetMaterialTypeListAsync(CmsBaseArgDto arg, CancellationToken cancellationToken = default) { - var mdsResults = await CallHttpClientAsync>(_mdsClientRequestFactory.CreateGetMaterialTypeListRequest(arg), arg.CmsAuthValues); + var mdsResults = await CallHttpClientAsync>(_mdsClientRequestFactory.CreateGetMaterialTypeListRequest(arg), arg.CmsAuthValues, cancellationToken); return mdsResults.Select(mdsResult => _cmsMaterialTypeMapper.Map(mdsResult)).ToArray(); } - public async Task> GetWitnessStatementsAsync(MdsWitnessStatementsArgDto arg) + public async Task> GetWitnessStatementsAsync(MdsWitnessStatementsArgDto arg, CancellationToken cancellationToken = default) { - var mdsResults = await CallHttpClientAsync(_mdsClientRequestFactory.CreateGetWitnessStatementsRequest(arg), arg.CmsAuthValues); + var mdsResults = await CallHttpClientAsync(_mdsClientRequestFactory.CreateGetWitnessStatementsRequest(arg), arg.CmsAuthValues, cancellationToken); return mdsResults.StatementsForWitness.Select(_caseWitnessStatementMapper.Map).ToArray(); } - public async Task ToggleIsUnusedDocumentAsync(MdsToggleIsUnusedDocumentDto toggleIsUnusedDocumentDto) => - (await CallHttpClientAsync(_mdsClientRequestFactory.CreateToggleIsUnusedDocumentRequest(toggleIsUnusedDocumentDto), toggleIsUnusedDocumentDto.CmsAuthValues)) + public async Task ToggleIsUnusedDocumentAsync(MdsToggleIsUnusedDocumentDto toggleIsUnusedDocumentDto, CancellationToken cancellationToken = default) => + (await CallHttpClientAsync(_mdsClientRequestFactory.CreateToggleIsUnusedDocumentRequest(toggleIsUnusedDocumentDto), toggleIsUnusedDocumentDto.CmsAuthValues, cancellationToken)) .IsSuccessStatusCode; - public async Task> ListCaseIdsAsync(MdsUrnArgDto arg) => - await CallHttpClientAsync>(_mdsClientRequestFactory.CreateListCasesRequest(arg), arg.CmsAuthValues); + public async Task> ListCaseIdsAsync(MdsUrnArgDto arg, CancellationToken cancellationToken = default) => + await CallHttpClientAsync>(_mdsClientRequestFactory.CreateListCasesRequest(arg), arg.CmsAuthValues, cancellationToken); - private async Task GetCaseInternalAsync(MdsCaseIdentifiersArgDto arg) => - await CallHttpClientAsync(_mdsClientRequestFactory.CreateGetCaseRequest(arg), arg.CmsAuthValues); + private async Task GetCaseInternalAsync(MdsCaseIdentifiersArgDto arg, CancellationToken cancellationToken = default) => + await CallHttpClientAsync(_mdsClientRequestFactory.CreateGetCaseRequest(arg), arg.CmsAuthValues, cancellationToken); protected override HttpClient GetHttpClient(string cmsAuthValues) { diff --git a/global.json b/global.json new file mode 100644 index 000000000..05740c38c --- /dev/null +++ b/global.json @@ -0,0 +1,6 @@ +{ + "sdk": { + "version": "10.0.300", + "rollForward": "latestFeature" + } +} diff --git a/polaris-gateway.tests/Functions/HouseKeeping/GetCaseInfoTests.cs b/polaris-gateway.tests/Functions/HouseKeeping/GetCaseInfoTests.cs index f63c5c4f5..6e9d40f6b 100644 --- a/polaris-gateway.tests/Functions/HouseKeeping/GetCaseInfoTests.cs +++ b/polaris-gateway.tests/Functions/HouseKeeping/GetCaseInfoTests.cs @@ -16,7 +16,9 @@ namespace PolarisGateway.Tests.Functions.HouseKeeping; using Common.Dto.Response.HouseKeeping; using Common.Dto.Request; using System; +using System.Threading; using Common.Constants; +using Common.Exceptions; /// /// Unit tests for the class. @@ -53,6 +55,13 @@ public async Task Run_ReturnsOkResult_WhenValidRequestProvided() // Set up a DefaultHttpContext to support setting headers var context = new DefaultHttpContext(); + + // Set up cookies + var mockCookies = new Mock(); + mockCookies.Setup(c => c.TryGetValue(It.IsAny(), out It.Ref.IsAny)) + .Returns(false); + + mockRequest.Setup(r => r.Cookies).Returns(mockCookies.Object); mockRequest.Setup(r => r.HttpContext).Returns(context); mockRequest.Setup(r => r.Headers.Add("corelation", "1232131231")); @@ -60,11 +69,11 @@ public async Task Run_ReturnsOkResult_WhenValidRequestProvided() // Ensure the mock returns the expected list of communications mockCaseInfoService - .Setup(x => x.GetCaseInfoAsync(123, It.IsAny())) + .Setup(x => x.GetCaseInfoAsync(123, It.IsAny(), It.IsAny())) .ReturnsAsync(mockCaseInfo); // Act - IActionResult result = await getCaseInfoFunction.Run(mockRequest.Object, 123); + IActionResult result = await getCaseInfoFunction.Run(mockRequest.Object, 123, CancellationToken.None); // Assert OkObjectResult okResult = Assert.IsType(result); @@ -90,21 +99,51 @@ public async Task Run_ReturnsOkResult_WhenValidRequestProvided() /// /// A task representing the asynchronous test operation. [Fact] + public async Task Run_Returns500InternalError_WhenUnhandledExceptionIsThrown() + { + // Arrange + Mock mockRequest = SetUpMockRequest(); + + mockCaseInfoService + .Setup(x => x.GetCaseInfoAsync(123, It.IsAny(), It.IsAny())) + .ThrowsAsync(new Exception("Internal server error")); + + // Act + IActionResult result = await getCaseInfoFunction.Run(mockRequest.Object, 123, CancellationToken.None); + + // Assert + StatusCodeResult statusCodeResult = Assert.IsType(result); + Assert.Equal(StatusCodes.Status500InternalServerError, statusCodeResult.StatusCode); + + Assert.Contains(mockLogger.Logs, log => + log.LogLevel == LogLevel.Information && + log.Message != null && log.Message.Contains($"{LoggingConstants.HskUiLogPrefix} GetCaseInfo function processed a request.")); + + Assert.Contains(mockLogger.Logs, log => + log.LogLevel == LogLevel.Error && + log.Message != null && log.Message.Contains($"{LoggingConstants.HskUiLogPrefix} GetCaseInfo function encountered an error")); + } + + /// + /// Tests that the function returns an unprocessable entity error when an InvalidOperationException is thrown. + /// + /// A task representing the asynchronous test operation. + [Fact] public async Task Run_ReturnsUnprocessableEntityError_WhenInvalidOperationExceptionIsThrown() { - // Arrange + // Arrange Mock mockRequest = SetUpMockRequest(); mockCaseInfoService - .Setup(x => x.GetCaseInfoAsync(123, It.IsAny())) + .Setup(x => x.GetCaseInfoAsync(123, It.IsAny(), It.IsAny())) .ThrowsAsync(new InvalidOperationException("Invalid operation error")); // Act - IActionResult result = await getCaseInfoFunction.Run(mockRequest.Object, 123); + IActionResult result = await getCaseInfoFunction.Run(mockRequest.Object, 123, CancellationToken.None); // Assert - ObjectResult objectResult = Assert.IsType(result); - Assert.Equal(StatusCodes.Status422UnprocessableEntity, objectResult.StatusCode); + UnprocessableEntityObjectResult unprocessableResult = Assert.IsType(result); + Assert.Equal("Invalid operation error", unprocessableResult.Value); Assert.Contains(mockLogger.Logs, log => log.LogLevel == LogLevel.Information && @@ -112,30 +151,30 @@ public async Task Run_ReturnsUnprocessableEntityError_WhenInvalidOperationExcept Assert.Contains(mockLogger.Logs, log => log.LogLevel == LogLevel.Error && - log.Message != null && log.Message.Contains($"{LoggingConstants.HskUiLogPrefix} GetCaseInfo function encountered an unprocessable entity error: " + - "GetCaseInfo function encountered an error fetching case information for caseId [123]")); + log.Message != null && log.Message.Contains($"{LoggingConstants.HskUiLogPrefix} Invalid operation error")); } /// - /// Tests that the function returns an internal server error when an exception is thrown. + /// Tests that the function returns an unprocessable entity error when an UnprocessableEntityException is thrown. /// /// A task representing the asynchronous test operation. [Fact] - public async Task Run_ReturnsUnprocessableEntityError_WhenExceptionIsThrown() + public async Task Run_ReturnsUnprocessableEntityError_WhenUnprocessableEntityExceptionIsThrown() { - // Arrange + // Arrange Mock mockRequest = SetUpMockRequest(); mockCaseInfoService - .Setup(x => x.GetCaseInfoAsync(123, It.IsAny())) - .ThrowsAsync(new Exception("Unexpected error")); + .Setup(x => x.GetCaseInfoAsync(123, It.IsAny(), It.IsAny())) + .ThrowsAsync(new UnprocessableEntityException("Unprocessable entity error")); // Act - IActionResult result = await getCaseInfoFunction.Run(mockRequest.Object, 123); + IActionResult result = await getCaseInfoFunction.Run(mockRequest.Object, 123, CancellationToken.None); // Assert ObjectResult objectResult = Assert.IsType(result); Assert.Equal(StatusCodes.Status422UnprocessableEntity, objectResult.StatusCode); + Assert.Equal("Unprocessable entity error", objectResult.Value); Assert.Contains(mockLogger.Logs, log => log.LogLevel == LogLevel.Information && @@ -143,8 +182,71 @@ public async Task Run_ReturnsUnprocessableEntityError_WhenExceptionIsThrown() Assert.Contains(mockLogger.Logs, log => log.LogLevel == LogLevel.Error && - log.Message != null && log.Message.Contains($"{LoggingConstants.HskUiLogPrefix} GetCaseInfo function encountered an unprocessable entity error: " + - "GetCaseInfo function encountered an error fetching case information for caseId [123]")); + log.Message != null && log.Message.Contains($"{LoggingConstants.HskUiLogPrefix} GetCaseInfo function encountered an unprocessable entity error: Unprocessable entity error")); + } + + /// + /// Tests that the function properly handles cancellation when the cancellation token is cancelled. + /// + /// A task representing the asynchronous test operation. + [Fact] + public async Task Run_ProperlyCancels_WhenCancellationTokenIsCancelled() + { + // Arrange + Mock mockRequest = SetUpMockRequest(); + var cancellationTokenSource = new CancellationTokenSource(); + + // Set up the service to throw OperationCanceledException when called + mockCaseInfoService + .Setup(x => x.GetCaseInfoAsync(123, It.IsAny(), It.IsAny())) + .ThrowsAsync(new OperationCanceledException("Operation was cancelled")); + + // Act & Assert - expect OperationCanceledException to propagate + var exception = await Assert.ThrowsAnyAsync(async () => + await getCaseInfoFunction.Run(mockRequest.Object, 123, cancellationTokenSource.Token)); + + // Verify the service was called + mockCaseInfoService.Verify( + x => x.GetCaseInfoAsync(123, It.IsAny(), It.IsAny()), + Times.Once); + + // Verify that cancellation was NOT logged (control-flow exceptions should not be logged) + Assert.DoesNotContain(mockLogger.Logs, log => + log.LogLevel == LogLevel.Information && + log.Message != null && log.Message.Contains("was cancelled")); + } + + /// + /// Tests that the cancellation token is passed through to the service layer. + /// + /// A task representing the asynchronous test operation. + [Fact] + public async Task Run_PassesCancellationToken_ToServiceLayer() + { + // Arrange + Mock mockRequest = SetUpMockRequest(); + var cancellationTokenSource = new CancellationTokenSource(); + var mockCaseInfo = new CaseSummaryResponse(123, "06SC1234572", "Will", "SMITH", 2, "Hull UT"); + + CancellationToken capturedToken = default; + + mockCaseInfoService + .Setup(x => x.GetCaseInfoAsync(123, It.IsAny(), It.IsAny())) + .Callback((caseId, authValues, ct) => + { + capturedToken = ct; + }) + .ReturnsAsync(mockCaseInfo); + + // Act + await getCaseInfoFunction.Run(mockRequest.Object, 123, cancellationTokenSource.Token); + + // Assert + Assert.Equal(cancellationTokenSource.Token, capturedToken); + + mockCaseInfoService.Verify( + x => x.GetCaseInfoAsync(123, It.IsAny(), cancellationTokenSource.Token), + Times.Once); } private static Mock SetUpMockRequest() @@ -153,6 +255,13 @@ private static Mock SetUpMockRequest() // Set up a DefaultHttpContext to support setting headers var context = new DefaultHttpContext(); + + // Set up cookies + var mockCookies = new Mock(); + mockCookies.Setup(c => c.TryGetValue(It.IsAny(), out It.Ref.IsAny)) + .Returns(false); + + mockRequest.Setup(r => r.Cookies).Returns(mockCookies.Object); mockRequest.Setup(r => r.HttpContext).Returns(context); mockRequest.Setup(r => r.Headers.Add("corelation", "1232131231")); diff --git a/polaris-gateway.tests/Services/Artefact/OcrArtefactServiceTests.cs b/polaris-gateway.tests/Services/Artefact/OcrArtefactServiceTests.cs index 9011745c5..b72072e1d 100644 --- a/polaris-gateway.tests/Services/Artefact/OcrArtefactServiceTests.cs +++ b/polaris-gateway.tests/Services/Artefact/OcrArtefactServiceTests.cs @@ -161,7 +161,13 @@ public async Task GetOcrAsync_WhenOperationIdIsNotProvidedAndPdfIsNotAvailable_W }; _pdfArtefactServiceMock - .Setup(x => x.GetPdfAsync(_cmsAuthValues, _correlationId, _urn, _caseId, _documentId, _versionId, false, false)) + .Setup(x => x.GetPdfAsync(It.Is(r => + r.Urn == _urn && + r.CaseId == _caseId && + r.MaterialId == _documentId && + r.DocumentId == _versionId && + r.IsOcrProcessed == false && + r.ForceRefresh == false), _cmsAuthValues, _correlationId, default)) .ReturnsAsync(pdfResult); var expectedResult = new ArtefactResult(); @@ -192,7 +198,13 @@ public async Task GetOcrAsync_WhenOperationIdIsNotProvidedAndPdfIsAvailable_Will }; _pdfArtefactServiceMock - .Setup(x => x.GetPdfAsync(_cmsAuthValues, _correlationId, _urn, _caseId, _documentId, _versionId, false, false)) + .Setup(x => x.GetPdfAsync(It.Is(r => + r.Urn == _urn && + r.CaseId == _caseId && + r.MaterialId == _documentId && + r.DocumentId == _versionId && + r.IsOcrProcessed == false && + r.ForceRefresh == false), _cmsAuthValues, _correlationId, default)) .ReturnsAsync(pdfResult); var newOperationId = _fixture.Create(); diff --git a/polaris-gateway.tests/Services/Artefact/PdfArtefactServiceTests.cs b/polaris-gateway.tests/Services/Artefact/PdfArtefactServiceTests.cs index 34ad41d7b..48de4ed7c 100644 --- a/polaris-gateway.tests/Services/Artefact/PdfArtefactServiceTests.cs +++ b/polaris-gateway.tests/Services/Artefact/PdfArtefactServiceTests.cs @@ -78,7 +78,13 @@ public async Task GetPdfAsync_WhenAPdfIsAlreadyInCache_WillReturnCachedPdf() .Returns(expectedResult); // Act - var result = await _pdfArtefactService.GetPdfAsync(_cmsAuthValues, _correlationId, _urn, _caseId, _documentId, _versionId, false); + var request = new GetPdfRequest( + Urn: _urn, + CaseId: _caseId, + MaterialId: _documentId, + DocumentId: _versionId, + IsOcrProcessed: false); + var result = await _pdfArtefactService.GetPdfAsync(request, _cmsAuthValues, _correlationId); // Assert result.Should().Be(expectedResult); @@ -103,7 +109,13 @@ public async Task GetPdfAsync_WhenAPdfIsNotAlreadyInCacheAndConversionFails_Will .Returns(expectedResult); // Act - var result = await _pdfArtefactService.GetPdfAsync(_cmsAuthValues, _correlationId, _urn, _caseId, _documentId, _versionId, false); + var request = new GetPdfRequest( + Urn: _urn, + CaseId: _caseId, + MaterialId: _documentId, + DocumentId: _versionId, + IsOcrProcessed: false); + var result = await _pdfArtefactService.GetPdfAsync(request, _cmsAuthValues, _correlationId); // Assert result.Should().Be(expectedResult); @@ -155,7 +167,13 @@ public async Task GetPdfAsync_WhenAPdfIsNotAlreadyInCacheAndConversionSucceeds_W .Returns(expectedResult); // Act - var result = await _pdfArtefactService.GetPdfAsync(_cmsAuthValues, _correlationId, _urn, _caseId, _documentId, _versionId, false); + var request = new GetPdfRequest( + Urn: _urn, + CaseId: _caseId, + MaterialId: _documentId, + DocumentId: _versionId, + IsOcrProcessed: false); + var result = await _pdfArtefactService.GetPdfAsync(request, _cmsAuthValues, _correlationId); // Assert result.Should().Be(expectedResult); @@ -183,14 +201,13 @@ public async Task GetPdfAsync_WhenCachedPdfExceedsSizeLimit_ShouldReturnLargeFil .Returns(expectedResult); // Act - var result = await _pdfArtefactService.GetPdfAsync( - _cmsAuthValues, - _correlationId, - _urn, - _caseId, - _documentId, - _versionId, - false); + var request = new GetPdfRequest( + Urn: _urn, + CaseId: _caseId, + MaterialId: _documentId, + DocumentId: _versionId, + IsOcrProcessed: false); + var result = await _pdfArtefactService.GetPdfAsync(request, _cmsAuthValues, _correlationId); // Assert result.Should().Be(expectedResult); @@ -221,14 +238,13 @@ public async Task GetPdfAsync_WhenCachedPdfWithinLimit_ShouldReturnNormalResult( .Returns(expectedResult); // Act - var result = await _pdfArtefactService.GetPdfAsync( - _cmsAuthValues, - _correlationId, - _urn, - _caseId, - _documentId, - _versionId, - false); + var request = new GetPdfRequest( + Urn: _urn, + CaseId: _caseId, + MaterialId: _documentId, + DocumentId: _versionId, + IsOcrProcessed: false); + var result = await _pdfArtefactService.GetPdfAsync(request, _cmsAuthValues, _correlationId); // Assert result.Should().Be(expectedResult); @@ -289,9 +305,13 @@ public async Task GetPdfAsync_WhenNewPdfExceedsSizeLimit_ShouldReturnLargeFileFl .Returns(expectedResult); // Act - var result = await _pdfArtefactService.GetPdfAsync( - _cmsAuthValues, _correlationId, _urn, - _caseId, _documentId, _versionId, false); + var request = new GetPdfRequest( + Urn: _urn, + CaseId: _caseId, + MaterialId: _documentId, + DocumentId: _versionId, + IsOcrProcessed: false); + var result = await _pdfArtefactService.GetPdfAsync(request, _cmsAuthValues, _correlationId); // Assert result.Should().Be(expectedResult); diff --git a/polaris-gateway/Functions/AddDocumentNote.cs b/polaris-gateway/Functions/AddDocumentNote.cs index e74af2399..65003bc1c 100644 --- a/polaris-gateway/Functions/AddDocumentNote.cs +++ b/polaris-gateway/Functions/AddDocumentNote.cs @@ -15,6 +15,7 @@ using PolarisGateway.TelemetryEvents; using PolarisGateway.Validators; using System.Net; +using System.Threading; using System.Threading.Tasks; namespace PolarisGateway.Functions; @@ -51,7 +52,8 @@ public AddDocumentNote( public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = RestApi.DocumentNotes)] HttpRequest req, string caseUrn, int caseId, - string materialId) + string materialId, + CancellationToken cancellationToken = default) { var telemetryEvent = new DocumentNoteRequestEvent(caseId, materialId) { diff --git a/polaris-gateway/Functions/CancelCheckoutDocument.cs b/polaris-gateway/Functions/CancelCheckoutDocument.cs index 80d7e65d2..7ee226c27 100644 --- a/polaris-gateway/Functions/CancelCheckoutDocument.cs +++ b/polaris-gateway/Functions/CancelCheckoutDocument.cs @@ -11,6 +11,7 @@ using Microsoft.Extensions.Logging; using Microsoft.OpenApi.Models; using System.Net; +using System.Threading; using System.Threading.Tasks; namespace PolarisGateway.Functions; @@ -43,7 +44,7 @@ public CancelCheckoutDocument( [OpenApiResponseWithoutBody(statusCode: HttpStatusCode.NoContent, Summary = "Invalid request", Description = "Missing or invalid parameters")] public async Task Run( - [HttpTrigger(AuthorizationLevel.Anonymous, "delete", Route = RestApi.DocumentCheckout)] HttpRequest req, string caseUrn, int caseId, string materialId, long documentId) + [HttpTrigger(AuthorizationLevel.Anonymous, "delete", Route = RestApi.DocumentCheckout)] HttpRequest req, string caseUrn, int caseId, string materialId, long documentId, CancellationToken cancellationToken = default) { var correlationId = EstablishCorrelation(req); var cmsAuthValues = EstablishCmsAuthValues(req); @@ -56,7 +57,7 @@ public async Task Run( materialId: materialId, documentId: documentId); - await _mdsClient.CancelCheckoutDocumentAsync(mdsDocumentIdAndVersionIdArgDto); + await _mdsClient.CancelCheckoutDocumentAsync(mdsDocumentIdAndVersionIdArgDto, cancellationToken: cancellationToken); return new OkResult(); } diff --git a/polaris-gateway/Functions/CheckoutDocument.cs b/polaris-gateway/Functions/CheckoutDocument.cs index 3e8746ec4..b3ad72f5a 100644 --- a/polaris-gateway/Functions/CheckoutDocument.cs +++ b/polaris-gateway/Functions/CheckoutDocument.cs @@ -10,6 +10,7 @@ using Microsoft.Extensions.Logging; using Microsoft.OpenApi.Models; using System.Net; +using System.Threading; using System.Threading.Tasks; namespace PolarisGateway.Functions; @@ -40,7 +41,7 @@ public CheckoutDocument( [OpenApiParameter("materialId", In = ParameterLocation.Path, Type = typeof(long), Description = "The document Id (version) of the material which has to be checked out", Required = true)] [OpenApiResponseWithBody(statusCode: HttpStatusCode.OK, contentType: "application/json", bodyType: typeof(object), Summary = "Case found", Description = "Returns case details")] [OpenApiResponseWithoutBody(statusCode: HttpStatusCode.NoContent, Summary = "Invalid request", Description = "Missing or invalid parameters")] - public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = RestApi.DocumentCheckout)] HttpRequest req, string caseUrn, int caseId, string materialId, long documentId) + public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = RestApi.DocumentCheckout)] HttpRequest req, string caseUrn, int caseId, string materialId, long documentId, CancellationToken cancellationToken = default) { var correlationId = EstablishCorrelation(req); var cmsAuthValues = EstablishCmsAuthValues(req); @@ -53,7 +54,7 @@ public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, materialId: materialId, documentId: documentId); - await _mdsClient.CheckoutDocumentAsync(mdsDocumentIdAndVersionIdArgDto); + await _mdsClient.CheckoutDocumentAsync(mdsDocumentIdAndVersionIdArgDto, cancellationToken); return new OkResult(); } } \ No newline at end of file diff --git a/polaris-gateway/Functions/GenerateThumbnail.cs b/polaris-gateway/Functions/GenerateThumbnail.cs index d2899c06b..55747074c 100644 --- a/polaris-gateway/Functions/GenerateThumbnail.cs +++ b/polaris-gateway/Functions/GenerateThumbnail.cs @@ -12,6 +12,7 @@ using PolarisGateway.Extensions; using System; using System.Net; +using System.Threading; using System.Threading.Tasks; namespace PolarisGateway.Functions; @@ -47,8 +48,9 @@ public GenerateThumbnail( [OpenApiResponseWithBody(statusCode: HttpStatusCode.OK, contentType: "application/json", bodyType: typeof(AddDocumentNoteRequestDto), Summary = "Case found", Description = "Returns case details")] [OpenApiResponseWithoutBody(statusCode: HttpStatusCode.NoContent, Summary = "Invalid request", Description = "Missing or invalid parameters")] public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = RestApi.GenerateThumbnail)] HttpRequest req, - string caseUrn, int caseId, string materialId, int documentId, int maxDimensionPixel, int? pageIndex) + string caseUrn, int caseId, string materialId, int documentId, int maxDimensionPixel, int? pageIndex, CancellationToken cancellationToken = default) { + cancellationToken.ThrowIfCancellationRequested(); var correlationId = EstablishCorrelation(req); var cmsAuthValues = EstablishCmsAuthValues(req); diff --git a/polaris-gateway/Functions/GetCase.cs b/polaris-gateway/Functions/GetCase.cs index ac6c4de78..45be54f3a 100644 --- a/polaris-gateway/Functions/GetCase.cs +++ b/polaris-gateway/Functions/GetCase.cs @@ -12,6 +12,7 @@ using Microsoft.OpenApi.Models; using System; using System.Net; +using System.Threading; using PolarisGateway.Services.MdsOrchestration; using System.Threading.Tasks; @@ -43,7 +44,7 @@ public GetCase( [OpenApiResponseWithBody(statusCode: HttpStatusCode.OK,contentType: "application/json",bodyType: typeof(object),Summary = "Case found",Description = "Returns case details")] [OpenApiResponseWithoutBody(statusCode: HttpStatusCode.NoContent, Summary = "Invalid request",Description = "Missing or invalid parameters")] public async Task Run( - [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = RestApi.Case)] HttpRequest req, string caseUrn, int caseId) + [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = RestApi.Case)] HttpRequest req, string caseUrn, int caseId, CancellationToken cancellationToken = default) { var correlationId = EstablishCorrelation(req); @@ -51,7 +52,7 @@ public async Task Run( var arg = _mdsArgFactory.CreateCaseIdentifiersArg(cmsAuthValues, correlationId, caseUrn, caseId); - var result = await _mdsOrchestrationService.GetCase(arg); + var result = await _mdsOrchestrationService.GetCase(arg, cancellationToken); return new OkObjectResult(result); } diff --git a/polaris-gateway/Functions/GetCases.cs b/polaris-gateway/Functions/GetCases.cs index 7f05bcee2..39efa4f6c 100644 --- a/polaris-gateway/Functions/GetCases.cs +++ b/polaris-gateway/Functions/GetCases.cs @@ -11,6 +11,7 @@ using Microsoft.OpenApi.Models; using System.Collections.Generic; using System.Net; +using System.Threading; using PolarisGateway.Services.MdsOrchestration; using System.Threading.Tasks; @@ -41,14 +42,14 @@ public GetCases( [OpenApiResponseWithBody(statusCode: HttpStatusCode.OK, contentType: "application/json", bodyType: typeof(IEnumerable), Summary = "List of cases for a case URN", Description = "Returns case list for the given URN")] [OpenApiResponseWithoutBody(statusCode: HttpStatusCode.NoContent, Summary = "Invalid request", Description = "Missing or invalid parameters")] - public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = RestApi.Cases)] HttpRequest req, string caseUrn) + public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = RestApi.Cases)] HttpRequest req, string caseUrn, CancellationToken cancellationToken = default) { var correlationId = EstablishCorrelation(req); var cmsAuthValues = EstablishCmsAuthValues(req); var arg = _mdsArgFactory.CreateUrnArg(cmsAuthValues, correlationId, caseUrn); - var result = await _mdsOrchestrationService.GetCases(arg); + var result = await _mdsOrchestrationService.GetCases(arg, cancellationToken); return new OkObjectResult(result); } diff --git a/polaris-gateway/Functions/GetDocumentList.cs b/polaris-gateway/Functions/GetDocumentList.cs index 1a9d02f31..0923d5f24 100644 --- a/polaris-gateway/Functions/GetDocumentList.cs +++ b/polaris-gateway/Functions/GetDocumentList.cs @@ -13,6 +13,7 @@ using System.Collections; using System.Collections.Generic; using System.Net; +using System.Threading; using Ddei.Factories; using Microsoft.Azure.Functions.Worker; using System.Threading.Tasks; @@ -50,10 +51,11 @@ public GetDocumentList( [OpenApiParameter("caseId", In = ParameterLocation.Path, Type = typeof(int), Description = "The Id of the case.", Required = true)] [OpenApiResponseWithBody(statusCode: HttpStatusCode.OK, contentType: "application/json", bodyType: typeof(IEnumerable), Summary = "Document List", Description = "Returns list of documennts")] [OpenApiResponseWithoutBody(statusCode: HttpStatusCode.NoContent, Summary = "Invalid request", Description = "Missing or invalid parameters")] - public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = RestApi.Documents)] HttpRequest req, string caseUrn, int caseId) + public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = RestApi.Documents)] HttpRequest req, string caseUrn, int caseId, CancellationToken cancellationToken = default) { var correlationId = EstablishCorrelation(req); var cmsAuthValues = EstablishCmsAuthValues(req); + cancellationToken.ThrowIfCancellationRequested(); var arg = _mdsArgFactory.CreateCaseIdentifiersArg(cmsAuthValues, correlationId, caseUrn, caseId); var result = await _mdsOrchestrationService.GetCaseDocuments(arg); diff --git a/polaris-gateway/Functions/GetDocumentNotes.cs b/polaris-gateway/Functions/GetDocumentNotes.cs index 9ce2cc84e..487066c52 100644 --- a/polaris-gateway/Functions/GetDocumentNotes.cs +++ b/polaris-gateway/Functions/GetDocumentNotes.cs @@ -12,6 +12,7 @@ using Microsoft.OpenApi.Models; using System.Collections.Generic; using System.Net; +using System.Threading; using System.Threading.Tasks; namespace PolarisGateway.Functions; @@ -41,14 +42,14 @@ public GetDocumentNotes(ILogger logger, [OpenApiParameter("materialId", In = ParameterLocation.Path, Type = typeof(string), Description = "The Id of the material", Required = true)] [OpenApiResponseWithBody(statusCode: HttpStatusCode.OK, contentType: "application/json", bodyType: typeof(IEnumerable), Summary = "Document Note List", Description = "Returns list of document notes")] [OpenApiResponseWithoutBody(statusCode: HttpStatusCode.NoContent, Summary = "Invalid request", Description = "Missing or invalid parameters")] - public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = RestApi.DocumentNotes)] HttpRequest req, string caseUrn, int caseId, string materialId) + public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = RestApi.DocumentNotes)] HttpRequest req, string caseUrn, int caseId, string materialId, CancellationToken cancellationToken = default) { var correlationId = EstablishCorrelation(req); var cmsAuthValues = EstablishCmsAuthValues(req); var arg = _mdsArgFactory.CreateDocumentArgDto(cmsAuthValues, correlationId, caseUrn, caseId, materialId); - var result = await _mdsClient.GetDocumentNotesAsync(arg); + var result = await _mdsClient.GetDocumentNotesAsync(arg, cancellationToken: cancellationToken); return new OkObjectResult(result); } diff --git a/polaris-gateway/Functions/GetExhibitProducers.cs b/polaris-gateway/Functions/GetExhibitProducers.cs index 21482cfdc..0e2a2527c 100644 --- a/polaris-gateway/Functions/GetExhibitProducers.cs +++ b/polaris-gateway/Functions/GetExhibitProducers.cs @@ -13,6 +13,7 @@ using System.Collections; using System.Collections.Generic; using System.Net; +using System.Threading; using System.Threading.Tasks; namespace PolarisGateway.Functions; @@ -41,14 +42,14 @@ public GetExhibitProducers(ILogger logger, [OpenApiParameter("caseId", In = ParameterLocation.Path, Type = typeof(int), Description = "The Id of the case to add a new action plan.", Required = true)] [OpenApiResponseWithBody(statusCode: HttpStatusCode.OK, contentType: "application/json", bodyType: typeof(IEnumerable), Summary = "Case exhibit producers", Description = "Returns the list of exhibit producers")] [OpenApiResponseWithoutBody(statusCode: HttpStatusCode.NoContent, Summary = "Invalid request", Description = "Missing or invalid parameters")] - public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = RestApi.CaseExhibitProducers)] HttpRequest req, string caseUrn, int caseId) + public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = RestApi.CaseExhibitProducers)] HttpRequest req, string caseUrn, int caseId, CancellationToken cancellationToken = default) { var correlationId = EstablishCorrelation(req); var cmsAuthValues = EstablishCmsAuthValues(req); var mdsCaseIdentifiersArgDto = _mdsArgFactory.CreateCaseIdentifiersArg(cmsAuthValues, correlationId, caseUrn, caseId); - var exhibitProducerDtos = await _mdsClient.GetExhibitProducersAsync(mdsCaseIdentifiersArgDto); + var exhibitProducerDtos = await _mdsClient.GetExhibitProducersAsync(mdsCaseIdentifiersArgDto, cancellationToken: cancellationToken); return new OkObjectResult(exhibitProducerDtos); } diff --git a/polaris-gateway/Functions/GetMaterialTypeList.cs b/polaris-gateway/Functions/GetMaterialTypeList.cs index 0d2757c7b..8defbb733 100644 --- a/polaris-gateway/Functions/GetMaterialTypeList.cs +++ b/polaris-gateway/Functions/GetMaterialTypeList.cs @@ -13,6 +13,7 @@ using Microsoft.OpenApi.Models; using System.Collections.Generic; using System.Net; +using System.Threading; using System.Threading.Tasks; namespace PolarisGateway.Functions; @@ -40,13 +41,13 @@ public GetMaterialTypeList( [OpenApiResponseWithBody(statusCode: HttpStatusCode.OK, contentType: "application/json", bodyType: typeof(IEnumerable), Summary = "Material Type List", Description = "Returns the list of material types")] [OpenApiResponseWithoutBody(statusCode: HttpStatusCode.NoContent, Summary = "Invalid request", Description = "Missing or invalid parameters")] - public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = RestApi.MaterialTypeList)] HttpRequest req) + public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = RestApi.MaterialTypeList)] HttpRequest req, CancellationToken cancellationToken = default) { var correlationId = EstablishCorrelation(req); var cmsAuthValues = EstablishCmsAuthValues(req); var mdsBaseArgDto = _mdsArgFactory.CreateCmsCaseDataArgDto(cmsAuthValues, correlationId); - var materialTypes = await _mdsClient.GetMaterialTypeListAsync(mdsBaseArgDto); + var materialTypes = await _mdsClient.GetMaterialTypeListAsync(mdsBaseArgDto, cancellationToken); return new OkObjectResult(materialTypes); } diff --git a/polaris-gateway/Functions/GetOcr.cs b/polaris-gateway/Functions/GetOcr.cs index af3a6921b..0b7956e2b 100644 --- a/polaris-gateway/Functions/GetOcr.cs +++ b/polaris-gateway/Functions/GetOcr.cs @@ -8,6 +8,7 @@ using PolarisGateway.Services.Artefact.Domain; using System; using System.Net; +using System.Threading; using System.Threading.Tasks; using Common.Extensions; using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Attributes; @@ -46,8 +47,9 @@ public GetOcr( [OpenApiResponseWithBody(statusCode: HttpStatusCode.OK, contentType: "application/json", bodyType: typeof(ArtefactResult), Summary = "Artefact Result", Description = "Gives the artefact results")] [OpenApiResponseWithoutBody(statusCode: HttpStatusCode.NoContent, Summary = "Invalid request", Description = "Missing or invalid parameters")] public async Task Run( - [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = RestApi.Ocr)] HttpRequest req, string caseUrn, int caseId, string materialId, long documentId) + [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = RestApi.Ocr)] HttpRequest req, string caseUrn, int caseId, string materialId, long documentId, CancellationToken cancellationToken = default) { + cancellationToken.ThrowIfCancellationRequested(); var correlationId = EstablishCorrelation(req); var cmsAuthValues = EstablishCmsAuthValues(req); diff --git a/polaris-gateway/Functions/GetPdf.cs b/polaris-gateway/Functions/GetPdf.cs index b42e1e01c..7534a1903 100644 --- a/polaris-gateway/Functions/GetPdf.cs +++ b/polaris-gateway/Functions/GetPdf.cs @@ -12,6 +12,7 @@ using PolarisGateway.Services.Artefact.Domain; using System.IO; using System.Net; +using System.Threading; using System.Threading.Tasks; @@ -47,14 +48,23 @@ public GetPdf( [OpenApiResponseWithoutBody(statusCode: HttpStatusCode.NoContent, Summary = "Invalid request", Description = "Missing or invalid parameters")] public async Task Run( - [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = RestApi.Pdf)] HttpRequest req, string caseUrn, int caseId, string materialId, long documentId) + [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = RestApi.Pdf)] HttpRequest req, string caseUrn, int caseId, string materialId, long documentId, CancellationToken cancellationToken = default) { var correlationId = EstablishCorrelation(req); var cmsAuthValues = EstablishCmsAuthValues(req); var isOcrProcessed = req.Query.ContainsKey(isOcrProcessedParamName) && bool.Parse(req.Query[isOcrProcessedParamName]); var forceRefresh = req.Query.ContainsKey(ForceRefreshParamName) && bool.Parse(req.Query[ForceRefreshParamName]); - var getPdfResult = await _pdfArtefactService.GetPdfAsync(cmsAuthValues, correlationId, caseUrn, caseId, materialId, documentId, isOcrProcessed, forceRefresh); + + var request = new GetPdfRequest( + Urn: caseUrn, + CaseId: caseId, + MaterialId: materialId, + DocumentId: documentId, + IsOcrProcessed: isOcrProcessed, + ForceRefresh: forceRefresh); + + var getPdfResult = await _pdfArtefactService.GetPdfAsync(request, cmsAuthValues, correlationId, cancellationToken); if (getPdfResult.FileSizeExceedsLimit == true) { diff --git a/polaris-gateway/Functions/GetPii.cs b/polaris-gateway/Functions/GetPii.cs index f7f332bbd..a003008b1 100644 --- a/polaris-gateway/Functions/GetPii.cs +++ b/polaris-gateway/Functions/GetPii.cs @@ -17,6 +17,7 @@ using System.Collections; using System.Collections.Generic; using System.Net; +using System.Threading; using System.Threading.Tasks; @@ -54,8 +55,9 @@ public GetPii( [OpenApiResponseWithoutBody(statusCode: HttpStatusCode.NoContent, Summary = "Invalid request", Description = "Missing or invalid parameters")] public async Task Run( - [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = RestApi.Pii)] HttpRequest req, string caseUrn, int caseId, string materialId, long documentId) + [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = RestApi.Pii)] HttpRequest req, string caseUrn, int caseId, string materialId, long documentId, CancellationToken cancellationToken = default) { + cancellationToken.ThrowIfCancellationRequested(); var correlationId = EstablishCorrelation(req); var cmsAuthValues = EstablishCmsAuthValues(req); diff --git a/polaris-gateway/Functions/GetThumbnail.cs b/polaris-gateway/Functions/GetThumbnail.cs index db96662d8..3175b2ee1 100644 --- a/polaris-gateway/Functions/GetThumbnail.cs +++ b/polaris-gateway/Functions/GetThumbnail.cs @@ -16,6 +16,7 @@ using System.Collections.Generic; using System.Net; using System.Net.Http; +using System.Threading; using System.Threading.Tasks; namespace PolarisGateway.Functions; @@ -53,7 +54,7 @@ public GetThumbnail( public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = RestApi.Thumbnail)] HttpRequest req, - string caseUrn, int caseId, string materialId, int documentId, int maxDimensionPixel, int pageIndex) + string caseUrn, int caseId, string materialId, int documentId, int maxDimensionPixel, int pageIndex, CancellationToken cancellationToken = default) { var correlationId = EstablishCorrelation(req); var cmsAuthValues = EstablishCmsAuthValues(req); diff --git a/polaris-gateway/Functions/GetWitnessStatements.cs b/polaris-gateway/Functions/GetWitnessStatements.cs index 10f3ef8e9..ca77c5384 100644 --- a/polaris-gateway/Functions/GetWitnessStatements.cs +++ b/polaris-gateway/Functions/GetWitnessStatements.cs @@ -12,6 +12,7 @@ using Microsoft.OpenApi.Models; using System.Collections.Generic; using System.Net; +using System.Threading; using System.Threading.Tasks; namespace PolarisGateway.Functions; @@ -42,13 +43,13 @@ public GetWitnessStatements( [OpenApiResponseWithBody(statusCode: HttpStatusCode.OK, contentType: "application/json", bodyType: typeof(IEnumerable), Summary = "Case found", Description = "Returns case details")] [OpenApiResponseWithoutBody(statusCode: HttpStatusCode.NoContent, Summary = "Invalid request", Description = "Missing or invalid parameters")] - public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = RestApi.WitnessStatements)] HttpRequest req, string caseUrn, int caseId, int witnessId) + public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = RestApi.WitnessStatements)] HttpRequest req, string caseUrn, int caseId, int witnessId, CancellationToken cancellationToken = default) { var correlationId = EstablishCorrelation(req); var cmsAuthValues = EstablishCmsAuthValues(req); var witnessStatementsArgDto = _mdsArgFactory.CreateWitnessStatementsArgDto(cmsAuthValues, correlationId, caseUrn, caseId, witnessId); - var witnessStatementDtos = await _mdsClient.GetWitnessStatementsAsync(witnessStatementsArgDto); + var witnessStatementDtos = await _mdsClient.GetWitnessStatementsAsync(witnessStatementsArgDto, cancellationToken: cancellationToken); return new OkObjectResult(witnessStatementDtos); } diff --git a/polaris-gateway/Functions/GetWitnesses.cs b/polaris-gateway/Functions/GetWitnesses.cs index 307f62bb1..8b237327d 100644 --- a/polaris-gateway/Functions/GetWitnesses.cs +++ b/polaris-gateway/Functions/GetWitnesses.cs @@ -14,6 +14,7 @@ using System.Collections.Generic; using System.Linq; using System.Net; +using System.Threading; using System.Threading.Tasks; namespace PolarisGateway.Functions; @@ -46,14 +47,14 @@ public GetWitnesses( [OpenApiResponseWithBody(statusCode: HttpStatusCode.OK, contentType: "application/json", bodyType: typeof(IEnumerable), Summary = "Case found", Description = "Returns case details")] [OpenApiResponseWithoutBody(statusCode: HttpStatusCode.NoContent, Summary = "Invalid request", Description = "Missing or invalid parameters")] - public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = RestApi.CaseWitnesses)] HttpRequest req, string caseUrn, int caseId) + public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = RestApi.CaseWitnesses)] HttpRequest req, string caseUrn, int caseId, CancellationToken cancellationToken = default) { var correlationId = EstablishCorrelation(req); var cmsAuthValues = EstablishCmsAuthValues(req); var arg = _mdsArgFactory.CreateCaseIdentifiersArg(cmsAuthValues, correlationId, caseUrn, caseId); - var caseWitnessResponses = await _mdsClient.GetWitnessesAsync(arg); + var caseWitnessResponses = await _mdsClient.GetWitnessesAsync(arg, cancellationToken: cancellationToken); var caseWitnesses = caseWitnessResponses.Select(_caseWitnessMapper.Map); return new OkObjectResult(caseWitnesses); diff --git a/polaris-gateway/Functions/HouseKeeping/BulkSetUnused.cs b/polaris-gateway/Functions/HouseKeeping/BulkSetUnused.cs index fdfaabe59..4630beda8 100644 --- a/polaris-gateway/Functions/HouseKeeping/BulkSetUnused.cs +++ b/polaris-gateway/Functions/HouseKeeping/BulkSetUnused.cs @@ -10,6 +10,7 @@ namespace PolarisGateway.Functions.HouseKeeping; using System.IO; using System.Net; using System.Text.Json; +using System.Threading; using System.Threading.Tasks; using Azure.Core; using Common.Configuration; @@ -53,7 +54,7 @@ public class BulkSetUnused(ILogger logger, IBulkSetUnusedService [OpenApiRequestBody("application/json", typeof(BulkSetUnusedResponse), Description = "Return success response.")] [OpenApiResponseWithoutBody(statusCode: HttpStatusCode.OK)] [Function("BulkSetUnused")] - public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = RestApi.BulkSetUnused)] HttpRequest req, int caseId) + public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = RestApi.BulkSetUnused)] HttpRequest req, int caseId, CancellationToken cancellationToken = default) { try { @@ -83,7 +84,7 @@ public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, return new BadRequestObjectResult($"{LoggingConstants.HskUiLogPrefix} Invalid or empty request body."); } - BulkSetUnusedResponse result = await this.bulkSetUnusedService.BulkSetUnusedAsync(caseId, cmsAuthValues, bulkSetUnusedRequests).ConfigureAwait(true); + BulkSetUnusedResponse result = await this.bulkSetUnusedService.BulkSetUnusedAsync(caseId, cmsAuthValues, bulkSetUnusedRequests, cancellationToken).ConfigureAwait(true); if (result.Status?.Equals("failed") == true) { diff --git a/polaris-gateway/Functions/HouseKeeping/CompleteReclassification.cs b/polaris-gateway/Functions/HouseKeeping/CompleteReclassification.cs index 089d1a951..ad39325bf 100644 --- a/polaris-gateway/Functions/HouseKeeping/CompleteReclassification.cs +++ b/polaris-gateway/Functions/HouseKeeping/CompleteReclassification.cs @@ -8,6 +8,7 @@ namespace PolarisGateway.Functions.HouseKeeping; using Microsoft.AspNetCore.Mvc; using Microsoft.Azure.Functions.Worker; using Microsoft.Extensions.Logging; +using System.Threading; using System.Threading.Tasks; using Cps.Fct.Hk.Ui.Interfaces; using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Attributes; @@ -63,7 +64,7 @@ public class CompleteReclassification( [Function("CompleteReclassification")] public async Task Run( [HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = RestApi.CompleteReclassification)] - HttpRequest request, int caseId, int materialId) + HttpRequest request, int caseId, int materialId, CancellationToken cancellationToken = default) { try { @@ -102,7 +103,8 @@ public async Task Run( caseId, materialId, cmsAuthValues, - completeReclassificationRequest).ConfigureAwait(false); + completeReclassificationRequest, + cancellationToken).ConfigureAwait(false); // All operations succeeded. if (result?.overallSuccess == true) diff --git a/polaris-gateway/Functions/HouseKeeping/DiscardMaterial.cs b/polaris-gateway/Functions/HouseKeeping/DiscardMaterial.cs index 3b7df567a..90b5aabeb 100644 --- a/polaris-gateway/Functions/HouseKeeping/DiscardMaterial.cs +++ b/polaris-gateway/Functions/HouseKeeping/DiscardMaterial.cs @@ -8,6 +8,7 @@ namespace PolarisGateway.Functions.HouseKeeping; using Microsoft.AspNetCore.Mvc; using Microsoft.Azure.Functions.Worker; using Microsoft.Extensions.Logging; +using System.Threading; using System.Threading.Tasks; using Cps.Fct.Hk.Ui.Interfaces; using System.Diagnostics; @@ -53,7 +54,7 @@ public class DiscardMaterial( [OpenApiResponseWithoutBody(statusCode: HttpStatusCode.UnprocessableEntity)] [OpenApiResponseWithoutBody(statusCode: HttpStatusCode.Unauthorized)] [Function("DiscardMaterial")] - public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, "patch", Route = RestApi.DiscardMaterial)] HttpRequest request, int caseId, int materialId) + public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, "patch", Route = RestApi.DiscardMaterial)] HttpRequest request, int caseId, int materialId, CancellationToken cancellationToken = default) { try { @@ -91,7 +92,8 @@ public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, discardMaterialRequest.materialId, discardMaterialRequest.discardReason, discardMaterialRequest.discardReasonDescription, - cmsAuthValues).ConfigureAwait(true); + cmsAuthValues, + cancellationToken: cancellationToken).ConfigureAwait(true); if (result?.DiscardMaterialData?.Id == null) { diff --git a/polaris-gateway/Functions/HouseKeeping/GetCaseDefendants.cs b/polaris-gateway/Functions/HouseKeeping/GetCaseDefendants.cs index dc8617b0a..b63f9a241 100644 --- a/polaris-gateway/Functions/HouseKeeping/GetCaseDefendants.cs +++ b/polaris-gateway/Functions/HouseKeeping/GetCaseDefendants.cs @@ -8,6 +8,7 @@ namespace PolarisGateway.Functions.HouseKeeping; using Microsoft.AspNetCore.Mvc; using Microsoft.Azure.Functions.Worker; using Microsoft.Extensions.Logging; +using System.Threading; using System.Threading.Tasks; using Cps.Fct.Hk.Ui.Interfaces; using System.Diagnostics; @@ -51,7 +52,7 @@ public class GetCaseDefendants( [OpenApiRequestBody("application/json", typeof(Defendant), Description = "Return case defendants response.")] [OpenApiResponseWithoutBody(statusCode: HttpStatusCode.OK)] [Function("GetCaseDefendants")] - public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = RestApi.CaseDefendants)] HttpRequest request, int caseId) + public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = RestApi.CaseDefendants)] HttpRequest request, int caseId, CancellationToken cancellationToken = default) { try { @@ -69,7 +70,7 @@ public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, DefendantsResponse? caseDefendants; try { - caseDefendants = await this.caseDefendantsService.GetCaseDefendantsAsync(caseId, cmsAuthValues).ConfigureAwait(true); + caseDefendants = await this.caseDefendantsService.GetCaseDefendantsAsync(caseId, cmsAuthValues, cancellationToken).ConfigureAwait(true); this.logger.LogInformation($"{LoggingConstants.HskUiLogPrefix} Milestone: caseId [{caseId}] GetCaseDefendants function completed in [{stopwatch.Elapsed}]"); var response = new OkObjectResult(caseDefendants); diff --git a/polaris-gateway/Functions/HouseKeeping/GetCaseExhibitProducers.cs b/polaris-gateway/Functions/HouseKeeping/GetCaseExhibitProducers.cs index 8d7d3598b..77a9fda3a 100644 --- a/polaris-gateway/Functions/HouseKeeping/GetCaseExhibitProducers.cs +++ b/polaris-gateway/Functions/HouseKeeping/GetCaseExhibitProducers.cs @@ -8,6 +8,7 @@ namespace PolarisGateway.Functions.HouseKeeping; using System.Diagnostics; using System.Linq; using System.Net; +using System.Threading; using System.Threading.Tasks; using Common.Configuration; using Common.Constants; @@ -51,7 +52,7 @@ public class GetCaseExhibitProducers(ILogger logger, [OpenApiResponseWithoutBody(statusCode: HttpStatusCode.UnprocessableEntity)] [OpenApiResponseWithoutBody(statusCode: HttpStatusCode.Unauthorized)] [Function(nameof(GetCaseExhibitProducers))] - public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = RestApi.ExhibitProducers)] HttpRequest request, int caseId) + public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = RestApi.ExhibitProducers)] HttpRequest request, int caseId, CancellationToken cancellationToken = default) { try { @@ -66,8 +67,8 @@ public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, // Build CMS auth values from cookie extracted from the request var cmsAuthValues = this.BuildCmsAuthValues(request); - var exhibitTask = this.communicationService.GetExhibitProducersAsync(caseId, cmsAuthValues); - var witnessTask = this.witnessService.GetCaseWitnessesAsync(caseId, cmsAuthValues); + var exhibitTask = this.communicationService.GetExhibitProducersAsync(caseId, cmsAuthValues, cancellationToken); + var witnessTask = this.witnessService.GetCaseWitnessesAsync(caseId, cmsAuthValues, cancellationToken); await Task.WhenAll(exhibitTask, witnessTask).ConfigureAwait(false); diff --git a/polaris-gateway/Functions/HouseKeeping/GetCaseHistoryEvent.cs b/polaris-gateway/Functions/HouseKeeping/GetCaseHistoryEvent.cs index 046164c43..8ea12e808 100644 --- a/polaris-gateway/Functions/HouseKeeping/GetCaseHistoryEvent.cs +++ b/polaris-gateway/Functions/HouseKeeping/GetCaseHistoryEvent.cs @@ -7,6 +7,7 @@ namespace PolarisGateway.Functions.HouseKeeping; using System; using System.Diagnostics; using System.Net; +using System.Threading; using System.Threading.Tasks; using Common.Configuration; using Common.Constants; @@ -53,7 +54,7 @@ public class GetCaseHistoryEvent( [OpenApiResponseWithoutBody(statusCode: HttpStatusCode.InternalServerError)] [Function(nameof(GetCaseHistoryEvent))] public async Task Run( - [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = RestApi.CaseHistoryEvent)] HttpRequest request, int caseId) + [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = RestApi.CaseHistoryEvent)] HttpRequest request, int caseId, CancellationToken cancellationToken = default) { try { @@ -68,7 +69,7 @@ public async Task Run( // Build CMS auth values from cookie extracted from the request var cmsAuthValues = this.BuildCmsAuthValues(request); - var result = await this.communicationService.GetHistoryEventsAsync(caseId, cmsAuthValues).ConfigureAwait(true); + var result = await this.communicationService.GetHistoryEventsAsync(caseId, cmsAuthValues, cancellationToken).ConfigureAwait(true); if (result == null) { diff --git a/polaris-gateway/Functions/HouseKeeping/GetCaseInfo.cs b/polaris-gateway/Functions/HouseKeeping/GetCaseInfo.cs index fb3b0722b..893f4b3c5 100644 --- a/polaris-gateway/Functions/HouseKeeping/GetCaseInfo.cs +++ b/polaris-gateway/Functions/HouseKeeping/GetCaseInfo.cs @@ -7,6 +7,7 @@ namespace PolarisGateway.Functions.HouseKeeping using System; using System.Diagnostics; using System.Net; + using System.Threading; using System.Threading.Tasks; using Common.Configuration; using Common.Constants; @@ -41,6 +42,7 @@ public class GetCaseInfo(ILogger logger, ICaseInfoService caseInfoS /// /// The HTTP request. /// The case Id. + /// The cancellation token to cancel the operation. /// An representing the response of the function. [OpenApiOperation(operationId: "GetCaseInfo", tags: ["Case"], Description = "Represents a function that retrieves the case information for display purposes.")] [OpenApiSecurity("function_key", SecuritySchemeType.ApiKey, Name = "x-functions-key", In = OpenApiSecurityLocationType.Header, Description = "The Azure Function API Key.")] @@ -48,32 +50,25 @@ public class GetCaseInfo(ILogger logger, ICaseInfoService caseInfoS [OpenApiRequestBody("application/json", typeof(CaseSummaryResponse), Description = "Return case summary response.")] [OpenApiResponseWithoutBody(statusCode: HttpStatusCode.OK)] [Function("GetCaseInfo")] - public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = RestApi.CaseInfo)] HttpRequest req, int caseId) + public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = RestApi.CaseInfo)] HttpRequest req, int caseId, CancellationToken cancellationToken = default) { try { var stopwatch = Stopwatch.StartNew(); - this.logger.LogInformation($"{LoggingConstants.HskUiLogPrefix} GetCaseInfo function processed a request."); - + this.logger.LogInformation("{Prefix} GetCaseInfo function processed a request.", LoggingConstants.HskUiLogPrefix); + if (caseId < 1) { return new BadRequestObjectResult($"{LoggingConstants.HskUiLogPrefix} Invalid case Id. It should be an integer."); } - + // Build CMS auth values from cookie extracted from the request var cmsAuthValues = this.BuildCmsAuthValues(req); CaseSummaryResponse caseSummary; - try - { - caseSummary = await this.caseInfoService.GetCaseInfoAsync(caseId, cmsAuthValues).ConfigureAwait(true); - this.logger.LogInformation(LoggingConstants.UnitNameExtractionSuccess, LoggingConstants.HskUiLogPrefix, caseSummary.UnitName, caseId); - } - catch (Exception ex) - { - this.logger.LogError($"{LoggingConstants.HskUiLogPrefix} GetCaseInfo function encountered an error fetching case information for caseId [{caseId}]: {ex.Message}"); - throw new UnprocessableEntityException($"GetCaseInfo function encountered an error fetching case information for caseId [{caseId}]"); - } + + caseSummary = await this.caseInfoService.GetCaseInfoAsync(caseId, cmsAuthValues, cancellationToken).ConfigureAwait(false); + this.logger.LogInformation(LoggingConstants.UnitNameExtractionSuccess, LoggingConstants.HskUiLogPrefix, caseSummary.UnitName, caseId); var response = new OkObjectResult(caseSummary); @@ -83,9 +78,15 @@ public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, return response; } + catch (OperationCanceledException) + { + // Let cancellation exceptions propagate naturally - they should not be converted to HTTP errors + // The runtime will handle them appropriately, no logging needed as this is a control-flow exception + throw; + } catch (UnprocessableEntityException ex) { - this.logger.LogError($"{LoggingConstants.HskUiLogPrefix} GetCaseInfo function encountered an unprocessable entity error: {ex.Message}"); + this.logger.LogError(ex, "{Prefix} GetCaseInfo function encountered an unprocessable entity error: {Message}", LoggingConstants.HskUiLogPrefix, ex.Message); return new ObjectResult(ex.Message) { StatusCode = StatusCodes.Status422UnprocessableEntity, @@ -93,12 +94,12 @@ public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, } catch (InvalidOperationException ex) { - this.logger.LogError($"{LoggingConstants.HskUiLogPrefix} {ex.Message}"); + this.logger.LogError(ex, "{Prefix} {Message}", LoggingConstants.HskUiLogPrefix, ex.Message); return new UnprocessableEntityObjectResult($"{ex.Message}"); } catch (Exception ex) { - this.logger.LogError($"{LoggingConstants.HskUiLogPrefix} GetCaseInfo function encountered an error: {ex.Message}"); + this.logger.LogError(ex, "{Prefix} GetCaseInfo function encountered an error: {Message}", LoggingConstants.HskUiLogPrefix, ex.Message); return new StatusCodeResult(StatusCodes.Status500InternalServerError); } } diff --git a/polaris-gateway/Functions/HouseKeeping/GetCaseLockInfo.cs b/polaris-gateway/Functions/HouseKeeping/GetCaseLockInfo.cs index ff0160774..278d58524 100644 --- a/polaris-gateway/Functions/HouseKeeping/GetCaseLockInfo.cs +++ b/polaris-gateway/Functions/HouseKeeping/GetCaseLockInfo.cs @@ -8,6 +8,7 @@ namespace PolarisGateway.Functions.HouseKeeping; using Microsoft.AspNetCore.Mvc; using Microsoft.Azure.Functions.Worker; using Microsoft.Extensions.Logging; +using System.Threading; using System.Threading.Tasks; using Cps.Fct.Hk.Ui.Interfaces; using System.Diagnostics; @@ -50,7 +51,7 @@ public class GetCaseLockInfo(ILogger logger, ICaseLockService c [OpenApiRequestBody("application/json", typeof(CaseLockedStatusResult), Description = "Return case lock response.")] [OpenApiResponseWithoutBody(statusCode: HttpStatusCode.OK)] [Function(nameof(GetCaseLockInfo))] - public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = RestApi.CaseLockInfo)] HttpRequest req, int caseId) + public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = RestApi.CaseLockInfo)] HttpRequest req, int caseId, CancellationToken cancellationToken = default) { try { @@ -68,7 +69,7 @@ public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, CaseLockedStatusResult caseLockSummary; try { - caseLockSummary = await this.caseLockService.CheckCaseLockAsync(caseId, cmsAuthValues).ConfigureAwait(true); + caseLockSummary = await this.caseLockService.CheckCaseLockAsync(caseId, cmsAuthValues, cancellationToken).ConfigureAwait(true); } catch (Exception ex) { diff --git a/polaris-gateway/Functions/HouseKeeping/GetCaseMaterials.cs b/polaris-gateway/Functions/HouseKeeping/GetCaseMaterials.cs index 8e6695e3d..e07968c8c 100644 --- a/polaris-gateway/Functions/HouseKeeping/GetCaseMaterials.cs +++ b/polaris-gateway/Functions/HouseKeeping/GetCaseMaterials.cs @@ -8,6 +8,7 @@ namespace PolarisGateway.Functions.HouseKeeping; using Microsoft.AspNetCore.Mvc; using Microsoft.Azure.Functions.Worker; using Microsoft.Extensions.Logging; +using System.Threading; using System.Threading.Tasks; using Cps.Fct.Hk.Ui.Interfaces; using System.Diagnostics; @@ -29,6 +30,25 @@ namespace PolarisGateway.Functions.HouseKeeping; using Common.Enums; using Cps.Fct.Hk.Ui.Services.Constants; +/// +/// Container for retrieved case materials data. +/// +/// The communications collection. +/// The unused materials. +/// The used statements. +/// The used exhibits. +/// The used MG forms. +/// The used other materials. +/// The exhibit producers. +internal record RetrievedCaseMaterials( + IReadOnlyCollection Communications, + UnusedMaterialsResponse UnusedMaterials, + UsedStatementsResponse UsedStatements, + UsedExhibitsResponse UsedExhibits, + UsedMgFormsResponse UsedMgForms, + UsedOtherMaterialsResponse UsedOtherMaterials, + ExhibitProducersResponse ExhibitProducers); + /// /// Represents a function that retrieves the case materials for a case, /// intended to be accessed via the Housekeeping UI front-end. @@ -54,6 +74,7 @@ public class GetCaseMaterials( /// /// The HTTP request. /// The case Id. + /// Cancellation token. /// An representing the response of the function. [OpenApiOperation(operationId: nameof(GetCaseMaterials), tags: ["Material"], Description = "Represents a function that retrieves the case materials for a case.")] [OpenApiSecurity("function_key", SecuritySchemeType.ApiKey, Name = "x-functions-key", In = OpenApiSecurityLocationType.Header, Description = "The Azure Function API Key.")] @@ -63,113 +84,38 @@ public class GetCaseMaterials( [OpenApiResponseWithoutBody(statusCode: HttpStatusCode.BadRequest)] [OpenApiResponseWithoutBody(statusCode: HttpStatusCode.UnprocessableEntity)] [Function("GetCaseMaterials")] - public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = RestApi.CaseMaterials)] HttpRequest req, int caseId) + public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = RestApi.CaseMaterials)] HttpRequest req, int caseId, CancellationToken cancellationToken = default) { try { var stopwatch = Stopwatch.StartNew(); this.logger.LogInformation($"{LoggingConstants.HskUiLogPrefix} GetCaseMaterials function processed a request."); - // Build CMS auth values from cookie extracted from the request var cmsAuthValues = this.BuildCmsAuthValues(req); - - // Retrieve case materials var (communications, unusedMaterials, usedStatements, usedExhibits, usedMgForms, usedOtherMaterials, exhibitProducers) = - await this.caseMaterialService.RetrieveCaseMaterialsAsync(caseId, cmsAuthValues).ConfigureAwait(false); + await this.caseMaterialService.RetrieveCaseMaterialsAsync(caseId, cmsAuthValues, cancellationToken).ConfigureAwait(false); - // Ensure all required data is retrieved before proceeding - if (communications == null || unusedMaterials == null || usedStatements == null || usedExhibits == null || usedMgForms == null || usedOtherMaterials == null) - { - this.logger.LogError($"{LoggingConstants.HskUiLogPrefix} Failed to retrieve case materials for caseId [{caseId}]"); - throw new UnprocessableEntityException($"Failed to retrieve case materials for caseId [{caseId}]"); - } + var retrievedMaterials = new RetrievedCaseMaterials( + communications, + unusedMaterials, + usedStatements, + usedExhibits, + usedMgForms, + usedOtherMaterials, + exhibitProducers); - this.logger?.LogInformation( - $"{LoggingConstants.HskUiLogPrefix} caseId [{caseId}] material count: " + - $"communications [{communications.Count}], " + - $"unusedMaterials (exhibits) [{unusedMaterials.Exhibits?.Count ?? 0}], " + - $"unusedMaterials (mgForms) [{unusedMaterials.MgForms?.Count ?? 0}], " + - $"unusedMaterials (otherMaterials) [{unusedMaterials.OtherMaterials?.Count ?? 0}], " + - $"unusedMaterials (statements) [{unusedMaterials.Statements?.Count ?? 0}], " + - $"usedStatements [{usedStatements.Statements?.Count ?? 0}], " + - $"usedExhibits [{usedExhibits.Exhibits?.Count ?? 0}], " + - $"usedMgForms [{usedMgForms.MgForms?.Count ?? 0}], " + - $"usedOtherMaterials [{usedOtherMaterials.MgForms?.Count ?? 0}] " + - $"exhibitProducers [{exhibitProducers.ExhibitProducers?.Count ?? 0}]"); - - // Map and combine communications with attachments - List combinedCommunications = - await this.GetMappedCommunicationsWithAttachmentsAsync(caseId, communications, cmsAuthValues).ConfigureAwait(false); - - // Map communications to CaseMaterials - List allCaseMaterials = this.caseMaterialService.MapCommunicationsToCaseMaterials(combinedCommunications) ?? new List(); - - // Add Used exhibits - this.caseMaterialService.AddCaseMaterials(allCaseMaterials!, usedExhibits.Exhibits ?? Enumerable.Empty(), "Exhibit", "Other Exhibit", "Used"); - if (usedExhibits.Exhibits != null && usedExhibits.Exhibits.Count != 0) - { - allCaseMaterials?.AddRange(this.caseMaterialService.MapUsedExhibitsToCaseMaterials(usedExhibits, exhibitProducers, communications, caseId)); - } - - // Add Used statements - this.caseMaterialService.AddCaseMaterials(allCaseMaterials!, usedStatements.Statements ?? Enumerable.Empty(), "Statement", "Other Statement", "Used"); - if (usedStatements.Statements != null && usedStatements.Statements.Count != 0) - { - allCaseMaterials?.AddRange(this.caseMaterialService.MapUsedStatementsToCaseMaterials(usedStatements, communications)); - } + this.ValidateRetrievedMaterials(caseId, retrievedMaterials); + this.LogMaterialCounts(caseId, retrievedMaterials); - // Add Used MG forms - // Exclude MG forms with material types that are in the ExcludedFromUsedMgForms list as they are already included in communications and will be mapped to CaseMaterials from communications - if (usedMgForms.MgForms != null) - { - usedMgForms.MgForms.RemoveAll(mgForm => - CommsDocumentTypeIds.ExcludedFromUsedMgForms.Contains(mgForm.MaterialType)); - } + var combinedCommunications = await this.GetMappedCommunicationsWithAttachmentsAsync(caseId, communications, cmsAuthValues).ConfigureAwait(false); + var allCaseMaterials = this.caseMaterialService.MapCommunicationsToCaseMaterials(combinedCommunications) ?? new List(); - this.caseMaterialService.AddCaseMaterials(allCaseMaterials!, usedMgForms.MgForms ?? Enumerable.Empty(), "MG Form", "MG Form", "Used"); - if (usedMgForms.MgForms != null && usedMgForms.MgForms.Count != 0) - { - allCaseMaterials?.AddRange(this.caseMaterialService.MapUsedMgFormsToCaseMaterials(usedMgForms)); - } - - // Add Used other materials - this.caseMaterialService.AddCaseMaterials(allCaseMaterials!, usedOtherMaterials.MgForms ?? Enumerable.Empty(), "Other Material", "Other Material", "Used"); - if (usedOtherMaterials.MgForms != null && usedOtherMaterials.MgForms.Count != 0) - { - allCaseMaterials?.AddRange(this.caseMaterialService.MapUsedOtherMaterialsToCaseMaterials(usedOtherMaterials)); - } - - // Add Unused Materials - foreach (var collection in new List<(string Name, IEnumerable UnusedMaterials)> - { - ("Exhibits", unusedMaterials.Exhibits ?? Enumerable.Empty()), - ("MgForms", unusedMaterials.MgForms ?? Enumerable.Empty()), - ("OtherMaterials", unusedMaterials.OtherMaterials ?? Enumerable.Empty()), - ("Statements", unusedMaterials.Statements ?? Enumerable.Empty()), - }) - { - if (collection.UnusedMaterials.Any()) - { - this.caseMaterialService.AddCaseMaterials(allCaseMaterials!, collection.UnusedMaterials, collection.Name, "Unused Material", "Unused"); - } - } - - // Map and add unused materials only if the result is not empty - List mappedUnusedMaterials = this.caseMaterialService.MapUnusedMaterialsToCaseMaterials(unusedMaterials, communications); - if (mappedUnusedMaterials != null && mappedUnusedMaterials.Any()) - { - allCaseMaterials?.AddRange(mappedUnusedMaterials); - } + this.ProcessUsedMaterials(allCaseMaterials, caseId, retrievedMaterials); + this.ProcessUnusedMaterials(allCaseMaterials, communications, unusedMaterials); this.logger!.LogInformation($"{LoggingConstants.HskUiLogPrefix} Milestone: caseId [{caseId}] GetCaseMaterials function completed in [{stopwatch.Elapsed}]"); - if (allCaseMaterials != null) - { - foreach (CaseMaterial allCaseMaterial in allCaseMaterials) - { - allCaseMaterial.ReadStatus = allCaseMaterial.ReadStatus.Equals("Complete", StringComparison.OrdinalIgnoreCase) ? MaterialReadStatusType.Read.ToString() : MaterialReadStatusType.Unread.ToString(); - } - } + NormalizeReadStatus(allCaseMaterials); var response = new OkObjectResult(allCaseMaterials); ConfigureResponseHeaders(req.HttpContext.Response); @@ -190,6 +136,162 @@ public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, } } + /// + /// Validates that all required case materials were retrieved successfully. + /// + private void ValidateRetrievedMaterials(int caseId, RetrievedCaseMaterials materials) + { + if (materials.Communications == null || + materials.UnusedMaterials == null || + materials.UsedStatements == null || + materials.UsedExhibits == null || + materials.UsedMgForms == null || + materials.UsedOtherMaterials == null) + { + this.logger.LogError($"{LoggingConstants.HskUiLogPrefix} Failed to retrieve case materials for caseId [{caseId}]"); + throw new UnprocessableEntityException($"Failed to retrieve case materials for caseId [{caseId}]"); + } + } + + /// + /// Logs the counts of all retrieved materials. + /// + private void LogMaterialCounts(int caseId, RetrievedCaseMaterials materials) + { + this.logger?.LogInformation( + $"{LoggingConstants.HskUiLogPrefix} caseId [{caseId}] material count: " + + $"communications [{materials.Communications.Count}], " + + $"unusedMaterials (exhibits) [{materials.UnusedMaterials.Exhibits?.Count ?? 0}], " + + $"unusedMaterials (mgForms) [{materials.UnusedMaterials.MgForms?.Count ?? 0}], " + + $"unusedMaterials (otherMaterials) [{materials.UnusedMaterials.OtherMaterials?.Count ?? 0}], " + + $"unusedMaterials (statements) [{materials.UnusedMaterials.Statements?.Count ?? 0}], " + + $"usedStatements [{materials.UsedStatements.Statements?.Count ?? 0}], " + + $"usedExhibits [{materials.UsedExhibits.Exhibits?.Count ?? 0}], " + + $"usedMgForms [{materials.UsedMgForms.MgForms?.Count ?? 0}], " + + $"usedOtherMaterials [{materials.UsedOtherMaterials.MgForms?.Count ?? 0}] " + + $"exhibitProducers [{materials.ExhibitProducers.ExhibitProducers?.Count ?? 0}]"); + } + + /// + /// Processes and adds all used materials to the case materials list. + /// + private void ProcessUsedMaterials( + List allCaseMaterials, + int caseId, + RetrievedCaseMaterials materials) + { + this.AddUsedExhibits(allCaseMaterials, caseId, materials.Communications, materials.UsedExhibits, materials.ExhibitProducers); + this.AddUsedStatements(allCaseMaterials, materials.Communications, materials.UsedStatements); + this.AddUsedMgForms(allCaseMaterials, materials.UsedMgForms); + this.AddUsedOtherMaterials(allCaseMaterials, materials.UsedOtherMaterials); + } + + /// + /// Adds used exhibits to the case materials list. + /// + private void AddUsedExhibits( + List allCaseMaterials, + int caseId, + IReadOnlyCollection communications, + UsedExhibitsResponse usedExhibits, + ExhibitProducersResponse exhibitProducers) + { + this.caseMaterialService.AddCaseMaterials(allCaseMaterials, usedExhibits.Exhibits ?? Enumerable.Empty(), "Exhibit", "Other Exhibit", "Used"); + if (usedExhibits.Exhibits != null && usedExhibits.Exhibits.Count != 0) + { + allCaseMaterials.AddRange(this.caseMaterialService.MapUsedExhibitsToCaseMaterials(usedExhibits, exhibitProducers, communications, caseId)); + } + } + + /// + /// Adds used statements to the case materials list. + /// + private void AddUsedStatements( + List allCaseMaterials, + IReadOnlyCollection communications, + UsedStatementsResponse usedStatements) + { + this.caseMaterialService.AddCaseMaterials(allCaseMaterials, usedStatements.Statements ?? Enumerable.Empty(), "Statement", "Other Statement", "Used"); + if (usedStatements.Statements != null && usedStatements.Statements.Count != 0) + { + allCaseMaterials.AddRange(this.caseMaterialService.MapUsedStatementsToCaseMaterials(usedStatements, communications)); + } + } + + /// + /// Adds used MG forms to the case materials list. + /// + private void AddUsedMgForms(List allCaseMaterials, UsedMgFormsResponse usedMgForms) + { + if (usedMgForms.MgForms != null) + { + usedMgForms.MgForms.RemoveAll(mgForm => CommsDocumentTypeIds.ExcludedFromUsedMgForms.Contains(mgForm.MaterialType)); + } + + this.caseMaterialService.AddCaseMaterials(allCaseMaterials, usedMgForms.MgForms ?? Enumerable.Empty(), "MG Form", "MG Form", "Used"); + if (usedMgForms.MgForms != null && usedMgForms.MgForms.Count != 0) + { + allCaseMaterials.AddRange(this.caseMaterialService.MapUsedMgFormsToCaseMaterials(usedMgForms)); + } + } + + /// + /// Adds used other materials to the case materials list. + /// + private void AddUsedOtherMaterials(List allCaseMaterials, UsedOtherMaterialsResponse usedOtherMaterials) + { + this.caseMaterialService.AddCaseMaterials(allCaseMaterials, usedOtherMaterials.MgForms ?? Enumerable.Empty(), "Other Material", "Other Material", "Used"); + if (usedOtherMaterials.MgForms != null && usedOtherMaterials.MgForms.Count != 0) + { + allCaseMaterials.AddRange(this.caseMaterialService.MapUsedOtherMaterialsToCaseMaterials(usedOtherMaterials)); + } + } + + /// + /// Processes and adds all unused materials to the case materials list. + /// + private void ProcessUnusedMaterials( + List allCaseMaterials, + IReadOnlyCollection communications, + UnusedMaterialsResponse unusedMaterials) + { + foreach (var collection in new List<(string Name, IEnumerable UnusedMaterials)> + { + ("Exhibits", unusedMaterials.Exhibits ?? Enumerable.Empty()), + ("MgForms", unusedMaterials.MgForms ?? Enumerable.Empty()), + ("OtherMaterials", unusedMaterials.OtherMaterials ?? Enumerable.Empty()), + ("Statements", unusedMaterials.Statements ?? Enumerable.Empty()), + }) + { + if (collection.UnusedMaterials.Any()) + { + this.caseMaterialService.AddCaseMaterials(allCaseMaterials, collection.UnusedMaterials, collection.Name, "Unused Material", "Unused"); + } + } + + var mappedUnusedMaterials = this.caseMaterialService.MapUnusedMaterialsToCaseMaterials(unusedMaterials, communications); + if (mappedUnusedMaterials != null && mappedUnusedMaterials.Any()) + { + allCaseMaterials.AddRange(mappedUnusedMaterials); + } + } + + /// + /// Normalizes the read status of all case materials. + /// + private static void NormalizeReadStatus(List allCaseMaterials) + { + if (allCaseMaterials != null) + { + foreach (var caseMaterial in allCaseMaterials) + { + caseMaterial.ReadStatus = caseMaterial.ReadStatus.Equals("Complete", StringComparison.OrdinalIgnoreCase) + ? MaterialReadStatusType.Read.ToString() + : MaterialReadStatusType.Unread.ToString(); + } + } + } + /// /// Configures the response headers to enhance security and prevent caching. /// diff --git a/polaris-gateway/Functions/HouseKeeping/GetCaseMaterialsPreview.cs b/polaris-gateway/Functions/HouseKeeping/GetCaseMaterialsPreview.cs index 7c6eed3e1..278e5902e 100644 --- a/polaris-gateway/Functions/HouseKeeping/GetCaseMaterialsPreview.cs +++ b/polaris-gateway/Functions/HouseKeeping/GetCaseMaterialsPreview.cs @@ -8,6 +8,7 @@ namespace PolarisGateway.Functions.HouseKeeping; using Microsoft.AspNetCore.Mvc; using Microsoft.Azure.Functions.Worker; using Microsoft.Extensions.Logging; +using System.Threading; using System.Threading.Tasks; using Cps.Fct.Hk.Ui.Interfaces; using System.Diagnostics; @@ -57,7 +58,7 @@ public class GetCaseMaterialsPreview( [OpenApiRequestBody("application/json", typeof(FileStreamResult), Description = "Return case summary response.")] [OpenApiResponseWithoutBody(statusCode: HttpStatusCode.OK)] [Function("GetCaseMaterialsPreview")] - public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = RestApi.CaseMaterialsPreview)] HttpRequest req, int caseId, int materialId) + public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = RestApi.CaseMaterialsPreview)] HttpRequest req, int caseId, int materialId, CancellationToken cancellationToken = default) { try { @@ -78,7 +79,7 @@ public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, var cmsAuthValues = this.BuildCmsAuthValues(req); // Get the material link - string link = await this.GetLinkForMaterialAsync(caseId, materialId, cmsAuthValues).ConfigureAwait(true); + string link = await this.GetLinkForMaterialAsync(caseId, materialId, cmsAuthValues, cancellationToken).ConfigureAwait(true); if (string.IsNullOrEmpty(link)) { return new NotFoundObjectResult($"{LoggingConstants.HskUiLogPrefix} No valid link found for the case material document with materialId [{materialId}]."); @@ -125,9 +126,9 @@ public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, /// /// A containing the communication link if found; otherwise, returns null. /// - private async Task GetLinkForMaterialAsync(int caseId, int materialId, CmsAuthValues cmsAuthValues) + private async Task GetLinkForMaterialAsync(int caseId, int materialId, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default) { - object linkResult = await this.communicationService.GetCaseMaterialLinkAsync(caseId, materialId, cmsAuthValues).ConfigureAwait(true); + object linkResult = await this.communicationService.GetCaseMaterialLinkAsync(caseId, materialId, cmsAuthValues, cancellationToken).ConfigureAwait(true); return linkResult is IActionResult ? null : linkResult as string; } diff --git a/polaris-gateway/Functions/HouseKeeping/GetCaseWitnessStatements.cs b/polaris-gateway/Functions/HouseKeeping/GetCaseWitnessStatements.cs index d702ee7a3..632be275a 100644 --- a/polaris-gateway/Functions/HouseKeeping/GetCaseWitnessStatements.cs +++ b/polaris-gateway/Functions/HouseKeeping/GetCaseWitnessStatements.cs @@ -7,6 +7,7 @@ namespace PolarisGateway.Functions.HouseKeeping; using System; using System.Diagnostics; using System.Net; +using System.Threading; using System.Threading.Tasks; using Common.Configuration; using Common.Constants; @@ -50,7 +51,7 @@ public class GetCaseWitnessStatements( [OpenApiResponseWithoutBody(statusCode: HttpStatusCode.UnprocessableEntity)] [OpenApiResponseWithoutBody(statusCode: HttpStatusCode.Unauthorized)] [Function(nameof(GetCaseWitnessStatements))] - public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = RestApi.CaseWitnessStatements)] HttpRequest request, int caseId, int witnessId) + public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = RestApi.CaseWitnessStatements)] HttpRequest request, int caseId, int witnessId, CancellationToken cancellationToken = default) { try { @@ -65,7 +66,7 @@ public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, // Build CMS auth values from cookie extracted from the request var cmsAuthValues = this.BuildCmsAuthValues(request); - WitnessStatementsResponse? result = await this.witnessService.GetWitnessStatementsAsync(witnessId, cmsAuthValues).ConfigureAwait(false); + WitnessStatementsResponse? result = await this.witnessService.GetWitnessStatementsAsync(witnessId, cmsAuthValues, cancellationToken).ConfigureAwait(false); this.logger.LogInformation($"{LoggingConstants.HskUiLogPrefix} Milestone: caseId [{caseId}] witnessId [{witnessId}] {nameof(GetCaseWitnessStatements)} function completed in [{stopwatch.Elapsed}]"); diff --git a/polaris-gateway/Functions/HouseKeeping/GetCaseWitnesses.cs b/polaris-gateway/Functions/HouseKeeping/GetCaseWitnesses.cs index 86e0a63ac..adf9cc1c5 100644 --- a/polaris-gateway/Functions/HouseKeeping/GetCaseWitnesses.cs +++ b/polaris-gateway/Functions/HouseKeeping/GetCaseWitnesses.cs @@ -7,6 +7,7 @@ namespace PolarisGateway.Functions.HouseKeeping; using System; using System.Diagnostics; using System.Net; +using System.Threading; using System.Threading.Tasks; using Common.Configuration; using Common.Constants; @@ -48,7 +49,7 @@ public class GetCaseWitnesses(ILogger logger, [OpenApiResponseWithoutBody(statusCode: HttpStatusCode.UnprocessableEntity)] [OpenApiResponseWithoutBody(statusCode: HttpStatusCode.Unauthorized)] [Function(nameof(GetCaseWitnesses))] - public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = RestApi.CaseWitnessesHk)] HttpRequest request, int caseId) + public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = RestApi.CaseWitnessesHk)] HttpRequest request, int caseId, CancellationToken cancellationToken = default) { try { @@ -63,7 +64,7 @@ public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, // Build CMS auth values from cookie extracted from the request var cmsAuthValues = BuildCmsAuthValues(request); - WitnessesResponse result = await witnessService.GetCaseWitnessesAsync(caseId, cmsAuthValues).ConfigureAwait(false); + WitnessesResponse result = await witnessService.GetCaseWitnessesAsync(caseId, cmsAuthValues, cancellationToken).ConfigureAwait(false); logger.LogInformation($"{LoggingConstants.HskUiLogPrefix} Milestone: caseId [{caseId}] {nameof(GetCaseWitnesses)} function completed in [{stopwatch.Elapsed}]"); diff --git a/polaris-gateway/Functions/HouseKeeping/GetInitialReview.cs b/polaris-gateway/Functions/HouseKeeping/GetInitialReview.cs index 77a9ff4ef..5c73ed6fa 100644 --- a/polaris-gateway/Functions/HouseKeeping/GetInitialReview.cs +++ b/polaris-gateway/Functions/HouseKeeping/GetInitialReview.cs @@ -7,6 +7,7 @@ namespace PolarisGateway.Functions.HouseKeeping; using System; using System.Diagnostics; using System.Net; +using System.Threading; using System.Threading.Tasks; using Common.Configuration; using Common.Constants; @@ -53,7 +54,7 @@ public class GetInitialReview( [OpenApiResponseWithoutBody(statusCode: HttpStatusCode.InternalServerError)] [Function(nameof(GetInitialReview))] public async Task Run( - [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = RestApi.InitialReviewByCase)] HttpRequest request, int caseId) + [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = RestApi.InitialReviewByCase)] HttpRequest request, int caseId, CancellationToken cancellationToken = default) { try { @@ -68,7 +69,7 @@ public async Task Run( // Build CMS auth values from cookie extracted from the request var cmsAuthValues = this.BuildCmsAuthValues(request); - var result = await this.caseHistoryEventProvider.FirstInitialReviewGetCaseHistoryAsync(caseId, cmsAuthValues).ConfigureAwait(true); + var result = await this.caseHistoryEventProvider.FirstInitialReviewGetCaseHistoryAsync(caseId, cmsAuthValues, cancellationToken).ConfigureAwait(true); if (result == null) { diff --git a/polaris-gateway/Functions/HouseKeeping/GetMaterialDocuments.cs b/polaris-gateway/Functions/HouseKeeping/GetMaterialDocuments.cs index fb8444d38..7238e0592 100644 --- a/polaris-gateway/Functions/HouseKeeping/GetMaterialDocuments.cs +++ b/polaris-gateway/Functions/HouseKeeping/GetMaterialDocuments.cs @@ -8,6 +8,7 @@ namespace PolarisGateway.Functions.HouseKeeping; using Microsoft.AspNetCore.Mvc; using Microsoft.Azure.Functions.Worker; using Microsoft.Extensions.Logging; +using System.Threading; using System.Threading.Tasks; using Cps.Fct.Hk.Ui.Interfaces; using System.Diagnostics; @@ -56,7 +57,7 @@ public class GetMaterialDocument( [OpenApiRequestBody("application/json", typeof(FileStreamResult), Description = "Return case summary response.")] [OpenApiResponseWithoutBody(statusCode: HttpStatusCode.OK)] [Function("GetMaterialDocument")] - public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = RestApi.MaterialDocument)] HttpRequest req, int caseId, int materialId) + public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = RestApi.MaterialDocument)] HttpRequest req, int caseId, int materialId, CancellationToken cancellationToken = default) { try { @@ -125,9 +126,9 @@ public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, /// /// A containing the communication link if found; otherwise, returns null. /// - private async Task GetLinkForMaterialAsync(int caseId, int materialId, CmsAuthValues cmsAuthValues) + private async Task GetLinkForMaterialAsync(int caseId, int materialId, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default) { - object linkResult = await this.communicationService.GetCaseMaterialLinkAsync(caseId, materialId, cmsAuthValues).ConfigureAwait(true); + object linkResult = await this.communicationService.GetCaseMaterialLinkAsync(caseId, materialId, cmsAuthValues, cancellationToken).ConfigureAwait(true); return linkResult is IActionResult ? null : linkResult as string; } @@ -142,9 +143,9 @@ private async Task GetLinkForMaterialAsync(int caseId, int materialId, C /// /// An that either contains the material document if found, or a file with 'not found' content if the document is missing. /// - private async Task GetMaterialDocumentAsync(string caseId, string link, CmsAuthValues cmsAuthValues, Stopwatch stopwatch) + private async Task GetMaterialDocumentAsync(string caseId, string link, CmsAuthValues cmsAuthValues, Stopwatch stopwatch, CancellationToken cancellationToken = default) { - FileStreamResult downloadedDocument = await this.documentService.GetMaterialDocumentAsync(caseId, link, cmsAuthValues, firstPageOnly: false).ConfigureAwait(true); + FileStreamResult downloadedDocument = await this.documentService.GetMaterialDocumentAsync(caseId, link, cmsAuthValues, firstPageOnly: false, cancellationToken).ConfigureAwait(true); if (downloadedDocument == null) { diff --git a/polaris-gateway/Functions/HouseKeeping/GetOffenceChargeById.cs b/polaris-gateway/Functions/HouseKeeping/GetOffenceChargeById.cs index 82e6c382c..5d1ef8289 100644 --- a/polaris-gateway/Functions/HouseKeeping/GetOffenceChargeById.cs +++ b/polaris-gateway/Functions/HouseKeeping/GetOffenceChargeById.cs @@ -1,71 +1,73 @@ -// -// Copyright (c) The Crown Prosecution Service. All rights reserved. -// - -namespace PolarisGateway.Functions.HouseKeeping; - -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Mvc; -using Microsoft.Azure.Functions.Worker; -using Microsoft.Extensions.Logging; -using System.Threading.Tasks; -using Cps.Fct.Hk.Ui.Interfaces; -using System.Diagnostics; -using Microsoft.OpenApi.Models; -using System.Net; -using System; -using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Attributes; -using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Enums; +// +// Copyright (c) The Crown Prosecution Service. All rights reserved. +// + +namespace PolarisGateway.Functions.HouseKeeping; + +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Azure.Functions.Worker; +using Microsoft.Extensions.Logging; +using System.Threading; +using System.Threading.Tasks; +using Cps.Fct.Hk.Ui.Interfaces; +using System.Diagnostics; +using Microsoft.OpenApi.Models; +using System.Net; +using System; +using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Attributes; +using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Enums; using Common.Configuration; using Common.Constants; using Common.Exceptions; -/// -/// Represents a function that return case offence charge by case id, -/// intended to be accessed via the Housekeeping UI front-end. -/// -/// -/// Initializes a new instance of the class. -/// -/// The logger instance used to log information and errors. -/// The service used to get call case history service. -/// The service used to handle cookie-related operations. -public class GetOffenceChargeById( - ILogger logger, - ICommunicationService communicationService) : BaseFunction(logger) -{ - private readonly ILogger logger = logger; - private readonly ICommunicationService communicationService = communicationService; - - /// - /// The Azure Function that processes an HTTP request for the 'case/{caseId}/pcd-review' route. - /// - /// The HTTP request. - /// The case id. - /// The history Id of the case to get offence charge. - /// An representing the response of the function. - [OpenApiOperation(operationId: nameof(GetOffenceChargeById), tags: ["CaseHistory"], Description = "Returns Offence charge with Case Id.")] - [OpenApiSecurity("function_key", SecuritySchemeType.ApiKey, Name = "x-functions-key", In = OpenApiSecurityLocationType.Header, Description = "The Azure Function API Key.")] - [OpenApiSecurity("Cookie", SecuritySchemeType.ApiKey, Name = "Cookie", In = OpenApiSecurityLocationType.Header, Description = "The CMS Auth Values. This can be retrieved via the DDEI Authenticate API Endpoint and URI encoded along with User session token.")] - [OpenApiParameter("caseId", In = ParameterLocation.Path, Type = typeof(int), Description = "The Id of the case.", Required = true)] - [OpenApiParameter("historyId", In = ParameterLocation.Path, Type = typeof(int), Description = "The history Id of the case to get offence charge.", Required = true)] - [OpenApiResponseWithBody(statusCode: HttpStatusCode.OK, contentType: "application/json", bodyType: typeof(Cps.MasterDataService.Infrastructure.ApiClient.PreChargeDecisionOutcome), Description = "Return PCD review.")] - [OpenApiResponseWithoutBody(statusCode: HttpStatusCode.BadRequest)] - [OpenApiResponseWithoutBody(statusCode: HttpStatusCode.UnprocessableEntity)] - [OpenApiResponseWithoutBody(statusCode: HttpStatusCode.Unauthorized)] - [OpenApiResponseWithoutBody(statusCode: HttpStatusCode.InternalServerError)] - [Function(nameof(GetOffenceChargeById))] - public async Task Run( - [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = RestApi.OffenseCharge)] - HttpRequest request, - int caseId, - int historyId) - { - try - { - var stopwatch = Stopwatch.StartNew(); - this.logger.LogInformation($"{LoggingConstants.HskUiLogPrefix} GetOffenceChargeById function processed a request."); - +/// +/// Represents a function that return case offence charge by case id, +/// intended to be accessed via the Housekeeping UI front-end. +/// +/// +/// Initializes a new instance of the class. +/// +/// The logger instance used to log information and errors. +/// The service used to get call case history service. +/// The service used to handle cookie-related operations. +public class GetOffenceChargeById( + ILogger logger, + ICommunicationService communicationService) : BaseFunction(logger) +{ + private readonly ILogger logger = logger; + private readonly ICommunicationService communicationService = communicationService; + + /// + /// The Azure Function that processes an HTTP request for the 'case/{caseId}/pcd-review' route. + /// + /// The HTTP request. + /// The case id. + /// The history Id of the case to get offence charge. + /// An representing the response of the function. + [OpenApiOperation(operationId: nameof(GetOffenceChargeById), tags: ["CaseHistory"], Description = "Returns Offence charge with Case Id.")] + [OpenApiSecurity("function_key", SecuritySchemeType.ApiKey, Name = "x-functions-key", In = OpenApiSecurityLocationType.Header, Description = "The Azure Function API Key.")] + [OpenApiSecurity("Cookie", SecuritySchemeType.ApiKey, Name = "Cookie", In = OpenApiSecurityLocationType.Header, Description = "The CMS Auth Values. This can be retrieved via the DDEI Authenticate API Endpoint and URI encoded along with User session token.")] + [OpenApiParameter("caseId", In = ParameterLocation.Path, Type = typeof(int), Description = "The Id of the case.", Required = true)] + [OpenApiParameter("historyId", In = ParameterLocation.Path, Type = typeof(int), Description = "The history Id of the case to get offence charge.", Required = true)] + [OpenApiResponseWithBody(statusCode: HttpStatusCode.OK, contentType: "application/json", bodyType: typeof(Cps.MasterDataService.Infrastructure.ApiClient.PreChargeDecisionOutcome), Description = "Return PCD review.")] + [OpenApiResponseWithoutBody(statusCode: HttpStatusCode.BadRequest)] + [OpenApiResponseWithoutBody(statusCode: HttpStatusCode.UnprocessableEntity)] + [OpenApiResponseWithoutBody(statusCode: HttpStatusCode.Unauthorized)] + [OpenApiResponseWithoutBody(statusCode: HttpStatusCode.InternalServerError)] + [Function(nameof(GetOffenceChargeById))] + public async Task Run( + [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = RestApi.OffenseCharge)] + HttpRequest request, + int caseId, + int historyId, + CancellationToken cancellationToken = default) + { + try + { + var stopwatch = Stopwatch.StartNew(); + this.logger.LogInformation($"{LoggingConstants.HskUiLogPrefix} GetOffenceChargeById function processed a request."); + if (caseId < 1) { return new BadRequestObjectResult($"{LoggingConstants.HskUiLogPrefix} Invalid case Id. It should be an integer."); @@ -77,41 +79,41 @@ public async Task Run( } // Build CMS auth values from cookie extracted from the request - var cmsAuthValues = this.BuildCmsAuthValues(request); - - var result = await this.communicationService.GetOffenceChargeByHistoryIdAsync(caseId, historyId, cmsAuthValues).ConfigureAwait(true); - - if (result == null) - { - this.logger.LogError($"{LoggingConstants.HskUiLogPrefix} caseId [{caseId}] GetOffenceChargeById function failed in [{stopwatch.Elapsed}]"); - return new UnprocessableEntityObjectResult(result); - } - - this.logger.LogInformation($"{LoggingConstants.HskUiLogPrefix} Milestone: caseId [{caseId}] GetOffenceChargeById function completed in [{stopwatch.Elapsed}]"); - - var response = new OkObjectResult(result); - - return response; - } - catch (InvalidOperationException ex) - { - this.logger.LogError($"{ex.Message}"); - return new UnprocessableEntityObjectResult($"{ex.Message}"); - } - catch (NotSupportedException ex) - { - this.logger.LogError(ex, $"{LoggingConstants.HskUiLogPrefix} GetOffenceChargeById function encountered unsupported content type."); - return new UnprocessableEntityObjectResult($"GetOffenceChargeById error: {ex.Message}"); - } - catch (UnauthorizedAccessException ex) - { - this.logger.LogError(ex, $"{LoggingConstants.HskUiLogPrefix} GetOffenceChargeById function encountered UnauthorizedAccess Exception."); - return new UnauthorizedObjectResult($"GetOffenceChargeById error: {ex.Message}"); - } - catch (Exception ex) - { - this.logger.LogError($"{LoggingConstants.HskUiLogPrefix} GetOffenceChargeById function encountered an error: {ex.Message}"); - return new StatusCodeResult(StatusCodes.Status500InternalServerError); - } - } -} + var cmsAuthValues = this.BuildCmsAuthValues(request); + + var result = await this.communicationService.GetOffenceChargeByHistoryIdAsync(caseId, historyId, cmsAuthValues, cancellationToken).ConfigureAwait(true); + + if (result == null) + { + this.logger.LogError($"{LoggingConstants.HskUiLogPrefix} caseId [{caseId}] GetOffenceChargeById function failed in [{stopwatch.Elapsed}]"); + return new UnprocessableEntityObjectResult(result); + } + + this.logger.LogInformation($"{LoggingConstants.HskUiLogPrefix} Milestone: caseId [{caseId}] GetOffenceChargeById function completed in [{stopwatch.Elapsed}]"); + + var response = new OkObjectResult(result); + + return response; + } + catch (InvalidOperationException ex) + { + this.logger.LogError($"{ex.Message}"); + return new UnprocessableEntityObjectResult($"{ex.Message}"); + } + catch (NotSupportedException ex) + { + this.logger.LogError(ex, $"{LoggingConstants.HskUiLogPrefix} GetOffenceChargeById function encountered unsupported content type."); + return new UnprocessableEntityObjectResult($"GetOffenceChargeById error: {ex.Message}"); + } + catch (UnauthorizedAccessException ex) + { + this.logger.LogError(ex, $"{LoggingConstants.HskUiLogPrefix} GetOffenceChargeById function encountered UnauthorizedAccess Exception."); + return new UnauthorizedObjectResult($"GetOffenceChargeById error: {ex.Message}"); + } + catch (Exception ex) + { + this.logger.LogError($"{LoggingConstants.HskUiLogPrefix} GetOffenceChargeById function encountered an error: {ex.Message}"); + return new StatusCodeResult(StatusCodes.Status500InternalServerError); + } + } +} diff --git a/polaris-gateway/Functions/HouseKeeping/GetPCDRequestByPcdId.cs b/polaris-gateway/Functions/HouseKeeping/GetPCDRequestByPcdId.cs index 371f79ab0..c04a94c3a 100644 --- a/polaris-gateway/Functions/HouseKeeping/GetPCDRequestByPcdId.cs +++ b/polaris-gateway/Functions/HouseKeeping/GetPCDRequestByPcdId.cs @@ -8,6 +8,7 @@ namespace PolarisGateway.Functions.HouseKeeping; using Microsoft.AspNetCore.Mvc; using Microsoft.Azure.Functions.Worker; using Microsoft.Extensions.Logging; +using System.Threading; using System.Threading.Tasks; using Cps.Fct.Hk.Ui.Interfaces; using System.Diagnostics; @@ -58,7 +59,7 @@ public class GetPcdRequestByPcdId( [OpenApiResponseWithoutBody(statusCode: HttpStatusCode.InternalServerError)] [Function(nameof(GetPcdRequestByPcdId))] public async Task Run( - [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = RestApi.PcdRequest)] HttpRequest request, int caseId, int pcdId) + [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = RestApi.PcdRequest)] HttpRequest request, int caseId, int pcdId, CancellationToken cancellationToken = default) { try { @@ -70,7 +71,7 @@ public async Task Run( string requestBody = await new StreamReader(request.Body).ReadToEndAsync().ConfigureAwait(false); - PcdRequestDto? result = await this.communicationService.GetPcdRequestByPcdIdAsync(caseId, pcdId, cmsAuthValues).ConfigureAwait(true); + PcdRequestDto? result = await this.communicationService.GetPcdRequestByPcdIdAsync(caseId, pcdId, cmsAuthValues, cancellationToken).ConfigureAwait(true); if (result == null) { diff --git a/polaris-gateway/Functions/HouseKeeping/GetPCDRequestCore.cs b/polaris-gateway/Functions/HouseKeeping/GetPCDRequestCore.cs index 8f3950b7a..48d0ebc72 100644 --- a/polaris-gateway/Functions/HouseKeeping/GetPCDRequestCore.cs +++ b/polaris-gateway/Functions/HouseKeeping/GetPCDRequestCore.cs @@ -8,6 +8,7 @@ namespace PolarisGateway.Functions.HouseKeeping; using Microsoft.AspNetCore.Mvc; using Microsoft.Azure.Functions.Worker; using Microsoft.Extensions.Logging; +using System.Threading; using System.Threading.Tasks; using Cps.Fct.Hk.Ui.Interfaces; using System.Diagnostics; @@ -57,7 +58,7 @@ public class GetPcdRequestCore( [OpenApiResponseWithoutBody(statusCode: HttpStatusCode.InternalServerError)] [Function(nameof(GetPcdRequestCore))] public async Task Run( - [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = RestApi.PcdRequestCore)] HttpRequest request, int caseId) + [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = RestApi.PcdRequestCore)] HttpRequest request, int caseId, CancellationToken cancellationToken = default) { try { @@ -69,7 +70,7 @@ public async Task Run( string requestBody = await new StreamReader(request.Body).ReadToEndAsync().ConfigureAwait(false); - IReadOnlyCollection result = await this.communicationService.GetPcdRequestCore(caseId, cmsAuthValues).ConfigureAwait(true); + IReadOnlyCollection result = await this.communicationService.GetPcdRequestCore(caseId, cmsAuthValues, cancellationToken).ConfigureAwait(true); if (result == null) { diff --git a/polaris-gateway/Functions/HouseKeeping/GetPcdReview.cs b/polaris-gateway/Functions/HouseKeeping/GetPcdReview.cs index 245f0f244..44d3d83bd 100644 --- a/polaris-gateway/Functions/HouseKeeping/GetPcdReview.cs +++ b/polaris-gateway/Functions/HouseKeeping/GetPcdReview.cs @@ -7,6 +7,7 @@ namespace PolarisGateway.Functions.HouseKeeping; using System; using System.Diagnostics; using System.Net; +using System.Threading; using System.Threading.Tasks; using Common.Configuration; using Common.Constants; @@ -53,7 +54,7 @@ public class GetPcdReview( [OpenApiResponseWithoutBody(statusCode: HttpStatusCode.InternalServerError)] [Function(nameof(GetPcdReview))] public async Task Run( - [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = RestApi.PcdReview)] HttpRequest request, int caseId) + [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = RestApi.PcdReview)] HttpRequest request, int caseId, CancellationToken cancellationToken = default) { try { @@ -68,7 +69,7 @@ public async Task Run( // Build CMS auth values from cookie extracted from the request var cmsAuthValues = this.BuildCmsAuthValues(request); - var result = await this.communicationService.GetPcdReview(caseId, cmsAuthValues); + var result = await this.communicationService.GetPcdReview(caseId, cmsAuthValues, cancellationToken); if (result == null) { diff --git a/polaris-gateway/Functions/HouseKeeping/GetPreChargeDecision.cs b/polaris-gateway/Functions/HouseKeeping/GetPreChargeDecision.cs index a4e1783ae..ebde2b6a8 100644 --- a/polaris-gateway/Functions/HouseKeeping/GetPreChargeDecision.cs +++ b/polaris-gateway/Functions/HouseKeeping/GetPreChargeDecision.cs @@ -7,6 +7,7 @@ namespace PolarisGateway.Functions.HouseKeeping; using System; using System.Diagnostics; using System.Net; +using System.Threading; using System.Threading.Tasks; using Common.Configuration; using Common.Constants; @@ -53,7 +54,7 @@ public class GetPreChargeDecision( [OpenApiResponseWithoutBody(statusCode: HttpStatusCode.InternalServerError)] [Function(nameof(GetPreChargeDecision))] public async Task Run( - [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = RestApi.PreChargeDecision)] HttpRequest request, int caseId) + [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = RestApi.PreChargeDecision)] HttpRequest request, int caseId, CancellationToken cancellationToken = default) { try { @@ -68,7 +69,7 @@ public async Task Run( // Build CMS auth values from cookie extracted from the request var cmsAuthValues = this.BuildCmsAuthValues(request); - var result = await this.communicationService.GetPreChargeDecisionCaseHistoryEventDetailsAsync(caseId, cmsAuthValues); + var result = await this.communicationService.GetPreChargeDecisionCaseHistoryEventDetailsAsync(caseId, cmsAuthValues, cancellationToken); if (result == null) { diff --git a/polaris-gateway/Functions/HouseKeeping/GetPreChargeDecisionByHistoryId.cs b/polaris-gateway/Functions/HouseKeeping/GetPreChargeDecisionByHistoryId.cs index 0e221ae7d..8017576b6 100644 --- a/polaris-gateway/Functions/HouseKeeping/GetPreChargeDecisionByHistoryId.cs +++ b/polaris-gateway/Functions/HouseKeeping/GetPreChargeDecisionByHistoryId.cs @@ -7,6 +7,7 @@ namespace PolarisGateway.Functions.HouseKeeping; using System; using System.Diagnostics; using System.Net; +using System.Threading; using System.Threading.Tasks; using Common.Configuration; using Common.Constants; @@ -55,7 +56,7 @@ public class GetPreChargeDecisionByHistoryId( [OpenApiResponseWithoutBody(statusCode: HttpStatusCode.InternalServerError)] [Function(nameof(GetPreChargeDecisionByHistoryId))] public async Task Run( - [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = RestApi.PreChargeDecisionByHistoryId)] HttpRequest request, int caseId, int historyId) + [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = RestApi.PreChargeDecisionByHistoryId)] HttpRequest request, int caseId, int historyId, CancellationToken cancellationToken = default) { try { @@ -75,7 +76,7 @@ public async Task Run( // Build CMS auth values from cookie extracted from the request var cmsAuthValues = this.BuildCmsAuthValues(request); - var result = await this.communicationService.GetPreChargeDecisionByHistoryId(caseId,historyId, cmsAuthValues).ConfigureAwait(true); + var result = await this.communicationService.GetPreChargeDecisionByHistoryId(caseId,historyId, cmsAuthValues, cancellationToken).ConfigureAwait(true); if (result == null) { diff --git a/polaris-gateway/Functions/HouseKeeping/RenameMaterial.cs b/polaris-gateway/Functions/HouseKeeping/RenameMaterial.cs index fe9a987a5..69fa4ca58 100644 --- a/polaris-gateway/Functions/HouseKeeping/RenameMaterial.cs +++ b/polaris-gateway/Functions/HouseKeeping/RenameMaterial.cs @@ -8,6 +8,7 @@ namespace PolarisGateway.Functions.HouseKeeping; using Microsoft.AspNetCore.Mvc; using Microsoft.Azure.Functions.Worker; using Microsoft.Extensions.Logging; +using System.Threading; using System.Threading.Tasks; using Cps.Fct.Hk.Ui.Interfaces; using System.Diagnostics; @@ -59,7 +60,7 @@ public class RenameMaterial( [OpenApiResponseWithoutBody(statusCode: HttpStatusCode.UnprocessableEntity)] [OpenApiResponseWithoutBody(statusCode: HttpStatusCode.Unauthorized)] [Function("RenameMaterial")] - public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, "patch", Route = RestApi.RenameMaterial)] HttpRequest request, int caseId, int materialId) + public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, "patch", Route = RestApi.RenameMaterial)] HttpRequest request, int caseId, int materialId, CancellationToken cancellationToken = default) { try { diff --git a/polaris-gateway/Functions/HouseKeeping/SetMaterialReadStatus.cs b/polaris-gateway/Functions/HouseKeeping/SetMaterialReadStatus.cs index 922a76981..1837ab9c6 100644 --- a/polaris-gateway/Functions/HouseKeeping/SetMaterialReadStatus.cs +++ b/polaris-gateway/Functions/HouseKeeping/SetMaterialReadStatus.cs @@ -8,6 +8,7 @@ namespace PolarisGateway.Functions.HouseKeeping; using Microsoft.AspNetCore.Mvc; using Microsoft.Azure.Functions.Worker; using Microsoft.Extensions.Logging; +using System.Threading; using System.Threading.Tasks; using Cps.Fct.Hk.Ui.Interfaces; using System.Diagnostics; @@ -56,7 +57,7 @@ public class SetMaterialReadStatus( [OpenApiResponseWithoutBody(statusCode: HttpStatusCode.InternalServerError, Description = $"{LoggingConstants.HskUiLogPrefix} SetMaterialReadStatus function encountered an error")] [Function("SetMaterialReadStatus")] public async Task Run( - [HttpTrigger(AuthorizationLevel.Anonymous, "patch", Route = RestApi.ReadStatus)] HttpRequest request, int caseId, int materialId) + [HttpTrigger(AuthorizationLevel.Anonymous, "patch", Route = RestApi.ReadStatus)] HttpRequest request, int caseId, int materialId, CancellationToken cancellationToken = default) { try { @@ -90,7 +91,7 @@ public async Task Run( return new BadRequestObjectResult(nameof(SetMaterialReadStatusRequest.state)); } - SetMaterialReadStatusResponse? result = await this.communicationService.SetMaterialReadStatusAsync(materialId, setMaterialReadStatusRequest.state, cmsAuthValues).ConfigureAwait(true); + SetMaterialReadStatusResponse? result = await this.communicationService.SetMaterialReadStatusAsync(materialId, setMaterialReadStatusRequest.state, cmsAuthValues, cancellationToken:cancellationToken).ConfigureAwait(true); if (result?.CompleteCommunicationData?.Id == null) { diff --git a/polaris-gateway/Functions/HouseKeeping/UmaReclassify.cs b/polaris-gateway/Functions/HouseKeeping/UmaReclassify.cs index e1c8dc52d..fa9257bb0 100644 --- a/polaris-gateway/Functions/HouseKeeping/UmaReclassify.cs +++ b/polaris-gateway/Functions/HouseKeeping/UmaReclassify.cs @@ -9,6 +9,7 @@ namespace PolarisGateway.Functions.HouseKeeping; using System.Diagnostics; using System.Linq; using System.Net; +using System.Threading; using System.Threading.Tasks; using Common.Configuration; using Common.Constants; @@ -60,7 +61,7 @@ public class UmaReclassify( [OpenApiRequestBody("application/json", typeof(IReadOnlyCollection), Description = "Body containing the Request info.")] [OpenApiResponseWithoutBody(statusCode: HttpStatusCode.OK)] [Function("UmaReclassify")] - public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = RestApi.UmaReclassify)] HttpRequest req, int caseId) + public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = RestApi.UmaReclassify)] HttpRequest req, int caseId, CancellationToken cancellationToken = default) { try { @@ -146,10 +147,11 @@ public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, /// /// The ID of the case. /// The authorization values. + /// The cancellation token. /// A task that represents the asynchronous operation. The task result contains a collection of objects. - private async Task> GetCommunicationsAsync(int caseId, CmsAuthValues cmsAuthValues) + private async Task> GetCommunicationsAsync(int caseId, CmsAuthValues cmsAuthValues, CancellationToken cancellationToken = default) { this.logger.LogInformation($"{LoggingConstants.HskUiLogPrefix} Retrieving communications for caseId [{caseId}]..."); - return await this.communicationService.GetCommunicationsAsync(caseId, cmsAuthValues).ConfigureAwait(false); + return await this.communicationService.GetCommunicationsAsync(caseId, cmsAuthValues, cancellationToken).ConfigureAwait(false); } } diff --git a/polaris-gateway/Functions/HouseKeeping/UpdateExhibit.cs b/polaris-gateway/Functions/HouseKeeping/UpdateExhibit.cs index faf0527bd..24661648a 100644 --- a/polaris-gateway/Functions/HouseKeeping/UpdateExhibit.cs +++ b/polaris-gateway/Functions/HouseKeeping/UpdateExhibit.cs @@ -8,6 +8,7 @@ namespace PolarisGateway.Functions.HouseKeeping; using Microsoft.AspNetCore.Mvc; using Microsoft.Azure.Functions.Worker; using Microsoft.Extensions.Logging; +using System.Threading; using System.Threading.Tasks; using Cps.Fct.Hk.Ui.Interfaces; using System.Diagnostics; @@ -55,7 +56,7 @@ public class UpdateExhibit( [OpenApiResponseWithoutBody(statusCode: HttpStatusCode.UnprocessableEntity)] [OpenApiResponseWithoutBody(statusCode: HttpStatusCode.Unauthorized)] [Function("UpdateExhibit")] - public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, "patch", Route = RestApi.UpdateExhibit)] HttpRequest request, int caseId, int materialId) + public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, "patch", Route = RestApi.UpdateExhibit)] HttpRequest request, int caseId, int materialId, CancellationToken cancellationToken = default) { try { @@ -96,7 +97,8 @@ public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, UpdateExhibitResponse result = await this.communicationService.UpdateExhibitAsync( caseId, updateExhibitRequest, - cmsAuthValues).ConfigureAwait(true); + cmsAuthValues, + cancellationToken:cancellationToken).ConfigureAwait(true); if (result?.UpdateExhibitData?.Id == null) { diff --git a/polaris-gateway/Functions/HouseKeeping/UpdateStatement.cs b/polaris-gateway/Functions/HouseKeeping/UpdateStatement.cs index 67c963d81..5525d7eb0 100644 --- a/polaris-gateway/Functions/HouseKeeping/UpdateStatement.cs +++ b/polaris-gateway/Functions/HouseKeeping/UpdateStatement.cs @@ -8,6 +8,7 @@ namespace PolarisGateway.Functions.HouseKeeping; using Microsoft.AspNetCore.Mvc; using Microsoft.Azure.Functions.Worker; using Microsoft.Extensions.Logging; +using System.Threading; using System.Threading.Tasks; using Cps.Fct.Hk.Ui.Interfaces; using System.Diagnostics; @@ -54,7 +55,7 @@ public class UpdateStatement( [OpenApiResponseWithoutBody(statusCode: HttpStatusCode.UnprocessableEntity)] [OpenApiResponseWithoutBody(statusCode: HttpStatusCode.Unauthorized)] [Function("UpdateStatement")] - public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, "patch", Route = RestApi.UpdateStatement)] HttpRequest request, int caseId, int materialId) + public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, "patch", Route = RestApi.UpdateStatement)] HttpRequest request, int caseId, int materialId, CancellationToken cancellationToken = default) { try { @@ -78,7 +79,7 @@ public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, var updateStatementRequest = JsonConvert.DeserializeObject(requestBody); updateStatementRequest.MaterialId = materialId; - + if (updateStatementRequest is null) { return new BadRequestObjectResult("Statement request is null"); @@ -93,7 +94,8 @@ public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, UpdateStatementResponse result = await this.communicationService.UpdateStatementAsync( caseId, updateStatementRequest, - cmsAuthValues).ConfigureAwait(true); + cmsAuthValues, + cancellationToken: cancellationToken).ConfigureAwait(true); if (result?.UpdateStatementData?.Id == null) { diff --git a/polaris-gateway/Functions/LookupUrn.cs b/polaris-gateway/Functions/LookupUrn.cs index 18e8926ef..eb9cc27f8 100644 --- a/polaris-gateway/Functions/LookupUrn.cs +++ b/polaris-gateway/Functions/LookupUrn.cs @@ -10,6 +10,7 @@ using Microsoft.Extensions.Logging; using Microsoft.OpenApi.Models; using System.Net; +using System.Threading; using System.Threading.Tasks; namespace PolarisGateway.Functions; @@ -40,14 +41,14 @@ public LookupUrn( [OpenApiResponseWithoutBody(statusCode: HttpStatusCode.NoContent, Summary = "Invalid request", Description = "Missing or invalid parameters")] public async Task Run( - [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = RestApi.LookupUrn)] HttpRequest req, int caseId) + [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = RestApi.LookupUrn)] HttpRequest req, int caseId, CancellationToken cancellationToken = default) { var correlationId = EstablishCorrelation(req); var cmsAuthValues = EstablishCmsAuthValues(req); var arg = _mdsArgFactory.CreateCaseIdArg(cmsAuthValues, correlationId, caseId); - var result = await _mdsClient.GetUrnFromCaseIdAsync(arg); + var result = await _mdsClient.GetUrnFromCaseIdAsync(arg, cancellationToken: cancellationToken); return new OkObjectResult(result); } diff --git a/polaris-gateway/Functions/PolarisPipelineCase.cs b/polaris-gateway/Functions/PolarisPipelineCase.cs index c4c89d65a..9dc936d25 100644 --- a/polaris-gateway/Functions/PolarisPipelineCase.cs +++ b/polaris-gateway/Functions/PolarisPipelineCase.cs @@ -11,6 +11,7 @@ using PolarisGateway.Extensions; using System.Net; using System.Net.Http; +using System.Threading; using System.Threading.Tasks; namespace PolarisGateway.Functions; @@ -43,7 +44,7 @@ public PolarisPipelineCase( [OpenApiResponseWithBody(statusCode: HttpStatusCode.OK, contentType: "application/json", bodyType: typeof(object), Summary = "Case found", Description = "Returns case details")] [OpenApiResponseWithoutBody(statusCode: HttpStatusCode.NoContent, Summary = "Invalid request", Description = "Missing or invalid parameters")] - public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = RestApi.Case)] HttpRequest req, string caseUrn, int caseId) + public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = RestApi.Case)] HttpRequest req, string caseUrn, int caseId, CancellationToken cancellationToken = default) { var correlationId = EstablishCorrelation(req); var cmsAuthValues = EstablishCmsAuthValues(req); diff --git a/polaris-gateway/Functions/PolarisPipelineCaseDelete.cs b/polaris-gateway/Functions/PolarisPipelineCaseDelete.cs index 5ff003b4b..7208ca1d9 100644 --- a/polaris-gateway/Functions/PolarisPipelineCaseDelete.cs +++ b/polaris-gateway/Functions/PolarisPipelineCaseDelete.cs @@ -4,6 +4,7 @@ using Common.Configuration; using PolarisGateway.Clients.Coordinator; using Microsoft.Azure.Functions.Worker; +using System.Threading; using System.Threading.Tasks; using PolarisGateway.Extensions; using Common.Telemetry; @@ -43,11 +44,12 @@ public PolarisPipelineCaseDelete( [OpenApiResponseWithoutBody(statusCode: HttpStatusCode.NoContent, Summary = "Invalid request", Description = "Missing or invalid parameters")] - public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, "delete", Route = RestApi.Case)] HttpRequest req, string caseUrn, int caseId) + public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, "delete", Route = RestApi.Case)] HttpRequest req, string caseUrn, int caseId, CancellationToken cancellationToken = default) { var correlationId = EstablishCorrelation(req); var cmsAuthValues = EstablishCmsAuthValues(req); + cancellationToken.ThrowIfCancellationRequested(); return await (await _coordinatorClient.DeleteCaseAsync( caseUrn, diff --git a/polaris-gateway/Functions/PolarisPipelineCaseSearch.cs b/polaris-gateway/Functions/PolarisPipelineCaseSearch.cs index 131ee16b4..5be7ce27f 100644 --- a/polaris-gateway/Functions/PolarisPipelineCaseSearch.cs +++ b/polaris-gateway/Functions/PolarisPipelineCaseSearch.cs @@ -11,6 +11,7 @@ using PolarisGateway.Extensions; using System.Net; using System.Net.Http; +using System.Threading; using System.Threading.Tasks; namespace PolarisGateway.Functions; @@ -45,8 +46,10 @@ public PolarisPipelineCaseSearch( [OpenApiResponseWithoutBody(statusCode: HttpStatusCode.NoContent, Summary = "Invalid request", Description = "Missing or invalid parameters")] - public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = RestApi.CaseSearch)] HttpRequest req, string caseUrn, int caseId) + public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = RestApi.CaseSearch)] HttpRequest req, string caseUrn, int caseId, CancellationToken cancellationToken = default) { + cancellationToken.ThrowIfCancellationRequested(); + var correlationId = EstablishCorrelation(req); return await (await _coordinatorClient.SearchCase( diff --git a/polaris-gateway/Functions/PolarisPipelineCaseSearchIndexCount.cs b/polaris-gateway/Functions/PolarisPipelineCaseSearchIndexCount.cs index d5e50dc88..bf125db19 100644 --- a/polaris-gateway/Functions/PolarisPipelineCaseSearchIndexCount.cs +++ b/polaris-gateway/Functions/PolarisPipelineCaseSearchIndexCount.cs @@ -11,6 +11,7 @@ using PolarisGateway.Extensions; using System.Net; using System.Net.Http; +using System.Threading; using System.Threading.Tasks; namespace PolarisGateway.Functions; @@ -43,8 +44,9 @@ public PolarisPipelineCaseSearchIndexCount( [OpenApiResponseWithoutBody(statusCode: HttpStatusCode.NoContent, Summary = "Invalid request", Description = "Missing or invalid parameters")] - public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = RestApi.CaseSearchCount)] HttpRequest req, string caseUrn, int caseId) + public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = RestApi.CaseSearchCount)] HttpRequest req, string caseUrn, int caseId, CancellationToken cancellationToken = default) { + cancellationToken.ThrowIfCancellationRequested(); var correlationId = EstablishCorrelation(req); return await (await _coordinatorClient.GetCaseSearchIndexCount( diff --git a/polaris-gateway/Functions/PolarisPipelineGetCaseTracker.cs b/polaris-gateway/Functions/PolarisPipelineGetCaseTracker.cs index 297ede7bb..6e9ceda73 100644 --- a/polaris-gateway/Functions/PolarisPipelineGetCaseTracker.cs +++ b/polaris-gateway/Functions/PolarisPipelineGetCaseTracker.cs @@ -11,6 +11,7 @@ using PolarisGateway.Extensions; using System.Net; using System.Net.Http; +using System.Threading; using System.Threading.Tasks; namespace PolarisGateway.Functions; @@ -42,8 +43,9 @@ public PolarisPipelineGetCaseTracker( [OpenApiResponseWithoutBody(statusCode: HttpStatusCode.NoContent, Summary = "Invalid request", Description = "Missing or invalid parameters")] - public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = RestApi.CaseTracker)] HttpRequest req, string caseUrn, int caseId) + public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = RestApi.CaseTracker)] HttpRequest req, string caseUrn, int caseId, CancellationToken cancellationToken = default) { + cancellationToken.ThrowIfCancellationRequested(); var correlationId = EstablishCorrelation(req); return await (await _coordinatorClient.GetTrackerGetCaseAsync( diff --git a/polaris-gateway/Functions/PolarisPipelineModifyDocument.cs b/polaris-gateway/Functions/PolarisPipelineModifyDocument.cs index 850ce3e6d..c60504261 100644 --- a/polaris-gateway/Functions/PolarisPipelineModifyDocument.cs +++ b/polaris-gateway/Functions/PolarisPipelineModifyDocument.cs @@ -1,6 +1,7 @@ using System; using System.Net; using System.Net.Http; +using System.Threading; using System.Threading.Tasks; using Common.Configuration; using Common.Dto.Request; @@ -48,13 +49,14 @@ public PolarisPipelineModifyDocument( [OpenApiParameter("caseId", In = ParameterLocation.Path, Type = typeof(int), Description = "The Id of the case to add a new action plan.", Required = true)] [OpenApiResponseWithBody(statusCode: HttpStatusCode.OK, contentType: "application/json", bodyType: typeof(object), Summary = "Case found", Description = "Returns case details")] [OpenApiResponseWithoutBody(statusCode: HttpStatusCode.NoContent, Summary = "Invalid request", Description = "Missing or invalid parameters")] - public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = RestApi.ModifyDocument)] HttpRequest req, string caseUrn, int caseId, string materialId, long documentId) + public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = RestApi.ModifyDocument)] HttpRequest req, string caseUrn, int caseId, string materialId, long documentId, CancellationToken cancellationToken = default) { var telemetryEvent = new DocumentModifiedEvent(caseId, materialId) { OperationName = nameof(PolarisPipelineModifyDocument), }; + cancellationToken.ThrowIfCancellationRequested(); var correlationId = EstablishCorrelation(req); var cmsAuthValues = EstablishCmsAuthValues(req); diff --git a/polaris-gateway/Functions/PolarisPipelineSaveDocumentRedactions.cs b/polaris-gateway/Functions/PolarisPipelineSaveDocumentRedactions.cs index 8fa65f305..14b853609 100644 --- a/polaris-gateway/Functions/PolarisPipelineSaveDocumentRedactions.cs +++ b/polaris-gateway/Functions/PolarisPipelineSaveDocumentRedactions.cs @@ -22,6 +22,7 @@ using System.Collections.Generic; using System.Net; using System.Net.Http; +using System.Threading; using System.Threading.Tasks; namespace PolarisGateway.Functions; @@ -60,13 +61,14 @@ public PolarisPipelineSaveDocumentRedactions( [OpenApiParameter("documentId", In = ParameterLocation.Path, Type = typeof(long), Description = "The document Id (version) of the material", Required = true)] [OpenApiResponseWithBody(HttpStatusCode.OK, "application/json", typeof(IEnumerable), Description = "OCR processing completed successfully")] [OpenApiResponseWithoutBody(statusCode: HttpStatusCode.NoContent, Summary = "Invalid request", Description = "Missing or invalid parameters")] - public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, "put", Route = RestApi.RedactDocument)] HttpRequest req, string caseUrn, int caseId, string materialId, long documentId) + public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, "put", Route = RestApi.RedactDocument)] HttpRequest req, string caseUrn, int caseId, string materialId, long documentId, CancellationToken cancellationToken = default) { var telemetryEvent = new RedactionRequestEvent(caseId, materialId) { OperationName = nameof(PolarisPipelineSaveDocumentRedactions), }; + cancellationToken.ThrowIfCancellationRequested(); var correlationId = EstablishCorrelation(req); var cmsAuthValues = EstablishCmsAuthValues(req); diff --git a/polaris-gateway/Functions/ReclassifyDocument.cs b/polaris-gateway/Functions/ReclassifyDocument.cs index d3e74b898..e331110c5 100644 --- a/polaris-gateway/Functions/ReclassifyDocument.cs +++ b/polaris-gateway/Functions/ReclassifyDocument.cs @@ -14,6 +14,7 @@ using PolarisGateway.TelemetryEvents; using PolarisGateway.Validators; using System.Net; +using System.Threading; using System.Threading.Tasks; namespace PolarisGateway.Functions; @@ -50,8 +51,9 @@ public ReclassifyDocument( [OpenApiResponseWithBody(statusCode: HttpStatusCode.OK, contentType: "application/json", bodyType: typeof(object), Summary = "Document Note List", Description = "Returns list of document notes")] [OpenApiResponseWithoutBody(statusCode: HttpStatusCode.NoContent, Summary = "Invalid request", Description = "Missing or invalid parameters")] - public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = RestApi.ReclassifyDocument)] HttpRequest req, string caseUrn, int caseId, string materialId) + public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = RestApi.ReclassifyDocument)] HttpRequest req, string caseUrn, int caseId, string materialId, CancellationToken cancellationToken = default) { + cancellationToken.ThrowIfCancellationRequested(); var telemetryEvent = new DocumentReclassifiedEvent(caseId, materialId) { OperationName = nameof(ReclassifyDocument), diff --git a/polaris-gateway/Functions/RenameDocument.cs b/polaris-gateway/Functions/RenameDocument.cs index ae1449116..fcb8b846f 100644 --- a/polaris-gateway/Functions/RenameDocument.cs +++ b/polaris-gateway/Functions/RenameDocument.cs @@ -19,6 +19,7 @@ using System; using System.Linq; using System.Net; +using System.Threading; using System.Threading.Tasks; namespace PolarisGateway.Functions; @@ -51,8 +52,9 @@ public RenameDocument(ILogger logger, [OpenApiResponseWithBody(statusCode: HttpStatusCode.OK, contentType: "application/json", bodyType: typeof(object), Summary = "Document rename", Description = "Returns list of document notes")] [OpenApiResponseWithoutBody(statusCode: HttpStatusCode.NoContent, Summary = "Invalid request", Description = "Missing or invalid parameters")] - public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, "put", Route = RestApi.RenameDocument)] HttpRequest req, string caseUrn, int caseId, string materialId) + public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, "put", Route = RestApi.RenameDocument)] HttpRequest req, string caseUrn, int caseId, string materialId, CancellationToken cancellationToken = default) { + cancellationToken.ThrowIfCancellationRequested(); var telemetryEvent = new RenameDocumentRequestEvent(caseId, materialId) { OperationName = nameof(RenameDocument), diff --git a/polaris-gateway/Functions/ToggleIsUnusedDocument.cs b/polaris-gateway/Functions/ToggleIsUnusedDocument.cs index 741acfbda..0fd94c2a8 100644 --- a/polaris-gateway/Functions/ToggleIsUnusedDocument.cs +++ b/polaris-gateway/Functions/ToggleIsUnusedDocument.cs @@ -11,6 +11,7 @@ using Microsoft.Extensions.Logging; using Microsoft.OpenApi.Models; using System.Net; +using System.Threading; using System.Threading.Tasks; namespace PolarisGateway.Functions; @@ -42,7 +43,8 @@ public async Task Run( string caseUrn, int caseId, string materialId, - string isUnused) + string isUnused, + CancellationToken cancellationToken = default) { var correlationId = EstablishCorrelation(req); var cmsAuthValues = EstablishCmsAuthValues(req); @@ -57,6 +59,7 @@ public async Task Run( Urn = caseUrn, }; - return await _mdsClient.ToggleIsUnusedDocumentAsync(toggleIsUnusedDocumentDto) ? new OkResult() : new BadRequestResult(); + cancellationToken.ThrowIfCancellationRequested(); + return await _mdsClient.ToggleIsUnusedDocumentAsync(toggleIsUnusedDocumentDto, cancellationToken) ? new OkResult() : new BadRequestResult(); } } \ No newline at end of file diff --git a/polaris-gateway/Services/Artefact/Domain/GetPdfRequest.cs b/polaris-gateway/Services/Artefact/Domain/GetPdfRequest.cs new file mode 100644 index 000000000..06a6b8f0d --- /dev/null +++ b/polaris-gateway/Services/Artefact/Domain/GetPdfRequest.cs @@ -0,0 +1,20 @@ +using System; + +namespace PolarisGateway.Services.Artefact.Domain; + +/// +/// Represents a request to retrieve a PDF artefact. +/// +/// The case URN identifier. +/// The case identifier. +/// The material identifier. +/// The document identifier (version) of the material. +/// Indicates whether OCR processing should be applied. +/// Indicates whether to force a refresh bypassing cache. +public record GetPdfRequest( + string Urn, + int CaseId, + string MaterialId, + long DocumentId, + bool IsOcrProcessed = false, + bool ForceRefresh = false); diff --git a/polaris-gateway/Services/Artefact/IPdfArtefactService.cs b/polaris-gateway/Services/Artefact/IPdfArtefactService.cs index 6a318ca27..2089a0711 100644 --- a/polaris-gateway/Services/Artefact/IPdfArtefactService.cs +++ b/polaris-gateway/Services/Artefact/IPdfArtefactService.cs @@ -1,12 +1,24 @@ using PolarisGateway.Services.Artefact.Domain; using System; using System.IO; +using System.Threading; using System.Threading.Tasks; -using Microsoft.AspNetCore.Http; namespace PolarisGateway.Services.Artefact; public interface IPdfArtefactService { - public Task> GetPdfAsync(string cmsAuthValues, Guid correlationId, string urn, int caseId, string materialId, long documentId, bool isOcrProcessed, bool forceRefresh = false); -} + /// + /// Retrieves a PDF artefact asynchronously. + /// + /// The request containing document identification and processing options. + /// The CMS authentication values. + /// The correlation identifier for tracking the request. + /// The cancellation token. + /// An artefact result containing the PDF stream. + public Task> GetPdfAsync( + GetPdfRequest request, + string cmsAuthValues, + Guid correlationId, + CancellationToken cancellationToken = default); +} \ No newline at end of file diff --git a/polaris-gateway/Services/Artefact/OcrArtefactService.cs b/polaris-gateway/Services/Artefact/OcrArtefactService.cs index 59a71aba8..67b7fecd2 100644 --- a/polaris-gateway/Services/Artefact/OcrArtefactService.cs +++ b/polaris-gateway/Services/Artefact/OcrArtefactService.cs @@ -52,7 +52,15 @@ public async Task> GetOcrAsync(string cmsAuthValu } // If we are being called without an operationId and there is nothing in cache then we need to start a new OCR operation... - var pdfResult = await _pdfArtefactService.GetPdfAsync(cmsAuthValues, correlationId, urn, caseId, materialId, documentId, isOcrProcessed, forceRefresh); + var request = new GetPdfRequest( + Urn: urn, + CaseId: caseId, + MaterialId: materialId, + DocumentId: documentId, + IsOcrProcessed: isOcrProcessed, + ForceRefresh: forceRefresh); + + var pdfResult = await _pdfArtefactService.GetPdfAsync(request, cmsAuthValues, correlationId); if (pdfResult.Status != ResultStatus.ArtefactAvailable) { diff --git a/polaris-gateway/Services/Artefact/PdfArtefactService.cs b/polaris-gateway/Services/Artefact/PdfArtefactService.cs index eb2b767b2..f3f77969b 100644 --- a/polaris-gateway/Services/Artefact/PdfArtefactService.cs +++ b/polaris-gateway/Services/Artefact/PdfArtefactService.cs @@ -13,6 +13,7 @@ using PolarisGateway.Services.Artefact.Factories; using System; using System.IO; +using System.Threading; using System.Threading.Tasks; namespace PolarisGateway.Services.Artefact; @@ -33,16 +34,22 @@ public class PdfArtefactService( private readonly IPdfRetrievalService _pdfRetrievalService = pdfRetrievalService.ExceptionIfNull(); private readonly IOcrService _ocrService = ocrService.ExceptionIfNull(); - public async Task> GetPdfAsync(string cmsAuthValues, Guid correlationId, string urn, int caseId, string materialId, long documentId, bool isOcrProcessed, bool forceRefresh = false) + public async Task> GetPdfAsync( + GetPdfRequest request, + string cmsAuthValues, + Guid correlationId, + CancellationToken cancellationToken = default) { - if (!forceRefresh && await _cacheService.TryGetPdfAsync(caseId, materialId, documentId, isOcrProcessed) is (true, var stream)) + cancellationToken.ThrowIfCancellationRequested(); + + if (!request.ForceRefresh && await _cacheService.TryGetPdfAsync(request.CaseId, request.MaterialId, request.DocumentId, request.IsOcrProcessed) is (true, var stream)) { - var cachedFileSizeInMb = await _cacheService.GetPdfSizeFromMetadataAsync(caseId, materialId, documentId, isOcrProcessed); + var cachedFileSizeInMb = await _cacheService.GetPdfSizeFromMetadataAsync(request.CaseId, request.MaterialId, request.DocumentId, request.IsOcrProcessed); - return ValidateFileSizeAndCreatePdfResult(stream, documentId, true, cachedFileSizeInMb ?? 0); + return ValidateFileSizeAndCreatePdfResult(stream, request.DocumentId, true, cachedFileSizeInMb ?? 0); } - var result = await _pdfRetrievalService.GetPdfStreamAsync(cmsAuthValues, correlationId, urn, caseId, materialId, documentId); + var result = await _pdfRetrievalService.GetPdfStreamAsync(cmsAuthValues, correlationId, request.Urn, request.CaseId, request.MaterialId, request.DocumentId); if (result.Status != PdfConversionStatus.DocumentConverted) { @@ -60,18 +67,18 @@ public async Task> GetPdfAsync(string cmsAuthValues, Guid } // Process OCR and upload to cache - await ProcessAndUploadOcrAsync(pdfBytes, caseId, materialId, documentId, correlationId); + await ProcessAndUploadOcrAsync(pdfBytes, request.CaseId, request.MaterialId, request.DocumentId, correlationId); // For PDF upload: use another fresh MemoryStream using (var uploadStream = new MemoryStream(pdfBytes)) { fileSizeInMb = uploadStream.Length / (1024.0 * 1024.0); - await _cacheService.UploadPdfAsync(caseId, materialId, documentId, isOcrProcessed, uploadStream, fileSizeInMb); + await _cacheService.UploadPdfAsync(request.CaseId, request.MaterialId, request.DocumentId, request.IsOcrProcessed, uploadStream, fileSizeInMb); } - var (_, pdfStream) = await _cacheService.TryGetPdfAsync(caseId, materialId, documentId, isOcrProcessed); + var (_, pdfStream) = await _cacheService.TryGetPdfAsync(request.CaseId, request.MaterialId, request.DocumentId, request.IsOcrProcessed); - return ValidateFileSizeAndCreatePdfResult(pdfStream, documentId, false, fileSizeInMb); + return ValidateFileSizeAndCreatePdfResult(pdfStream, request.DocumentId, false, fileSizeInMb); } private ArtefactResult ValidateFileSizeAndCreatePdfResult(Stream pdfStream, long documentId, bool fromCache, double fileSizeInMb) diff --git a/polaris-gateway/Services/MdsOrchestration/IMdsCaseOrchestrationService.cs b/polaris-gateway/Services/MdsOrchestration/IMdsCaseOrchestrationService.cs index aa82d1ea7..a4a717c59 100644 --- a/polaris-gateway/Services/MdsOrchestration/IMdsCaseOrchestrationService.cs +++ b/polaris-gateway/Services/MdsOrchestration/IMdsCaseOrchestrationService.cs @@ -1,12 +1,13 @@ using Common.Dto.Response.Case; using Ddei.Domain.CaseData.Args.Core; using System.Collections.Generic; +using System.Threading; using System.Threading.Tasks; namespace PolarisGateway.Services.MdsOrchestration; public interface IMdsCaseOrchestrationService { - Task GetCase(MdsCaseIdentifiersArgDto arg); - Task> GetCases(MdsUrnArgDto arg); + Task GetCase(MdsCaseIdentifiersArgDto arg, CancellationToken cancellationToken = default); + Task> GetCases(MdsUrnArgDto arg, CancellationToken cancellationToken = default); } \ No newline at end of file diff --git a/polaris-gateway/Services/MdsOrchestration/MdsCaseOrchestrationService.cs b/polaris-gateway/Services/MdsOrchestration/MdsCaseOrchestrationService.cs index e4412494a..59533a3c8 100644 --- a/polaris-gateway/Services/MdsOrchestration/MdsCaseOrchestrationService.cs +++ b/polaris-gateway/Services/MdsOrchestration/MdsCaseOrchestrationService.cs @@ -7,6 +7,7 @@ using DdeiClient.Clients.Interfaces; using System.Collections.Generic; using System.Linq; +using System.Threading; using System.Threading.Tasks; namespace PolarisGateway.Services.MdsOrchestration; @@ -28,29 +29,29 @@ ICaseDetailsMapper caseDetailsMapper _caseDetailsMapper = caseDetailsMapper.ExceptionIfNull(); } - public async Task GetCase(MdsCaseIdentifiersArgDto arg) + public async Task GetCase(MdsCaseIdentifiersArgDto arg, CancellationToken cancellationToken = default) { - var @case = await GetCaseDetails(arg); + var @case = await GetCaseDetails(arg, cancellationToken); return _caseDetailsMapper.MapCaseDetails(@case); } - public async Task> GetCases(MdsUrnArgDto arg) + public async Task> GetCases(MdsUrnArgDto arg, CancellationToken cancellationToken = default) { - var caseIdentifiers = await _mdsClient.ListCaseIdsAsync(arg); + var caseIdentifiers = await _mdsClient.ListCaseIdsAsync(arg, cancellationToken); var calls = caseIdentifiers.Select(async caseIdentifier => - await GetCaseDetails(_mdsArgFactory.CreateCaseArgFromUrnArg(arg, caseIdentifier.Id))); + await GetCaseDetails(_mdsArgFactory.CreateCaseArgFromUrnArg(arg, caseIdentifier.Id), cancellationToken)); var cases = await Task.WhenAll(calls); return cases.Select(@case => _caseDetailsMapper.MapCaseDetails(@case)); } - private async Task GetCaseDetails(MdsCaseIdentifiersArgDto arg) + private async Task GetCaseDetails(MdsCaseIdentifiersArgDto arg, CancellationToken cancellationToken = default) { - var getCaseSummaryTask = _mdsClient.GetCaseSummaryAsync(_mdsArgFactory.CreateCaseIdArg(arg.CmsAuthValues, arg.CorrelationId, arg.CaseId, arg.Urn)); - var getDefendantsAndChargesTask = _mdsClient.GetDefendantAndChargesAsync(arg); - var witnessesTask = _mdsClient.GetWitnessesAsync(arg); - var getPcdRequestTask = _mdsClient.GetPcdRequestsAsync(arg); + var getCaseSummaryTask = _mdsClient.GetCaseSummaryAsync(_mdsArgFactory.CreateCaseIdArg(arg.CmsAuthValues, arg.CorrelationId, arg.CaseId, arg.Urn), cancellationToken); + var getDefendantsAndChargesTask = _mdsClient.GetDefendantAndChargesAsync(arg, cancellationToken); + var witnessesTask = _mdsClient.GetWitnessesAsync(arg, cancellationToken); + var getPcdRequestTask = _mdsClient.GetPcdRequestsAsync(arg, cancellationToken); await Task.WhenAll(getCaseSummaryTask, getDefendantsAndChargesTask, witnessesTask, getPcdRequestTask); diff --git a/polaris-pipeline/Common/Dto/Request/HouseKeeping/ReclassifyCaseMaterialServiceRequest.cs b/polaris-pipeline/Common/Dto/Request/HouseKeeping/ReclassifyCaseMaterialServiceRequest.cs new file mode 100644 index 000000000..44f1b1fd4 --- /dev/null +++ b/polaris-pipeline/Common/Dto/Request/HouseKeeping/ReclassifyCaseMaterialServiceRequest.cs @@ -0,0 +1,30 @@ +// +// Copyright (c) The Crown Prosecution Service. All rights reserved. +// + +namespace Common.Dto.Request.HouseKeeping; + +using System; + +/// +/// Represents a service-level request to reclassify a case material, containing all necessary parameters. +/// +/// The unique identifier of the case. +/// The unique identifier of the material to reclassify. +/// The type of classification to apply. +/// The document type id. +/// Flag to indicate if material is used or unused. +/// The material subject. +/// The statement request. +/// Exhibit request. +/// The correspondence identifier. +public record ReclassifyCaseMaterialServiceRequest( + int CaseId, + int MaterialId, + string Classification, + int DocumentTypeId, + bool Used, + string Subject, + ReclassifyStatementRequest? Statement = null, + ReclassifyExhibitRequest? Exhibit = null, + Guid CorrespondenceId = default); From a36604f282fb58a948589c2998846f5eec9dec55 Mon Sep 17 00:00:00 2001 From: brad-cps Date: Fri, 10 Jul 2026 10:02:14 +0100 Subject: [PATCH 15/19] FCT2-16019 Whitelist Register a Case in prod for auth handover (#2086) --- polaris-terraform/main-terraform/prod.tfvars | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/polaris-terraform/main-terraform/prod.tfvars b/polaris-terraform/main-terraform/prod.tfvars index 4ab3f70cf..dc72f6f20 100644 --- a/polaris-terraform/main-terraform/prod.tfvars +++ b/polaris-terraform/main-terraform/prod.tfvars @@ -73,7 +73,7 @@ cms_details = { cin5_upstream_cms_services_domain_name = "not-used-in-cin5.cps.gov.uk" } -auth_handover_whitelist = "/auth-refresh-inbound,https://cps.outsystemsenterprise.com/,https://housekeeping-fn.cps.gov.uk/,https://lcc-api.cps.gov.uk/,https://polaris.cps.gov.uk/auth-refresh-inbound?polaris-ui-url=/materials-ui" +auth_handover_whitelist = "/auth-refresh-inbound,https://cps.outsystemsenterprise.com/,https://housekeeping-fn.cps.gov.uk/,https://lcc-api.cps.gov.uk/,https://polaris.cps.gov.uk/auth-refresh-inbound?polaris-ui-url=/materials-ui,https://register-a-case-api.cps.gov.uk/" app_service_log_retention = 90 app_service_log_total_retention = 2555 From 4fbc498f289d4d6adbe391b8620404fb756c50ce Mon Sep 17 00:00:00 2001 From: robmolloy-cps Date: Tue, 14 Jul 2026 10:11:11 +0100 Subject: [PATCH 16/19] =?UTF-8?q?FCT2-20395-cwa-make-supporting-notes-requ?= =?UTF-8?q?ired-where-redaction-type-ot=E2=80=A6=20(#2087)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * FCT2-20395-cwa-make-supporting-notes-required-where-redaction-type-other-is-selected * FCT2-20395-cwa-make-supporting-notes-required-where-redaction-type-other-is-selected --- .../redactionLog/RedactionLogContent.tsx | 30 ++++++++++++++----- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/polaris-ui/src/app/features/cases/presentation/case-details/redactionLog/RedactionLogContent.tsx b/polaris-ui/src/app/features/cases/presentation/case-details/redactionLog/RedactionLogContent.tsx index c1b117dc1..c36127e1c 100644 --- a/polaris-ui/src/app/features/cases/presentation/case-details/redactionLog/RedactionLogContent.tsx +++ b/polaris-ui/src/app/features/cases/presentation/case-details/redactionLog/RedactionLogContent.tsx @@ -45,6 +45,7 @@ export type ErrorState = { underRedaction: boolean; overRedaction: boolean; notes: boolean; + isSelectedRedactionOfOtherTypeAndNotesBlank: boolean; }; type RedactionLogContentProps = { @@ -89,6 +90,9 @@ export const RedactionLogContent: React.FC = ({ redactionLogMappingsData, handleCloseRedactionLog, }) => { + const isSelectedRedactionOfOtherType = savedRedactionTypes.some( + (x) => x.name === "Other" + ); const errorSummaryRef = useRef(null); const trackEvent = useAppInsightsTrackEvent(); const [savingRedactionLog, setSavingRedactionLog] = useState(false); @@ -102,6 +106,7 @@ export const RedactionLogContent: React.FC = ({ underRedaction: false, overRedaction: false, notes: false, + isSelectedRedactionOfOtherTypeAndNotesBlank: false, }); const [defaultValues, setDefaultValues] = useState({ cpsArea: "", @@ -241,7 +246,7 @@ export const RedactionLogContent: React.FC = ({ ); }; - const supportingNotesGuidanceContent = () => { + const SupportingNotesGuidanceContent = () => { return (

@@ -254,10 +259,6 @@ export const RedactionLogContent: React.FC = ({

  • Avoid recording full names
  • Do not record sensitive personal data
  • -
  • - {`Supporting notes optional - ${NOTES_MAX_CHARACTERS} characters - maximum`} -
  • ); @@ -453,6 +454,12 @@ export const RedactionLogContent: React.FC = ({ href: "#redaction-log-notes", "data-testid": "redaction-log-notes-link", }; + case "isSelectedRedactionOfOtherTypeAndNotesBlank": + return { + children: `Please enter required Supporting notes`, + href: "#redaction-log-notes", + "data-testid": "redaction-log-notes-link", + }; } }; @@ -607,6 +614,9 @@ export const RedactionLogContent: React.FC = ({ documentType: !getValues("documentType"), chargeStatus: !getValues("chargeStatus"), notes: getValues("notes").length > NOTES_MAX_CHARACTERS, + isSelectedRedactionOfOtherTypeAndNotesBlank: + isSelectedRedactionOfOtherType && + getValues("notes").trim().length === 0, })); handleSubmit( (data) => { @@ -624,7 +634,6 @@ export const RedactionLogContent: React.FC = ({ if (errorSummaryRef.current) { (errorSummaryRef?.current as HTMLButtonElement).focus(); } - console.log("error", errors); } )(event); }} @@ -870,13 +879,18 @@ export const RedactionLogContent: React.FC = ({ ariaDescription="Guidance on adding optional supporting notes for redaction log" dataTestId="guidance-supporting-notes" > - {supportingNotesGuidanceContent()} + errorState.notes !== true }, + validate: { + required: () => errorState.notes !== true, + isSelectedRedactionOfOtherTypeAndNotBlank: (val) => + errorState.isSelectedRedactionOfOtherTypeAndNotesBlank !== + true, + }, }} render={({ field }) => { return ( From 3e6f8fe21ae23c41ccdebd844325dd1cc079cc86 Mon Sep 17 00:00:00 2001 From: robmolloy-cps Date: Tue, 14 Jul 2026 10:14:46 +0100 Subject: [PATCH 17/19] FCT2-20486-19-i-cannot-view-materials-3 (#2085) --- .../use-case-details-state/map-redaction-save-request.ts | 2 +- .../case-details/pdf-tabs/HeaderAttachmentMode.tsx | 2 +- .../presentation/case-details/portals/DeletePage.tsx | 2 +- .../case-details/reclassify/ReclassifyStage2.tsx | 4 ++-- .../case-details/redactionLog/UnderRedactionContent.tsx | 9 ++++++--- 5 files changed, 11 insertions(+), 8 deletions(-) diff --git a/polaris-ui/src/app/features/cases/hooks/use-case-details-state/map-redaction-save-request.ts b/polaris-ui/src/app/features/cases/hooks/use-case-details-state/map-redaction-save-request.ts index 691f5e3bc..a03ca9f7f 100644 --- a/polaris-ui/src/app/features/cases/hooks/use-case-details-state/map-redaction-save-request.ts +++ b/polaris-ui/src/app/features/cases/hooks/use-case-details-state/map-redaction-save-request.ts @@ -115,7 +115,7 @@ export const mapSearchPIISaveRedactionObject = ( const piiData = Object.entries(piiCategoryGroupedHighlights).map( ([key, value]) => { return { - polarisCategory: value[0].redactionType.name, + polarisCategory: value[0].redactionType?.name, providerCategory: key, countSuggestions: value.length, countAccepted: value.filter( diff --git a/polaris-ui/src/app/features/cases/presentation/case-details/pdf-tabs/HeaderAttachmentMode.tsx b/polaris-ui/src/app/features/cases/presentation/case-details/pdf-tabs/HeaderAttachmentMode.tsx index 38952d750..802977e8f 100644 --- a/polaris-ui/src/app/features/cases/presentation/case-details/pdf-tabs/HeaderAttachmentMode.tsx +++ b/polaris-ui/src/app/features/cases/presentation/case-details/pdf-tabs/HeaderAttachmentMode.tsx @@ -36,7 +36,7 @@ export const HeaderAttachmentMode: React.FC = ({ handleAttachmentClick(item.documentId); }} > - {item.name} + {item?.name} {index < attachments.length - 1 && ( , )} diff --git a/polaris-ui/src/app/features/cases/presentation/case-details/portals/DeletePage.tsx b/polaris-ui/src/app/features/cases/presentation/case-details/portals/DeletePage.tsx index a9536cdac..a6299456a 100644 --- a/polaris-ui/src/app/features/cases/presentation/case-details/portals/DeletePage.tsx +++ b/polaris-ui/src/app/features/cases/presentation/case-details/portals/DeletePage.tsx @@ -78,7 +78,7 @@ export const DeletePage: React.FC = ({ trackEvent("Delete Page", { documentId: documentId, pageNumber: pageNumber, - reason: redactionType.name, + reason: redactionType?.name, }); setShowModal(false); }; diff --git a/polaris-ui/src/app/features/cases/presentation/case-details/reclassify/ReclassifyStage2.tsx b/polaris-ui/src/app/features/cases/presentation/case-details/reclassify/ReclassifyStage2.tsx index ee2273919..3c20e59df 100644 --- a/polaris-ui/src/app/features/cases/presentation/case-details/reclassify/ReclassifyStage2.tsx +++ b/polaris-ui/src/app/features/cases/presentation/case-details/reclassify/ReclassifyStage2.tsx @@ -257,10 +257,10 @@ export const ReclassifyStage2: React.FC = ({ const handleStatementDateChange = (event: any) => { let type: "day" | "month" | "year" = "day"; - if (event.target.name === "reclassify-statement-date-month") { + if (event.target?.name === "reclassify-statement-date-month") { type = "month"; } - if (event.target.name === "reclassify-statement-date-year") { + if (event.target?.name === "reclassify-statement-date-year") { type = "year"; } if (type) diff --git a/polaris-ui/src/app/features/cases/presentation/case-details/redactionLog/UnderRedactionContent.tsx b/polaris-ui/src/app/features/cases/presentation/case-details/redactionLog/UnderRedactionContent.tsx index df3a66cd3..8ae6c9da9 100644 --- a/polaris-ui/src/app/features/cases/presentation/case-details/redactionLog/UnderRedactionContent.tsx +++ b/polaris-ui/src/app/features/cases/presentation/case-details/redactionLog/UnderRedactionContent.tsx @@ -14,11 +14,14 @@ export const UnderRedactionContent: React.FC = ({ const redactionSummary = useMemo(() => { const groupedRedactions = savedRedactionTypes.reduce( (acc, redactionType) => { - if (!acc[redactionType.name]) { - acc[redactionType.name] = 1; + const redactionTypeName = redactionType.name; + if (!redactionTypeName) return acc; + + if (!acc[redactionTypeName]) { + acc[redactionTypeName] = 1; return acc; } - acc[redactionType.name] = acc[redactionType.name] + 1; + acc[redactionTypeName] = acc[redactionTypeName] + 1; return acc; }, {} as Record From 23179b643cea40606c6462719626c24d4283ab56 Mon Sep 17 00:00:00 2001 From: kramduny-cps Date: Tue, 14 Jul 2026 16:46:21 +0100 Subject: [PATCH 18/19] FCT2-19721 - Fix for Redaction converting PDF to image (#2090) * FCT2-19721 - Fix for Redaction converting PDF to image and reducing quality. * fix warning --- .../DirectImplementation.cs | 43 ++++++++++++------- .../Extensions/ServiceCollectionExtension.cs | 2 +- 2 files changed, 29 insertions(+), 16 deletions(-) diff --git a/polaris-pipeline/pdf-redactor/Services/DocumentRedaction/Aspose/RedactionImplementations/DirectImplementation.cs b/polaris-pipeline/pdf-redactor/Services/DocumentRedaction/Aspose/RedactionImplementations/DirectImplementation.cs index 355ade166..c48e22290 100644 --- a/polaris-pipeline/pdf-redactor/Services/DocumentRedaction/Aspose/RedactionImplementations/DirectImplementation.cs +++ b/polaris-pipeline/pdf-redactor/Services/DocumentRedaction/Aspose/RedactionImplementations/DirectImplementation.cs @@ -1,26 +1,39 @@ using Aspose.Pdf; using Aspose.Pdf.Annotations; -namespace pdf_redactor.Services.DocumentRedaction.Aspose.RedactionImplementations +namespace pdf_redactor.Services.DocumentRedaction.Aspose.RedactionImplementations; + +public class DirectImplementation : IRedactionImplementation { - public class DirectImplementation : IRedactionImplementation + public void AttachAnnotation(Page page, Rectangle rect) { - public void AttachAnnotation(Page page, Rectangle rect) + var redaction = new RedactionAnnotation(page, rect) { - var hardAnnotation = new RedactionAnnotation(page, rect) - { - FillColor = Color.Black, - }; - - page.Annotations.Add(hardAnnotation, true); - hardAnnotation.Redact(); - } + FillColor = Color.Black, + Color = Color.Black, + }; - public void FinaliseAnnotations(ref Document doc, Guid correlationId) { } + page.Annotations.Add(redaction, true); + } - public (ProviderType, string?) GetProviderType() + public void FinaliseAnnotations(ref Document doc, Guid correlationId) + { + foreach (Page page in doc.Pages) { - return (ProviderType.DirectRedaction, null); + var redactions = page.Annotations + .Where(a => a.AnnotationType == AnnotationType.Redaction) + .Cast() + .ToList(); + + foreach (var redaction in redactions) + { + redaction.Redact(); + } } } -} \ No newline at end of file + + public (ProviderType, string?) GetProviderType() + { + return (ProviderType.DirectRedaction, null); + } +} diff --git a/polaris-pipeline/pdf-redactor/Services/Extensions/ServiceCollectionExtension.cs b/polaris-pipeline/pdf-redactor/Services/Extensions/ServiceCollectionExtension.cs index 2519d4553..f457fe23b 100644 --- a/polaris-pipeline/pdf-redactor/Services/Extensions/ServiceCollectionExtension.cs +++ b/polaris-pipeline/pdf-redactor/Services/Extensions/ServiceCollectionExtension.cs @@ -17,7 +17,7 @@ public static void AddRedactionServices(this IServiceCollection services, IConfi // Aspose-specific services services.AddSingleton(); services.AddSingleton(); - services.AddSingleton(); + services.AddSingleton(); services.AddSingleton(); services.Configure(configuration.GetSection(ImageConversionOptions.ConfigKey)); } From bc292352d4cdcbeea8c1a7ae1e391c08be0c0e00 Mon Sep 17 00:00:00 2001 From: TahmeedAhmed-NTT-CPS Date: Wed, 15 Jul 2026 10:34:55 +0100 Subject: [PATCH 19/19] Fct2 18624 expose large file size header (#2091) * expose header to javascript * test * removed test code * 15mb max size limit * refactor http header keys --- polaris-gateway/Functions/GetPdf.cs | 1 + polaris-pipeline/Common/Constants/HttpHeaderKeys.cs | 1 + polaris-terraform/main-terraform/function-gateway-staging.tf | 1 + 3 files changed, 3 insertions(+) diff --git a/polaris-gateway/Functions/GetPdf.cs b/polaris-gateway/Functions/GetPdf.cs index 7534a1903..11d532efd 100644 --- a/polaris-gateway/Functions/GetPdf.cs +++ b/polaris-gateway/Functions/GetPdf.cs @@ -68,6 +68,7 @@ public async Task Run( if (getPdfResult.FileSizeExceedsLimit == true) { + req.HttpContext.Response.Headers.Append(HttpHeaderKeys.AccessControlExposeHeaders, HttpHeaderKeys.CpsFileTooLarge); req.HttpContext.Response.Headers[HttpHeaderKeys.CpsFileTooLarge] = "true"; } diff --git a/polaris-pipeline/Common/Constants/HttpHeaderKeys.cs b/polaris-pipeline/Common/Constants/HttpHeaderKeys.cs index e0a131433..299b14053 100644 --- a/polaris-pipeline/Common/Constants/HttpHeaderKeys.cs +++ b/polaris-pipeline/Common/Constants/HttpHeaderKeys.cs @@ -6,6 +6,7 @@ public static class HttpHeaderKeys public const string CmsAuthValues = "Cms-Auth-Values"; public const string CmsToken = "Token"; public const string CmsCookie = "Cookies"; + public const string AccessControlExposeHeaders = "Access-Control-Expose-Headers"; public const string CpsFileTooLarge = "CPS-File-Too-Large"; } } diff --git a/polaris-terraform/main-terraform/function-gateway-staging.tf b/polaris-terraform/main-terraform/function-gateway-staging.tf index 7c1fa4449..b2c7fdfe7 100644 --- a/polaris-terraform/main-terraform/function-gateway-staging.tf +++ b/polaris-terraform/main-terraform/function-gateway-staging.tf @@ -43,6 +43,7 @@ resource "azurerm_linux_function_app_slot" "fa_polaris_staging1" { "PolarisPipelineCoordinatorBaseUrl" = "https://fa-${local.global_resource_name}-coordinator.azurewebsites.net/api/" "PolarisPipelineRedactPdfBaseUrl" = "https://fa-${local.global_resource_name}-pdf-generator.azurewebsites.net/api/" "PolarisPdfThumbnailGeneratorBaseUrl" = "https://fa-${local.global_resource_name}-pdf-thumb-gen.azurewebsites.net/api/" + "RedactionFileSize__FileSizeLimitMb" = var.redaction_file_size_limit_mb "TenantId" = data.azurerm_client_config.current.tenant_id "WEBSITE_ADD_SITENAME_BINDINGS_IN_APPHOST_CONFIG" = "1" "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING" = azurerm_storage_account.sa_gateway.primary_connection_string