From 811730bb43708ec850da5307eb8f601db38825cb Mon Sep 17 00:00:00 2001
From: Andrea Morabito <78792023+and-mora@users.noreply.github.com>
Date: Tue, 2 Apr 2024 11:18:32 +0200
Subject: [PATCH 1/2] breaking: [RTD-2455] report v2 with additional
information (#131)
---
.github/workflows/release.yml | 4 +-
.github/workflows/scan.yml | 4 +-
docs/entities.uml | 40 ++++++
helm/rtd/values.yaml | 2 +
pom.xml | 16 +--
.../RtdMsFileReporterApplication.java | 9 +-
.../configuration/AppConfiguration.java | 8 +-
.../ConsumeEventControllerImpl.java | 8 +-
.../controller/FileReportController.java | 7 +-
.../controller/FileReportControllerImpl.java | 13 +-
.../model/{ => v1}/FileMetadataDto.java | 2 +-
.../model/{ => v1}/FileReportDto.java | 2 +-
.../model/{ => v1}/FileReportDtoMapper.java | 2 +-
.../model/v2/FileMetadataV2Dto.java | 15 +++
.../controller/model/v2/FileReportV2Dto.java | 10 ++
.../model/v2/FileReportV2DtoMapper.java | 16 +++
.../domain/FileReportCommandFactory.java | 8 +-
.../domain/model/AggregatesDataSummary.java | 36 +++++
.../domain/model/FileMetadata.java | 22 +++-
.../domain/model/FileReport.java | 11 +-
.../domain/service/DecryptedEventCommand.java | 26 ++++
.../domain/service/StorageAccountService.java | 41 ++++++
.../event/FileReportEventAdapter.java | 2 +-
.../event/model/EventToDomainMapper.java | 27 +++-
.../event/model/ProjectorEventDto.java | 2 +-
.../feign/AggregatesDataSummaryMapper.java | 20 +++
.../feign/StorageAccountRestConnector.java | 82 ++++++++++++
.../feign/config/HttpClientConfig.java | 42 ++++++
.../feign/config/StorageProperties.java | 16 +++
src/main/resources/application.yml | 6 +
.../controller/DomainToDtoMapperTest.java | 9 +-
.../FileReportControllerImplTest.java | 57 +++++++-
.../domain/model/FileReportTest.java | 58 +++++----
.../service/DecryptedEventCommandTest.java | 75 +++++++++++
.../service/StorageAccountServiceTest.java | 89 +++++++++++++
.../event/EventHandlerTest.java | 2 +-
.../event/FileReportEventAdapterTest.java | 48 ++++---
.../event/model/EventToDomainMapperTest.java | 21 ++-
.../AggregatesDataSummaryMapperTest.java | 37 ++++++
.../StorageAccountRestConnectorTest.java | 123 ++++++++++++++++++
.../FileReportRepositoryImplTest.java | 6 +-
41 files changed, 928 insertions(+), 96 deletions(-)
create mode 100644 docs/entities.uml
rename src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/controller/model/{ => v1}/FileMetadataDto.java (92%)
rename src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/controller/model/{ => v1}/FileReportDto.java (67%)
rename src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/controller/model/{ => v1}/FileReportDtoMapper.java (83%)
create mode 100644 src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/controller/model/v2/FileMetadataV2Dto.java
create mode 100644 src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/controller/model/v2/FileReportV2Dto.java
create mode 100644 src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/controller/model/v2/FileReportV2DtoMapper.java
create mode 100644 src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/domain/model/AggregatesDataSummary.java
create mode 100644 src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/domain/service/DecryptedEventCommand.java
create mode 100644 src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/domain/service/StorageAccountService.java
create mode 100644 src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/feign/AggregatesDataSummaryMapper.java
create mode 100644 src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/feign/StorageAccountRestConnector.java
create mode 100644 src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/feign/config/HttpClientConfig.java
create mode 100644 src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/feign/config/StorageProperties.java
create mode 100644 src/test/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/domain/service/DecryptedEventCommandTest.java
create mode 100644 src/test/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/domain/service/StorageAccountServiceTest.java
create mode 100644 src/test/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/feign/AggregatesDataSummaryMapperTest.java
create mode 100644 src/test/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/feign/StorageAccountRestConnectorTest.java
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index f3d7f9c..aac6940 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -17,13 +17,13 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
- uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
+ uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 #v4.1.1
with:
persist-credentials: false
fetch-depth: 0
- name: Release
- uses: cycjimmy/semantic-release-action@8e58d20d0f6c8773181f43eb74d6a05e3099571d # v3.4.2
+ uses: cycjimmy/semantic-release-action@61680d0e9b02ff86f5648ade99e01be17f0260a4 #v4.0.0
with:
semantic_version: 18.0.0
extra_plugins: |
diff --git a/.github/workflows/scan.yml b/.github/workflows/scan.yml
index a3d5502..7445433 100644
--- a/.github/workflows/scan.yml
+++ b/.github/workflows/scan.yml
@@ -33,12 +33,12 @@ jobs:
environment: dev
steps:
- name: Checkout the code
- uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 #v3.6.0
+ uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 #v4.1.1
- name: Build the Docker image
run: docker build . --file ${{ env.DOCKERFILE }} --target cve --tag localbuild/testimage:latest
- name: Run the Trivy scan action itself with GitHub Advanced Security code scanning integration enabled
id: scan
- uses: aquasecurity/trivy-action@fbd16365eb88e12433951383f5e99bd901fc618f #v0.12.0
+ uses: aquasecurity/trivy-action@062f2592684a31eb3aa050cc61e7ca1451cecd3d #v0.18.0
with:
image-ref: "localbuild/testimage:latest"
format: 'sarif'
diff --git a/docs/entities.uml b/docs/entities.uml
new file mode 100644
index 0000000..771fa71
--- /dev/null
+++ b/docs/entities.uml
@@ -0,0 +1,40 @@
+@startuml
+class FileReport {
+ -senderCodes: String[]
+ -filesUploaded: FileMetadata[]
+ -ackToDownload: String[]
+ +addFileUploaded(file)
+ +removeFileUploaded(file)
+ +addSenderCode(senderCode)
+ +addAckToDownload(file)
+ +removeAckToDownload(file)
+ +addFileOrUpdateStatus(file)
+ +removeFilesOlderThan(days)
+ +addSquaringDataToFile(file)
+}
+
+class FileMetadata {
+ -name: String
+ -path: String
+ -size: Long
+ -status: Enum
+ -transmissionDate: Date
+ -dataSummary: AggregatesDataSummary
+
+ +enrichWithSquaringData()
+}
+
+class AggregatesDataSummary {
+ -minAccountingDate: Date
+ -maxAccountingDate: Date
+ -numberOfMerchants: Integer
+ -countNegativeTransactions: Long
+ -countPositiveTransactions: Long
+ -sumAmountNegativeTransactions: Long
+ -sumAmountPositiveTransactions: Long
+ -sha256OriginFile: String
+}
+
+FileReport "1" *-- "n" FileMetadata
+FileMetadata *-- AggregatesDataSummary
+@enduml
\ No newline at end of file
diff --git a/helm/rtd/values.yaml b/helm/rtd/values.yaml
index 1cf6a77..3c4f85a 100644
--- a/helm/rtd/values.yaml
+++ b/helm/rtd/values.yaml
@@ -56,6 +56,7 @@ microservice-chart:
MONGODB_CONNECTION_URI: mongo-db-connection-uri
KAFKA_RTD_PROJECTOR_SASL_JAAS_CONFIG: evh-rtd-file-register-projector-rtd-file-register-projector-consumer-policy-rtd
APPLICATIONINSIGHTS_CONNECTION_STRING: appinsights-instrumentation-key
+ INTERNAL_SERVICES_API_KEY: rtd-internal-api-product-subscription-key
envConfigMapExternals:
rtd-file-register-projector-consumer:
@@ -64,3 +65,4 @@ microservice-chart:
rtd-filereporter:
OPENTELEMETRY_LOG_LEVEL: APPLICATIONINSIGHTS_INSTRUMENTATION_LOGGING_LEVEL
+ STORAGE_ACCOUNT_HOST: STORAGE_ACCOUNT_HOST
diff --git a/pom.xml b/pom.xml
index 214f55f..6c3801b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,20 +5,20 @@
org.springframework.boot
spring-boot-starter-parent
- 3.2.3
+ 3.2.4
it.gov.pagopa.rtd.ms
rtd-ms-file-reporter
- 1.4.1
+ 2.0.0
rtd-ms-file-reporter
Micro-service to retrieve and keep updated the file reports for senders
17
2023.0.0
- 1.19.3
+ 1.19.7
2.2
3.6.1
**/telemetry/**.java
@@ -115,6 +115,10 @@
mongodb
test
+
+ org.apache.httpcomponents.client5
+ httpclient5
+
@@ -150,12 +154,6 @@
pom
import
-
-
- org.springframework
- spring-core
- 6.1.3
-
diff --git a/src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/RtdMsFileReporterApplication.java b/src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/RtdMsFileReporterApplication.java
index ccc0b3f..0069b04 100644
--- a/src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/RtdMsFileReporterApplication.java
+++ b/src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/RtdMsFileReporterApplication.java
@@ -1,13 +1,16 @@
package it.gov.pagopa.rtd.ms.rtdmsfilereporter;
+import it.gov.pagopa.rtd.ms.rtdmsfilereporter.feign.config.StorageProperties;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
@SpringBootApplication
+@EnableConfigurationProperties(StorageProperties.class)
public class RtdMsFileReporterApplication {
- public static void main(String[] args) {
- SpringApplication.run(RtdMsFileReporterApplication.class, args);
- }
+ public static void main(String[] args) {
+ SpringApplication.run(RtdMsFileReporterApplication.class, args);
+ }
}
diff --git a/src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/configuration/AppConfiguration.java b/src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/configuration/AppConfiguration.java
index 70d08b7..5f02f04 100644
--- a/src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/configuration/AppConfiguration.java
+++ b/src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/configuration/AppConfiguration.java
@@ -2,6 +2,7 @@
import it.gov.pagopa.rtd.ms.rtdmsfilereporter.domain.FileReportCommandFactory;
import it.gov.pagopa.rtd.ms.rtdmsfilereporter.domain.repository.FileReportRepository;
+import it.gov.pagopa.rtd.ms.rtdmsfilereporter.domain.service.DecryptedEventCommand;
import it.gov.pagopa.rtd.ms.rtdmsfilereporter.domain.service.FileReportService;
import it.gov.pagopa.rtd.ms.rtdmsfilereporter.domain.service.FileReportServiceImpl;
import it.gov.pagopa.rtd.ms.rtdmsfilereporter.persistance.FileReportDao;
@@ -23,12 +24,13 @@ public FileReportService getFileReportService(FileReportRepository repository) {
}
@Bean
- public FileReportRepository getFileReportRepository(FileReportDao dao, FileReportEntityMapper mapper) {
+ public FileReportRepository getFileReportRepository(FileReportDao dao,
+ FileReportEntityMapper mapper) {
return new FileReportRepositoryImpl(dao, mapper);
}
@Bean
- public FileReportCommandFactory getFileReportCommandFactory() {
- return new FileReportCommandFactory();
+ public FileReportCommandFactory getFileReportCommandFactory(DecryptedEventCommand command) {
+ return new FileReportCommandFactory(command);
}
}
diff --git a/src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/controller/ConsumeEventControllerImpl.java b/src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/controller/ConsumeEventControllerImpl.java
index 4a86526..684c5c6 100644
--- a/src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/controller/ConsumeEventControllerImpl.java
+++ b/src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/controller/ConsumeEventControllerImpl.java
@@ -3,8 +3,8 @@
import it.gov.pagopa.rtd.ms.rtdmsfilereporter.event.FileReportEventAdapter;
import it.gov.pagopa.rtd.ms.rtdmsfilereporter.event.model.ProjectorEventDto;
import jakarta.validation.Valid;
+import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
-import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.ResponseBody;
@@ -13,14 +13,14 @@
@RestController
@ResponseBody
@Slf4j
+@RequiredArgsConstructor
public class ConsumeEventControllerImpl implements ConsumeEventController {
- @Autowired
- private FileReportEventAdapter adapter;
+ private final FileReportEventAdapter adapter;
@Override
public void consumeEvent(@RequestBody @Valid ProjectorEventDto eventData) {
- log.info("Received event [{}]", eventData.getFileName());
+ log.info("Received event [{}]", eventData.getFilePath());
adapter.consumeEvent(MessageBuilder.withPayload(eventData).build().getPayload());
}
diff --git a/src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/controller/FileReportController.java b/src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/controller/FileReportController.java
index 818e098..6c9a478 100644
--- a/src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/controller/FileReportController.java
+++ b/src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/controller/FileReportController.java
@@ -1,7 +1,8 @@
package it.gov.pagopa.rtd.ms.rtdmsfilereporter.controller;
-import it.gov.pagopa.rtd.ms.rtdmsfilereporter.controller.model.FileReportDto;
import it.gov.pagopa.rtd.ms.rtdmsfilereporter.controller.model.SenderAdeAckListDto;
+import it.gov.pagopa.rtd.ms.rtdmsfilereporter.controller.model.v1.FileReportDto;
+import it.gov.pagopa.rtd.ms.rtdmsfilereporter.controller.model.v2.FileReportV2Dto;
import jakarta.validation.constraints.NotNull;
import java.util.Collection;
import org.springframework.http.MediaType;
@@ -13,6 +14,10 @@ public interface FileReportController {
@GetMapping(value = "file-report", produces = MediaType.APPLICATION_JSON_VALUE)
FileReportDto getFileReport(@RequestParam(name = "senderCodes") Collection senderCodes);
+ @GetMapping(value = "v2/file-report", produces = MediaType.APPLICATION_JSON_VALUE)
+ FileReportV2Dto getFileReportV2(
+ @RequestParam(name = "senderCodes") Collection senderCodes);
+
@GetMapping(value = "/sender-ade-ack", produces = MediaType.APPLICATION_JSON_VALUE)
SenderAdeAckListDto getSenderAdeAckList(
@NotNull @RequestParam(name = "senderCodes") Collection senderCodes);
diff --git a/src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/controller/FileReportControllerImpl.java b/src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/controller/FileReportControllerImpl.java
index 22e733f..56e2f3e 100644
--- a/src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/controller/FileReportControllerImpl.java
+++ b/src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/controller/FileReportControllerImpl.java
@@ -1,8 +1,10 @@
package it.gov.pagopa.rtd.ms.rtdmsfilereporter.controller;
-import it.gov.pagopa.rtd.ms.rtdmsfilereporter.controller.model.FileReportDto;
-import it.gov.pagopa.rtd.ms.rtdmsfilereporter.controller.model.FileReportDtoMapper;
import it.gov.pagopa.rtd.ms.rtdmsfilereporter.controller.model.SenderAdeAckListDto;
+import it.gov.pagopa.rtd.ms.rtdmsfilereporter.controller.model.v1.FileReportDto;
+import it.gov.pagopa.rtd.ms.rtdmsfilereporter.controller.model.v1.FileReportDtoMapper;
+import it.gov.pagopa.rtd.ms.rtdmsfilereporter.controller.model.v2.FileReportV2Dto;
+import it.gov.pagopa.rtd.ms.rtdmsfilereporter.controller.model.v2.FileReportV2DtoMapper;
import it.gov.pagopa.rtd.ms.rtdmsfilereporter.domain.service.FileReportService;
import jakarta.validation.constraints.NotNull;
import java.util.Collection;
@@ -17,6 +19,7 @@ public class FileReportControllerImpl implements FileReportController {
private final FileReportService fileReportService;
private final FileReportDtoMapper mapper;
+ private final FileReportV2DtoMapper mapperV2;
@Override
public FileReportDto getFileReport(Collection senderCodes) {
@@ -24,6 +27,12 @@ public FileReportDto getFileReport(Collection senderCodes) {
return mapper.fileReportToDto(fileReportService.getAggregateFileReport(senderCodes));
}
+ @Override
+ public FileReportV2Dto getFileReportV2(Collection senderCodes) {
+ log.info("GET file report v2 for sender codes: {}", senderCodes.toString());
+ return mapperV2.fileReportToDto(fileReportService.getAggregateFileReport(senderCodes));
+ }
+
@Override
public SenderAdeAckListDto getSenderAdeAckList(@NotNull Collection senderCodes) {
log.info("GET ack to download list for sender codes: {}", senderCodes.toString());
diff --git a/src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/controller/model/FileMetadataDto.java b/src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/controller/model/v1/FileMetadataDto.java
similarity index 92%
rename from src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/controller/model/FileMetadataDto.java
rename to src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/controller/model/v1/FileMetadataDto.java
index b5fcc32..281605e 100644
--- a/src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/controller/model/FileMetadataDto.java
+++ b/src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/controller/model/v1/FileMetadataDto.java
@@ -1,4 +1,4 @@
-package it.gov.pagopa.rtd.ms.rtdmsfilereporter.controller.model;
+package it.gov.pagopa.rtd.ms.rtdmsfilereporter.controller.model.v1;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
diff --git a/src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/controller/model/FileReportDto.java b/src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/controller/model/v1/FileReportDto.java
similarity index 67%
rename from src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/controller/model/FileReportDto.java
rename to src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/controller/model/v1/FileReportDto.java
index c575593..83be2a5 100644
--- a/src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/controller/model/FileReportDto.java
+++ b/src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/controller/model/v1/FileReportDto.java
@@ -1,4 +1,4 @@
-package it.gov.pagopa.rtd.ms.rtdmsfilereporter.controller.model;
+package it.gov.pagopa.rtd.ms.rtdmsfilereporter.controller.model.v1;
import java.util.Collection;
import lombok.Data;
diff --git a/src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/controller/model/FileReportDtoMapper.java b/src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/controller/model/v1/FileReportDtoMapper.java
similarity index 83%
rename from src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/controller/model/FileReportDtoMapper.java
rename to src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/controller/model/v1/FileReportDtoMapper.java
index d6a98d3..92f0d3e 100644
--- a/src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/controller/model/FileReportDtoMapper.java
+++ b/src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/controller/model/v1/FileReportDtoMapper.java
@@ -1,4 +1,4 @@
-package it.gov.pagopa.rtd.ms.rtdmsfilereporter.controller.model;
+package it.gov.pagopa.rtd.ms.rtdmsfilereporter.controller.model.v1;
import it.gov.pagopa.rtd.ms.rtdmsfilereporter.domain.model.FileReport;
import org.mapstruct.Mapper;
diff --git a/src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/controller/model/v2/FileMetadataV2Dto.java b/src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/controller/model/v2/FileMetadataV2Dto.java
new file mode 100644
index 0000000..c0eab7a
--- /dev/null
+++ b/src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/controller/model/v2/FileMetadataV2Dto.java
@@ -0,0 +1,15 @@
+package it.gov.pagopa.rtd.ms.rtdmsfilereporter.controller.model.v2;
+
+import it.gov.pagopa.rtd.ms.rtdmsfilereporter.controller.model.v1.FileMetadataDto;
+import it.gov.pagopa.rtd.ms.rtdmsfilereporter.domain.model.AggregatesDataSummary;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+@EqualsAndHashCode(callSuper = true)
+@Data
+public class FileMetadataV2Dto extends FileMetadataDto {
+
+ @NotNull
+ private AggregatesDataSummary dataSummary;
+}
diff --git a/src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/controller/model/v2/FileReportV2Dto.java b/src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/controller/model/v2/FileReportV2Dto.java
new file mode 100644
index 0000000..f880089
--- /dev/null
+++ b/src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/controller/model/v2/FileReportV2Dto.java
@@ -0,0 +1,10 @@
+package it.gov.pagopa.rtd.ms.rtdmsfilereporter.controller.model.v2;
+
+import java.util.Collection;
+import lombok.Data;
+
+@Data
+public class FileReportV2Dto {
+
+ Collection filesRecentlyUploaded;
+}
diff --git a/src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/controller/model/v2/FileReportV2DtoMapper.java b/src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/controller/model/v2/FileReportV2DtoMapper.java
new file mode 100644
index 0000000..405bb76
--- /dev/null
+++ b/src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/controller/model/v2/FileReportV2DtoMapper.java
@@ -0,0 +1,16 @@
+package it.gov.pagopa.rtd.ms.rtdmsfilereporter.controller.model.v2;
+
+import it.gov.pagopa.rtd.ms.rtdmsfilereporter.domain.model.FileMetadata;
+import it.gov.pagopa.rtd.ms.rtdmsfilereporter.domain.model.FileReport;
+import org.mapstruct.Mapper;
+import org.mapstruct.Mapping;
+
+@Mapper(componentModel = "spring")
+public interface FileReportV2DtoMapper {
+
+ @Mapping(source = "filesUploaded", target = "filesRecentlyUploaded")
+ FileReportV2Dto fileReportToDto(FileReport fileReport);
+
+ @Mapping(source = "aggregatesDataSummary", target = "dataSummary")
+ FileMetadataV2Dto fileMetadataToDto(FileMetadata fileMetadata);
+}
diff --git a/src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/domain/FileReportCommandFactory.java b/src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/domain/FileReportCommandFactory.java
index 925a210..f887c3a 100644
--- a/src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/domain/FileReportCommandFactory.java
+++ b/src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/domain/FileReportCommandFactory.java
@@ -2,18 +2,24 @@
import it.gov.pagopa.rtd.ms.rtdmsfilereporter.domain.model.FileMetadata;
import it.gov.pagopa.rtd.ms.rtdmsfilereporter.domain.model.FileReport;
+import it.gov.pagopa.rtd.ms.rtdmsfilereporter.domain.service.DecryptedEventCommand;
import it.gov.pagopa.rtd.ms.rtdmsfilereporter.event.model.EventStatusEnum;
import java.util.function.BiConsumer;
+import lombok.RequiredArgsConstructor;
+@RequiredArgsConstructor
public class FileReportCommandFactory {
+ private final DecryptedEventCommand decryptCommand;
+
public BiConsumer getCommandByStatus(String status) {
return switch (EventStatusEnum.valueOf(status)) {
case ACK_TO_DOWNLOAD ->
(fileReport, fileMetadata) -> fileReport.addAckToDownload(fileMetadata.getName());
case ACK_DOWNLOADED ->
(fileReport, fileMetadata) -> fileReport.removeAckToDownload(fileMetadata.getName());
- default -> FileReport::addFileOrUpdateStatusIfPresent;
+ case DECRYPTED -> decryptCommand;
+ case RECEIVED, SENT_TO_ADE -> FileReport::addFileOrUpdateStatusIfPresent;
};
}
}
diff --git a/src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/domain/model/AggregatesDataSummary.java b/src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/domain/model/AggregatesDataSummary.java
new file mode 100644
index 0000000..555b33f
--- /dev/null
+++ b/src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/domain/model/AggregatesDataSummary.java
@@ -0,0 +1,36 @@
+package it.gov.pagopa.rtd.ms.rtdmsfilereporter.domain.model;
+
+import java.time.LocalDate;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class AggregatesDataSummary {
+
+ private LocalDate minAccountingDate;
+ private LocalDate maxAccountingDate;
+ private int numberOfMerchants;
+ private long countNegativeTransactions;
+ private long countPositiveTransactions;
+ private long sumAmountNegativeTransactions;
+ private long sumAmountPositiveTransactions;
+ // sha256 of the initial input file containing the transactions
+ private String sha256OriginFile;
+
+ public static AggregatesDataSummary createInvalidDataSummary() {
+ return AggregatesDataSummary.builder()
+ .sumAmountPositiveTransactions(-1)
+ .sumAmountNegativeTransactions(-1)
+ .countPositiveTransactions(-1)
+ .countNegativeTransactions(-1)
+ .numberOfMerchants(-1)
+ .minAccountingDate(null)
+ .maxAccountingDate(null)
+ .build();
+ }
+}
diff --git a/src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/domain/model/FileMetadata.java b/src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/domain/model/FileMetadata.java
index b071246..be7cdba 100644
--- a/src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/domain/model/FileMetadata.java
+++ b/src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/domain/model/FileMetadata.java
@@ -1,9 +1,11 @@
package it.gov.pagopa.rtd.ms.rtdmsfilereporter.domain.model;
-import java.time.LocalDateTime;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
+import java.time.LocalDateTime;
+import java.util.Objects;
import lombok.AllArgsConstructor;
+import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
@@ -13,12 +15,16 @@
@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode
+@Builder
public class FileMetadata implements Comparable {
@NotNull
@NotBlank
private String name;
+ @NotNull
+ private String path;
+
private Long size;
@NotNull
@@ -28,12 +34,14 @@ public class FileMetadata implements Comparable {
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
private LocalDateTime transmissionDate;
+ private AggregatesDataSummary aggregatesDataSummary;
+
public static FileMetadata createNewFileMetadata(String name) {
return createNewFileMetadataWithStatus(name, null);
}
public static FileMetadata createNewFileMetadataWithStatus(String name, FileStatusEnum status) {
- return new FileMetadata(name, null, status, LocalDateTime.now());
+ return new FileMetadata(name, null, null, status, LocalDateTime.now(), null);
}
/**
@@ -48,4 +56,14 @@ public int compareTo(@NotNull FileMetadata o) {
return o.getTransmissionDate().isEqual(this.transmissionDate) ? o.getName()
.compareTo(this.name) : o.getTransmissionDate().compareTo(this.transmissionDate);
}
+
+ /**
+ * Enrich the file metadata with the summary of the content.
+ *
+ * @param dataSummary additional information about content of file
+ */
+ public void enrichWithSquaringData(AggregatesDataSummary dataSummary) {
+ dataSummary = Objects.requireNonNullElse(dataSummary, AggregatesDataSummary.builder().build());
+ this.aggregatesDataSummary = dataSummary;
+ }
}
diff --git a/src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/domain/model/FileReport.java b/src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/domain/model/FileReport.java
index 8658797..05cff7a 100644
--- a/src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/domain/model/FileReport.java
+++ b/src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/domain/model/FileReport.java
@@ -2,13 +2,13 @@
import static java.util.Collections.emptyList;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
import java.time.LocalDateTime;
import java.util.Collection;
import java.util.HashSet;
import java.util.Objects;
import java.util.TreeSet;
-import jakarta.validation.constraints.NotBlank;
-import jakarta.validation.constraints.NotNull;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@@ -86,4 +86,11 @@ public static FileReport mergeFileReports(FileReport firstReport, FileReport sec
Objects.requireNonNullElse(secondReport.getAckToDownload(), emptyList()));
return firstReport;
}
+
+ public void addSquaringDataToFile(FileMetadata fileMetadata) {
+ this.filesUploaded.stream()
+ .filter(file -> file.getName().equals(fileMetadata.getName()))
+ .findAny()
+ .ifPresent(file -> file.setAggregatesDataSummary(fileMetadata.getAggregatesDataSummary()));
+ }
}
diff --git a/src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/domain/service/DecryptedEventCommand.java b/src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/domain/service/DecryptedEventCommand.java
new file mode 100644
index 0000000..012b83b
--- /dev/null
+++ b/src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/domain/service/DecryptedEventCommand.java
@@ -0,0 +1,26 @@
+package it.gov.pagopa.rtd.ms.rtdmsfilereporter.domain.service;
+
+import it.gov.pagopa.rtd.ms.rtdmsfilereporter.domain.model.FileMetadata;
+import it.gov.pagopa.rtd.ms.rtdmsfilereporter.domain.model.FileReport;
+import java.util.function.BiConsumer;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Component;
+
+@RequiredArgsConstructor
+@Component
+public class DecryptedEventCommand implements BiConsumer {
+
+ private final StorageAccountService service;
+
+ @Override
+ public void accept(FileReport fileReport, FileMetadata fileMetadata) {
+ // preliminary api call
+ var dataSummary = service.getMetadata(fileMetadata.getPath(), fileMetadata.getName());
+ // actions on domain object
+ fileMetadata.enrichWithSquaringData(dataSummary);
+ // two operations are needed: update status + add aggregates summary
+ fileReport.addFileOrUpdateStatusIfPresent(fileMetadata);
+ fileReport.addSquaringDataToFile(fileMetadata);
+ }
+
+}
diff --git a/src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/domain/service/StorageAccountService.java b/src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/domain/service/StorageAccountService.java
new file mode 100644
index 0000000..3a69940
--- /dev/null
+++ b/src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/domain/service/StorageAccountService.java
@@ -0,0 +1,41 @@
+package it.gov.pagopa.rtd.ms.rtdmsfilereporter.domain.service;
+
+import it.gov.pagopa.rtd.ms.rtdmsfilereporter.domain.model.AggregatesDataSummary;
+import it.gov.pagopa.rtd.ms.rtdmsfilereporter.feign.AggregatesDataSummaryMapper;
+import it.gov.pagopa.rtd.ms.rtdmsfilereporter.feign.StorageAccountRestConnector;
+import java.io.IOException;
+import java.time.format.DateTimeParseException;
+import java.util.Map;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+@RequiredArgsConstructor
+@Service
+@Slf4j
+public class StorageAccountService {
+
+ private final StorageAccountRestConnector connector;
+ private final AggregatesDataSummaryMapper mapper;
+
+ public AggregatesDataSummary getMetadata(String basePath, String fileName) {
+ Map response;
+ try {
+ response = connector.getBlobMetadata(basePath, fileName);
+ } catch (IOException e) {
+ log.warn("Failed to retrieve the file metadata from the storage! Error: {}", e.getMessage());
+ return AggregatesDataSummary.createInvalidDataSummary();
+ }
+
+ // catch any eventual cast exceptions
+ AggregatesDataSummary dataSummary;
+ try {
+ dataSummary = mapper.getDataSummary(response);
+ } catch (DateTimeParseException | NumberFormatException ex) {
+ log.error("Error in parsing some metadata! Error: {}", ex.getMessage());
+ return AggregatesDataSummary.createInvalidDataSummary();
+ }
+
+ return dataSummary;
+ }
+}
diff --git a/src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/event/FileReportEventAdapter.java b/src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/event/FileReportEventAdapter.java
index 94dc161..9d1c97c 100644
--- a/src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/event/FileReportEventAdapter.java
+++ b/src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/event/FileReportEventAdapter.java
@@ -34,7 +34,7 @@ public void consumeEvent(@Valid ProjectorEventDto eventDto) {
if (!validationErrors.isEmpty()) {
throw new ConstraintViolationException(validationErrors);
}
- log.info("Received event for file {} with status {}", eventDto.getFileName(), eventDto.getStatus().name());
+ log.info("Received event for file {} with status {}", eventDto.getFilePath(), eventDto.getStatus().name());
// retrieve the report
var report = service.getFileReport(eventDto.getSender())
diff --git a/src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/event/model/EventToDomainMapper.java b/src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/event/model/EventToDomainMapper.java
index 26942e5..7b69c61 100644
--- a/src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/event/model/EventToDomainMapper.java
+++ b/src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/event/model/EventToDomainMapper.java
@@ -4,12 +4,37 @@
import it.gov.pagopa.rtd.ms.rtdmsfilereporter.domain.model.FileStatusEnum;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
+import org.mapstruct.Named;
@Mapper(componentModel = "spring")
public interface EventToDomainMapper {
- @Mapping(source = "fileName", target = "name")
+
+ /**
+ * Extract the file name from a path. e.g. '/container/filename.txt' returns 'filename.txt'
+ */
+ @Named("filePathToFileName")
+ static String filePathToFileName(String filePath) {
+ return filePath.substring(filePath.lastIndexOf('/') + 1);
+ }
+
+ /**
+ * Map from a path containing the file name to a string containing the path only.
+ * e.g. '/container/filename.txt' returns '/container/'
+ */
+ @Named("filePathToPath")
+ static String filePathToPath(String filePath) {
+ if (filePath.contains("/")) {
+ return filePath.substring(0, filePath.lastIndexOf('/') + 1);
+ } else {
+ return "";
+ }
+ }
+
+ @Mapping(source = "filePath", target = "name", qualifiedByName = "filePathToFileName")
+ @Mapping(source = "filePath", target = "path", qualifiedByName = "filePathToPath")
@Mapping(source = "receiveTimestamp", target = "transmissionDate")
+ @Mapping(target = "aggregatesDataSummary", ignore = true)
FileMetadata eventToDomain(ProjectorEventDto eventDto);
default FileStatusEnum convertFromStringToStatusEnum(EventStatusEnum status) {
diff --git a/src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/event/model/ProjectorEventDto.java b/src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/event/model/ProjectorEventDto.java
index 09438ef..d879304 100644
--- a/src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/event/model/ProjectorEventDto.java
+++ b/src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/event/model/ProjectorEventDto.java
@@ -21,7 +21,7 @@ public class ProjectorEventDto {
@NotNull
@NotBlank
- private String fileName;
+ private String filePath;
@NotNull
@NotBlank
diff --git a/src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/feign/AggregatesDataSummaryMapper.java b/src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/feign/AggregatesDataSummaryMapper.java
new file mode 100644
index 0000000..f274f6b
--- /dev/null
+++ b/src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/feign/AggregatesDataSummaryMapper.java
@@ -0,0 +1,20 @@
+package it.gov.pagopa.rtd.ms.rtdmsfilereporter.feign;
+
+import it.gov.pagopa.rtd.ms.rtdmsfilereporter.domain.model.AggregatesDataSummary;
+import java.util.Map;
+import org.mapstruct.Mapper;
+import org.mapstruct.Mapping;
+
+@Mapper(componentModel = "spring")
+public interface AggregatesDataSummaryMapper {
+
+ @Mapping(source = "numMerchant", target = "numberOfMerchants")
+ @Mapping(source = "numCanceledTrx", target = "countNegativeTransactions")
+ @Mapping(source = "numPositiveTrx", target = "countPositiveTransactions")
+ @Mapping(source = "totalAmountCanceledTrx", target = "sumAmountNegativeTransactions")
+ @Mapping(source = "totalAmountPositiveTrx", target = "sumAmountPositiveTransactions")
+ @Mapping(source = "maxAccountingDate", target = "maxAccountingDate")
+ @Mapping(source = "minAccountingDate", target = "minAccountingDate")
+ @Mapping(source = "checkSum", target = "sha256OriginFile")
+ AggregatesDataSummary getDataSummary(Map data);
+}
diff --git a/src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/feign/StorageAccountRestConnector.java b/src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/feign/StorageAccountRestConnector.java
new file mode 100644
index 0000000..3885e80
--- /dev/null
+++ b/src/main/java/it/gov/pagopa/rtd/ms/rtdmsfilereporter/feign/StorageAccountRestConnector.java
@@ -0,0 +1,82 @@
+package it.gov.pagopa.rtd.ms.rtdmsfilereporter.feign;
+
+import it.gov.pagopa.rtd.ms.rtdmsfilereporter.feign.config.StorageProperties;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.stream.Collectors;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.hc.client5.http.classic.methods.HttpGet;
+import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
+import org.apache.hc.core5.http.Header;
+import org.apache.hc.core5.http.io.HttpClientResponseHandler;
+import org.apache.hc.core5.http.message.BasicHeader;
+import org.jetbrains.annotations.NotNull;
+import org.springframework.stereotype.Component;
+
+@RequiredArgsConstructor
+@Slf4j
+@Component
+public class StorageAccountRestConnector {
+
+ public static final String BLOB_METADATA_PREFIX = "x-ms-meta-";
+ public static final String BLOB_METADATA_QUERY = "?comp=metadata";
+ public static final String SUBSCRIPTION_KEY_HEADER = "Ocp-Apim-Subscription-Key";
+ private final StorageProperties properties;
+ private final CloseableHttpClient httpClient;
+
+ /**
+ * Returns a map with header name and header value as key-value. The headers are filtered by the
+ * expected prefix for metadata.
+ *
+ * @param basePath - path of blob storage starting and ending with '/'
+ * @param fileName - name of blob storage
+ * @return a map with the headers
+ * @throws IOException - thrown by an error occurred in the http client or when the returned
+ * status code does not match 200
+ */
+ public Map getBlobMetadata(String basePath, String fileName) throws IOException {
+
+ if (!basePath.startsWith("/") || !basePath.endsWith("/")) {
+ throw new IllegalArgumentException(
+ "Invalid format for basePath! Make it start and end with '/'");
+ }
+
+ var uri = properties.url()
+ + basePath
+ + fileName
+ + BLOB_METADATA_QUERY;
+
+ final HttpGet httpGet = new HttpGet(uri);
+ httpGet.setHeader(new BasicHeader(SUBSCRIPTION_KEY_HEADER, properties.apiKey()));
+
+ return httpClient.execute(httpGet, validateAndGetMetadata());
+ }
+
+ /**
+ * Returns the metadata as a Map. Contains the logic about where to retrieve the metadata in the
+ * response entity (e.g. in the body, in the headers etc...) and cleanup the data.
+ *
+ * @return a map containing the metadata
+ */
+ protected HttpClientResponseHandler